melonjs 20.1.1 → 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 (165) hide show
  1. package/README.md +88 -10
  2. package/build/application/settings.d.ts +4 -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 +10048 -10341
  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/input/pointerevent.d.ts.map +1 -1
  36. package/build/lang/deprecated.d.ts +4 -2
  37. package/build/lang/deprecated.d.ts.map +1 -1
  38. package/build/level/gltf/GLTFScene.d.ts +12 -0
  39. package/build/level/gltf/GLTFScene.d.ts.map +1 -1
  40. package/build/level/tiled/TMXObjectFactory.d.ts.map +1 -1
  41. package/build/loader/loader.d.ts +4 -40
  42. package/build/loader/loader.d.ts.map +1 -1
  43. package/build/loader/parsers/audio.d.ts +31 -0
  44. package/build/loader/parsers/audio.d.ts.map +1 -0
  45. package/build/loader/parsers/shader.d.ts.map +1 -1
  46. package/build/particles/emitter.d.ts +81 -3
  47. package/build/particles/emitter.d.ts.map +1 -1
  48. package/build/particles/particle.d.ts +62 -1
  49. package/build/particles/particle.d.ts.map +1 -1
  50. package/build/particles/settings.d.ts +50 -7
  51. package/build/particles/settings.d.ts.map +1 -1
  52. package/build/physics/adapter.d.ts +3 -3
  53. package/build/physics/builtin/body.d.ts +23 -24
  54. package/build/physics/builtin/body.d.ts.map +1 -1
  55. package/build/physics/builtin/detector.d.ts +1 -1
  56. package/build/plugin/plugin.d.ts +9 -1
  57. package/build/plugin/plugin.d.ts.map +1 -1
  58. package/build/polyfill/index.d.ts +1 -4
  59. package/build/polyfill/index.d.ts.map +1 -1
  60. package/build/renderable/container.d.ts +10 -0
  61. package/build/renderable/container.d.ts.map +1 -1
  62. package/build/renderable/entity/entity.d.ts +10 -0
  63. package/build/renderable/entity/entity.d.ts.map +1 -1
  64. package/build/renderable/mesh.d.ts +16 -0
  65. package/build/renderable/mesh.d.ts.map +1 -1
  66. package/build/renderable/renderable.d.ts +122 -32
  67. package/build/renderable/renderable.d.ts.map +1 -1
  68. package/build/renderable/sprite.d.ts +7 -7
  69. package/build/renderable/sprite.d.ts.map +1 -1
  70. package/build/state/stage.d.ts +4 -2
  71. package/build/state/stage.d.ts.map +1 -1
  72. package/build/system/event.d.ts +1 -1
  73. package/build/system/platform.d.ts +21 -1
  74. package/build/system/platform.d.ts.map +1 -1
  75. package/build/utils/fetchdata.d.ts.map +1 -0
  76. package/build/video/blendmodes.d.ts +107 -0
  77. package/build/video/blendmodes.d.ts.map +1 -0
  78. package/build/video/canvas/canvas_renderer.d.ts +31 -24
  79. package/build/video/canvas/canvas_renderer.d.ts.map +1 -1
  80. package/build/video/effects/blendEffect.d.ts +57 -0
  81. package/build/video/effects/blendEffect.d.ts.map +1 -0
  82. package/build/video/effects/blur.d.ts +4 -4
  83. package/build/video/effects/blur.d.ts.map +1 -1
  84. package/build/video/effects/chromaticAberration.d.ts +5 -5
  85. package/build/video/effects/chromaticAberration.d.ts.map +1 -1
  86. package/build/video/effects/colorMatrix.d.ts +5 -5
  87. package/build/video/effects/colorMatrix.d.ts.map +1 -1
  88. package/build/video/effects/desaturate.d.ts +5 -5
  89. package/build/video/effects/desaturate.d.ts.map +1 -1
  90. package/build/video/effects/dissolve.d.ts +4 -4
  91. package/build/video/effects/dissolve.d.ts.map +1 -1
  92. package/build/video/effects/dropShadow.d.ts +5 -5
  93. package/build/video/effects/dropShadow.d.ts.map +1 -1
  94. package/build/video/effects/flash.d.ts +4 -4
  95. package/build/video/effects/flash.d.ts.map +1 -1
  96. package/build/video/effects/glow.d.ts +5 -5
  97. package/build/video/effects/glow.d.ts.map +1 -1
  98. package/build/video/effects/hologram.d.ts +4 -4
  99. package/build/video/effects/hologram.d.ts.map +1 -1
  100. package/build/video/effects/invert.d.ts +5 -5
  101. package/build/video/effects/invert.d.ts.map +1 -1
  102. package/build/video/effects/outline.d.ts +6 -6
  103. package/build/video/effects/outline.d.ts.map +1 -1
  104. package/build/video/effects/pixelate.d.ts +4 -4
  105. package/build/video/effects/pixelate.d.ts.map +1 -1
  106. package/build/video/effects/radialGradient.d.ts +2 -2
  107. package/build/video/effects/scanline.d.ts +6 -6
  108. package/build/video/effects/scanline.d.ts.map +1 -1
  109. package/build/video/effects/sepia.d.ts +5 -5
  110. package/build/video/effects/sepia.d.ts.map +1 -1
  111. package/build/video/effects/shadereffect.d.ts +12 -10
  112. package/build/video/effects/shadereffect.d.ts.map +1 -1
  113. package/build/video/effects/shine.d.ts +3 -3
  114. package/build/video/effects/shine.d.ts.map +1 -1
  115. package/build/video/effects/tintPulse.d.ts +4 -4
  116. package/build/video/effects/tintPulse.d.ts.map +1 -1
  117. package/build/video/effects/vignette.d.ts +6 -6
  118. package/build/video/effects/vignette.d.ts.map +1 -1
  119. package/build/video/effects/wave.d.ts +4 -4
  120. package/build/video/effects/wave.d.ts.map +1 -1
  121. package/build/video/renderer.d.ts +3 -4
  122. package/build/video/renderer.d.ts.map +1 -1
  123. package/build/video/rendertarget/canvasrendertarget.d.ts +1 -0
  124. package/build/video/rendertarget/canvasrendertarget.d.ts.map +1 -1
  125. package/build/video/texture/atlas.d.ts +1 -1
  126. package/build/video/webgl/batchers/batcher.d.ts.map +1 -1
  127. package/build/video/webgl/glshader.d.ts +2 -2
  128. package/build/video/webgl/glshader.d.ts.map +1 -1
  129. package/build/video/webgl/utils/program.d.ts.map +1 -1
  130. package/build/video/webgl/webgl_renderer.d.ts +117 -29
  131. package/build/video/webgl/webgl_renderer.d.ts.map +1 -1
  132. package/build/video/webgpu/batchers/quad_batcher.d.ts +7 -0
  133. package/build/video/webgpu/batchers/quad_batcher.d.ts.map +1 -1
  134. package/build/video/webgpu/pipeline/cache.d.ts +0 -9
  135. package/build/video/webgpu/pipeline/cache.d.ts.map +1 -1
  136. package/build/video/webgpu/webgpu_renderer.d.ts +101 -6
  137. package/build/video/webgpu/webgpu_renderer.d.ts.map +1 -1
  138. package/package.json +6 -10
  139. package/skills/AGENTS.md +67 -0
  140. package/skills/melonjs/SKILL.md +156 -0
  141. package/skills/melonjs-20-migration/SKILL.md +160 -0
  142. package/skills/melonjs-3d/SKILL.md +226 -0
  143. package/skills/melonjs-3d-assets/SKILL.md +239 -0
  144. package/skills/melonjs-audio/SKILL.md +215 -0
  145. package/skills/melonjs-camera-and-drawing/SKILL.md +171 -0
  146. package/skills/melonjs-deployment/SKILL.md +113 -0
  147. package/skills/melonjs-effects-and-shaders/SKILL.md +177 -0
  148. package/skills/melonjs-events/SKILL.md +159 -0
  149. package/skills/melonjs-getting-started/SKILL.md +183 -0
  150. package/skills/melonjs-input/SKILL.md +166 -0
  151. package/skills/melonjs-lighting/SKILL.md +139 -0
  152. package/skills/melonjs-loading-assets/SKILL.md +157 -0
  153. package/skills/melonjs-particles-and-trails/SKILL.md +136 -0
  154. package/skills/melonjs-performance/SKILL.md +178 -0
  155. package/skills/melonjs-physics/SKILL.md +321 -0
  156. package/skills/melonjs-plugins/SKILL.md +191 -0
  157. package/skills/melonjs-renderables/SKILL.md +214 -0
  158. package/skills/melonjs-renderer-backends/SKILL.md +173 -0
  159. package/skills/melonjs-scenes-and-state/SKILL.md +180 -0
  160. package/skills/melonjs-sprites-and-animation/SKILL.md +173 -0
  161. package/skills/melonjs-tilemaps/SKILL.md +193 -0
  162. package/skills/melonjs-ui-and-text/SKILL.md +175 -0
  163. package/build/audio/backend.d.ts.map +0 -1
  164. package/build/loader/parsers/fetchdata.d.ts.map +0 -1
  165. /package/build/{loader/parsers → utils}/fetchdata.d.ts +0 -0
@@ -0,0 +1,156 @@
1
+ ---
2
+ name: melonjs
3
+ description: "Use this skill FIRST for any melonJS task; it routes to the right specialised skill and lists the companion packages. melonJS is an open-source 2D, 2.5D and 3D HTML5 game engine running on WebGPU, WebGL 2 or Canvas. Covers Application setup, the scene graph, renderables, sprites, tilemaps, physics, audio, particles, shaders, and the 3D tier — perspective cameras, meshes and glTF scenes. Triggers on: melonjs, melonJS, me.game, Application, app.init, app.world, Renderable, Sprite, Stage, state.change, Camera2d, Camera3d, Mesh, tilemap, Tiled, TMX, ParticleEmitter, ShaderEffect, how do I make a game, HTML5 game engine."
4
+ license: MIT
5
+ ---
6
+
7
+ # melonJS
8
+
9
+ Entry point for the melonJS skill collection. melonJS is an open-source HTML5
10
+ game engine for indie developers, covering 2D, 2.5D and 3D — perspective and
11
+ orthogonal cameras, GPU-accelerated tilemap rendering, post-processing effects,
12
+ custom shaders, 3D meshes, polygon-accurate physics and modern Tiled workflows.
13
+ It runs on WebGPU, WebGL 2 or Canvas with automatic fallback, and has no runtime
14
+ dependencies.
15
+
16
+ ## How to use this skill
17
+
18
+ 1. Find the specialised skill below that matches the task and follow it.
19
+ 2. If the task involves anything 3D, read `melonjs-3d` **first** — melonJS's
20
+ coordinate conventions are the inverse of OpenGL's, so untutored 3D instincts
21
+ are backwards.
22
+ 3. If you are writing melonJS from prior knowledge rather than from the current
23
+ docs, read `melonjs-20-migration` — most published melonJS material predates
24
+ 20.0 and its bootstrap no longer exists.
25
+ 4. If none of them covers the task, use the escape hatch below rather than
26
+ guessing at an API.
27
+
28
+ ## Skill router
29
+
30
+ | Skill | Load when… |
31
+ |---|---|
32
+ | [melonjs-getting-started](../melonjs-getting-started/SKILL.md) | Bootstrapping a game, `new Application`, `await app.init()`, choosing a renderer, preloading assets. |
33
+ | [melonjs-20-migration](../melonjs-20-migration/SKILL.md) | Code based on melonJS 19.x or earlier, or an API that "should exist" but doesn't — `video.init`, `Entity`, `renderable.shader =`. |
34
+ | [melonjs-scenes-and-state](../melonjs-scenes-and-state/SKILL.md) | `Stage` subclasses, the state manager, transitions, pausing, the update loop, timers, tweens, saved data. |
35
+ | [melonjs-renderables](../melonjs-renderables/SKILL.md) | Subclassing `Renderable`, custom `draw()`, draw order, anchors, `floating`, post effects on an object. |
36
+ | [melonjs-sprites-and-animation](../melonjs-sprites-and-animation/SKILL.md) | `Sprite`, frame animation, texture atlases (TexturePacker / Aseprite / ShoeBox), tint, flip, pooling. |
37
+ | [melonjs-input](../melonjs-input/SKILL.md) | Keyboard actions, pointer and touch handling, drag, gamepad, virtual controls. |
38
+ | [melonjs-physics](../melonjs-physics/SKILL.md) | Collision, bodies, movement, spatial queries, and the planck / matter adapters. |
39
+ | [melonjs-tilemaps](../melonjs-tilemaps/SKILL.md) | Tiled maps — TMX/TSX loading, spawning entities from objects, collision layers, isometric maps. |
40
+ | [melonjs-audio](../melonjs-audio/SKILL.md) | Sound effects, music, audio sprites, spatial audio, procedural tone and noise. |
41
+ | [melonjs-effects-and-shaders](../melonjs-effects-and-shaders/SKILL.md) | Post effects, custom GLSL/WGSL shaders, blend modes, colour grading, screen capture. |
42
+ | [melonjs-3d](../melonjs-3d/SKILL.md) | Anything 3D or 2.5D — `Camera3d`, meshes, instancing, `Sprite3d` billboards, `Light3d`, glTF scenes. |
43
+ | [melonjs-3d-assets](../melonjs-3d-assets/SKILL.md) | Loading glTF/GLB or OBJ models — materials, imported lights, instancing, and what is not supported. |
44
+ | [melonjs-camera-and-drawing](../melonjs-camera-and-drawing/SKILL.md) | Camera follow, bounds, shake and fade, coordinate conversion, and immediate-mode shape drawing. |
45
+ | [melonjs-ui-and-text](../melonjs-ui-and-text/SKILL.md) | HUDs, buttons, menus, drag-and-drop, `Text` and `BitmapText`, web fonts, panels. |
46
+ | [melonjs-particles-and-trails](../melonjs-particles-and-trails/SKILL.md) | `ParticleEmitter`, burst versus stream, `referenceSpace`, and the `Trail` renderable. |
47
+ | [melonjs-lighting](../melonjs-lighting/SKILL.md) | 2D dynamic lighting — `Light2d`, stage ambient, normal-mapped sprites. |
48
+ | [melonjs-deployment](../melonjs-deployment/SKILL.md) | Scaffolding a project, building, browser support and transpiling, native and mini-game platforms. |
49
+ | [melonjs-loading-assets](../melonjs-loading-assets/SKILL.md) | Resource descriptors, the asset type list, base URLs, cross-origin, progress events, unloading. |
50
+ | [melonjs-renderer-backends](../melonjs-renderer-backends/SKILL.md) | A feature works on one machine but not another; choosing or pinning a backend; degrading gracefully. |
51
+ | [melonjs-events](../melonjs-events/SKILL.md) | The event bus, per-frame and lifecycle events, and subscribing without leaking. |
52
+ | [melonjs-performance](../melonjs-performance/SKILL.md) | Dropped frames, draw-call counts, pooling, batching, culling, baking, profiling. |
53
+ | [melonjs-plugins](../melonjs-plugins/SKILL.md) | Registering the debug, Spine or Tiled-inflate plugins, physics adapters, or writing your own plugin. |
54
+
55
+
56
+ ## Escape hatch: the full API index
57
+
58
+ These skills are hand-written and deliberately partial — they cover the paths
59
+ people actually take and the mistakes those paths invite. When the task needs
60
+ something they do not mention, do **not** infer an API from the shape of the
61
+ engine. Fetch the generated index instead:
62
+
63
+ <https://melonjs.github.io/melonJS/llms.txt>
64
+
65
+ It is regenerated on every docs build from the same TSDoc comments the reference
66
+ pages render, so it is always current for `master`. It lists every exported
67
+ class, function, interface, type and namespace with a one-line summary and a
68
+ link to its page — fetch the pages you need from there.
69
+
70
+ Two things it gives you that this collection cannot:
71
+
72
+ - **Members.** The skills name classes; `llms.txt` links to the page listing
73
+ every method, property, default and `@since` tag on them.
74
+ - **Deprecations.** Entries marked `**deprecated**` are exactly the APIs that a
75
+ model trained on older melonJS material will reach for. If something you were
76
+ about to write appears with that marker, follow the page for the replacement.
77
+
78
+ If a class, function, namespace or type is absent from `llms.txt`, it is absent
79
+ from the engine's public API — that is the useful negative answer, and it is
80
+ worth acting on rather than writing code around something that does not exist.
81
+ The index lists top-level exports only, so a *member* missing from it proves
82
+ nothing: follow the owning class's page to check that.
83
+
84
+ ## The three rules that catch everyone
85
+
86
+ Whatever the task, these produce code that runs and is wrong:
87
+
88
+ 1. **`await app.init()` is mandatory** since 20.0. The constructor builds the
89
+ world but not the renderer: a plain renderable can still be added and simply
90
+ never draws, while `new Sprite(...)` / `new Text(...)` throw a `TypeError`
91
+ on the global `game`, which is unset until the first `init()` resolves.
92
+ Neither symptom names the missing call.
93
+ 2. **`addChild(child, z)` is the only way to set draw order.** `renderable.z`
94
+ does not exist; setting `depth` before `addChild` is overwritten, and setting
95
+ it after does not resort (except under `Camera3d`).
96
+ 3. **`isKinematic` defaults to `true`**, which silently excludes a renderable
97
+ from pointer events and from the physics broadphase. Plain `Renderable` and
98
+ `Sprite` subclasses need `this.isKinematic = false`.
99
+
100
+ ## Companion packages
101
+
102
+ melonJS ships optional packages alongside the engine. Reach for these rather
103
+ than reimplementing what they cover — and note the physics adapters and the
104
+ Tiled inflate plugin are *required* for their use cases, not merely convenient.
105
+
106
+ | Package | Use when |
107
+ |---|---|
108
+ | [`@melonjs/planck-adapter`](https://www.npmjs.com/package/@melonjs/planck-adapter) | You want full rigid-body dynamics — stacking, joints, realistic restitution. Pass it as the Application's `physic` setting; the portable `raycast` and `queryAABB` calls work unchanged across adapters (`querySphere` and `raycast3d` are built-in-adapter only). |
109
+ | [`@melonjs/matter-adapter`](https://www.npmjs.com/package/@melonjs/matter-adapter) | Same, backed by matter-js. Choose one adapter per game. |
110
+ | [`@melonjs/tiled-inflate-plugin`](https://www.npmjs.com/package/@melonjs/tiled-inflate-plugin) | **Required** to load gzip-, zlib- or zstd-compressed Tiled maps. Without it, parsing such a map throws `No inflate function set`. |
111
+ | [`@melonjs/spine-plugin`](https://www.npmjs.com/package/@melonjs/spine-plugin) | Skeletal animation authored in Spine, as a melonJS renderable. |
112
+ | [`@melonjs/debug-plugin`](https://www.npmjs.com/package/@melonjs/debug-plugin) | An in-game debug panel — FPS, draw counts, collision-shape and bounds overlays. Register it after `app.init()`. |
113
+ | [`@melonjs/capacitor-plugin`](https://www.npmjs.com/package/@melonjs/capacitor-plugin) | Wrapping a game as a native iOS/Android app: it bridges Capacitor's lifecycle — pause/resume, the hardware back button, orientation lock, splash screen. |
114
+ | [`create-melonjs`](https://www.npmjs.com/package/create-melonjs) | Scaffolding a new project — start here rather than assembling a build by hand. |
115
+
116
+ Plugins are registered **after** `init()`, into a global registry:
117
+
118
+ ```js
119
+ import { plugin } from "melonjs";
120
+ import { DebugPanelPlugin } from "@melonjs/debug-plugin";
121
+
122
+ await app.init();
123
+ plugin.register(DebugPanelPlugin, "debugPanel");
124
+ ```
125
+
126
+ Physics adapters are different — they are an `Application` setting, not a
127
+ plugin:
128
+
129
+ ```js
130
+ import { PlanckAdapter } from "@melonjs/planck-adapter";
131
+
132
+ const app = new Application(800, 600, {
133
+ parent: "screen",
134
+ // gravity is in pixels/s²; pixelsPerMeter converts it to the adapter's
135
+ // metres. Both are shown at their defaults; subSteps defaults to 1
136
+ physic: new PlanckAdapter({
137
+ gravity: { x: 0, y: 320 },
138
+ pixelsPerMeter: 32,
139
+ subSteps: 2,
140
+ }),
141
+ });
142
+ await app.init();
143
+ ```
144
+
145
+ `melonjs-plugins` covers the registry, the version gate and writing your own.
146
+
147
+ ## Prefer built-in features
148
+
149
+ melonJS covers a lot that is easy to reimplement badly. Before hand-rolling,
150
+ check for: `ParticleEmitter` and `Trail`, `Tween` with easing, the built-in
151
+ `ShaderEffect` presets (vignette, scanline, chromatic aberration, glow, dissolve
152
+ and more), `Light2d` / `Light3d`, `UIBaseElement` / `UISpriteElement` /
153
+ `UITextButton`, `NineSliceSprite`, `TextureAtlas` (TexturePacker, ShoeBox,
154
+ Aseprite), `BitmapText`, `CanvasRenderTarget` for bake-once drawing,
155
+ `NoiseTexture2d`, `viewport.shake` / `fadeIn` / `fadeOut`, and `save` for
156
+ localStorage-backed persistence.
@@ -0,0 +1,160 @@
1
+ ---
2
+ name: melonjs-20-migration
3
+ description: "Use this skill when writing melonJS code that may be based on pre-20.x knowledge, when migrating a game from melonJS 19.x or earlier, or when an API you expected does not exist. Covers the mandatory async Application.init(), the WebGL 2 baseline and WebGPU backend, renderable post effects replacing the shader property, and the deprecated exports still present. Triggers on: migration, upgrade, melonJS 19, me.game, me.video.init, renderable.shader, Compositor, CanvasTexture, me.Math, deprecated."
4
+ license: MIT
5
+ ---
6
+
7
+ # Migrating to melonJS 20.x
8
+
9
+ > What changed in melonJS 20.x, and which older APIs are gone, deprecated, or
10
+ > renamed. Read this before writing melonJS code from memory — much of what is
11
+ > published about melonJS predates 20.0.
12
+
13
+ **Why this skill exists:** most melonJS material in circulation describes 19.x or
14
+ earlier. Code written from that knowledge looks correct and fails at runtime.
15
+ The items below are ordered by how likely they are to be reproduced from memory.
16
+
17
+ ## 1. `Application.init()` is mandatory and asynchronous
18
+
19
+ Since 20.0, constructing an `Application` no longer initialises it.
20
+
21
+ ```js
22
+ // ✗ pre-20.x — the constructor called init(width, height, options) for you
23
+ const app = new Application(800, 600, { parent: "screen" });
24
+ app.world.addChild(sprite); // added, but nothing ever renders
25
+
26
+ // ✓ 20.x
27
+ const app = new Application(800, 600, { parent: "screen" });
28
+ await app.init(); // REQUIRED
29
+ app.world.addChild(sprite);
30
+ ```
31
+
32
+ `init()` is async because acquiring a WebGPU device is async. There is no
33
+ synchronous alternative, and no automatic fallback that papers over the missing
34
+ call. Nothing that then breaks names it: the constructor still builds
35
+ `app.world`, so children can be added and simply never draw — no canvas is
36
+ appended, the app never subscribes to the frame tick, and `app.renderer` /
37
+ `app.viewport` stay `undefined` — while constructing a `Sprite` or `Text` first
38
+ throws a `TypeError` on the unset global `game` instead.
39
+
40
+ The signature changed too: 19.x took `init(width, height, options)`, 20.x takes
41
+ none, and anything passed is ignored (settings come from the constructor).
42
+
43
+ **`video.init(...)` no longer exists.** The `video` module now exports only the
44
+ four renderer constants (`AUTO`, `CANVAS`, `WEBGL`, `WEBGPU`) — there is no
45
+ `init` on it to call. Any code shaped like `me.video.init(800, 600, {...})` is
46
+ from a removed API. Build an `Application` and await `init()`.
47
+
48
+ Note that `import * as me from "melonjs"` still works, so `me.Sprite` style is
49
+ fine. It is the *globals bootstrap* that is gone, not the namespace import.
50
+
51
+ ## 2. Post effects replaced the `shader` property
52
+
53
+ `renderable.shader = …` is **deprecated since 19.2.0**. Use the post-effect API:
54
+
55
+ ```js
56
+ // ✗ deprecated
57
+ mySprite.shader = new ShaderEffect(app.renderer, glslBody);
58
+
59
+ // ✓
60
+ mySprite.addPostEffect(new ShaderEffect(app.renderer, glslBody));
61
+ ```
62
+
63
+ Related trap: **`removePostEffect()` destroys the effect** — and so does
64
+ assigning `renderable.shader`, which destroys whatever it replaces. Only an
65
+ effect carrying `shared = true` is spared. To turn one off temporarily, toggle
66
+ `effect.enabled` instead: remove-and-re-add hands you back an object whose GPU
67
+ resources have already been freed.
68
+
69
+ ## 3. WebGL 2 is the baseline; WebGPU is the default attempt
70
+
71
+ `video.AUTO` now tries **WebGPU → WebGL 2 → Canvas**. WebGL 1 is gone.
72
+
73
+ Consequences:
74
+
75
+ - Which backend runs is a runtime fact. Do not write code that assumes WebGL.
76
+ - Custom shaders can carry both GLSL and WGSL in one asset, so one effect runs
77
+ on either GPU backend.
78
+ - Features needing a programmable pipeline are inert on Canvas and warn once
79
+ rather than throwing.
80
+
81
+ ## 4. Deprecated exports still present
82
+
83
+ These resolve but should not be used in new code:
84
+
85
+ | deprecated | since | use instead |
86
+ |---|---|---|
87
+ | `CanvasTexture` | 17.1.0 | `CanvasRenderTarget` |
88
+ | `Compositor` | 18.1.0 | `WebGLBatcher` |
89
+ | `PrimitiveCompositor` | 18.1.0 | `PrimitiveBatcher` |
90
+ | `QuadCompositor` | 18.1.0 | `QuadBatcher` |
91
+ | `Math` (capitalised) | 18.0.0 | `math` (lowercase) |
92
+ | `device.requestFullscreen` / `exitFullscreen` | 19.7.0 | `app.requestFullscreen()` / `app.exitFullscreen()` |
93
+ | `renderable.shader = …` | 19.2.0 | `addPostEffect()` |
94
+ | `Entity` | 18.1.0 | `Sprite` / `Renderable` + a `Body` |
95
+ | `loader.onload` / `onProgress` / `onError` | 18.2.0, **removed 20.3** | the `LOADER_*` events, or `preload(assets, onloadcb)` |
96
+ | `response.overlap` / `overlapN` / `overlapV` | — | `response.depth` / `response.normal` |
97
+ | `setLineWidth()` | 17.3.0 | the `lineWidth` property |
98
+
99
+ Two of these deserve emphasis:
100
+
101
+ - **`Entity`** is still exported, so code using it compiles and runs while being
102
+ the wrong shape for 20.x. Compose a `Sprite`/`Renderable` with a `Body`
103
+ instead.
104
+ - **The capitalised `Math`** shadows the global `Math` if imported carelessly.
105
+ `me.Math.random()` from older docs resolves to the deprecated re-export.
106
+
107
+ ## 5. The global `game` is not the modern shape
108
+
109
+ `game` is still exported, but since 20.0 it names the most recently
110
+ **initialized** `Application` and is `undefined` until the first `init()`
111
+ resolves — so anything reading it at module scope gets `undefined`. Take the
112
+ `Application` instance as a parameter instead: `Stage#onResetEvent` and
113
+ `onDestroyEvent` are handed it, and any renderable can reach it through
114
+ `parentApp`.
115
+
116
+ ## 6. Node and SSR
117
+
118
+ melonJS imports cleanly under Node — useful for isomorphic apps and for tooling.
119
+ It has **no runtime dependencies** as of 20.3. Do not add polyfills for
120
+ `globalThis`, `String.trimStart` or `String.trimEnd`: the published bundle
121
+ targets ES2022, so every environment that can parse it already has them.
122
+
123
+ ## 7. Browser support
124
+
125
+ The published bundle targets **ES2022** and uses private class members. A browser
126
+ that predates that cannot parse the file at all — it fails at load, not when a
127
+ feature is used. Transpile if you need older browsers, and note that transpiling
128
+ handles *syntax* only: built-in methods need separate polyfills, which a
129
+ bundler's `target` setting will never add.
130
+
131
+ ## The shipped examples are not all current
132
+
133
+ The examples in this repository are the best reference for how melonJS is
134
+ assembled, but a few contain stale comments or legacy calls. Do not learn these
135
+ from them:
136
+
137
+ - `webgpu/` has a comment claiming *"`video.AUTO` never selects the WebGPU
138
+ backend"*. That is pre-20 leftover — AUTO tries WebGPU **first**. The code is
139
+ right; the comment is wrong.
140
+ - Several examples assign `viewport.shader = …` / `sprite.shader = …`, which is
141
+ deprecated. `addPostEffect()` is current.
142
+ - Five files set `this.z = Number.POSITIVE_INFINITY` on a HUD. That property
143
+ does not exist; those HUDs draw on top only because they are added last.
144
+ - `platformer/entities/player.ts` reads `response.overlapV`, the deprecated
145
+ field. Use `response.depth` / `response.normal`.
146
+ - Particle speeds tuned before 20.2 look wrong now: the particle transform fix
147
+ changed how far a burst travels, and emitters were retuned upward to match.
148
+
149
+ ## Checklist when code "should work" but doesn't
150
+
151
+ 1. Is `await app.init()` there?
152
+ 2. Is the code assuming WebGL when it might be running on Canvas or WebGPU?
153
+ 3. Is it using `renderable.shader =` instead of `addPostEffect()`?
154
+ 4. Is it importing a deprecated symbol from the table above?
155
+ 5. Is it referencing a global `game`?
156
+
157
+ ## Related skills
158
+
159
+ - `melonjs-getting-started` — the correct 20.x bootstrap in full
160
+ - `melonjs-renderables` — post effects, pointer events and custom draw code
@@ -0,0 +1,226 @@
1
+ ---
2
+ name: melonjs-3d
3
+ description: "Use this skill for anything 3D or 2.5D in melonJS — Camera3d, Mesh, InstancedMesh, Sprite3d billboards, Light3d, ground shadows, glTF/GLB scenes, and depth sorting. Covers the Y-down/+Z-forward convention that is the inverse of OpenGL, the cameraClass opt-in, clip planes, and what does not work on the Canvas fallback. Triggers on: Camera3d, Mesh, InstancedMesh, Sprite3d, Light3d, billboard, glTF, glb, 3D, 2.5D, depth, cameraClass, fov, setClipPlanes, castGroundShadow, lit."
4
+ license: MIT
5
+ ---
6
+
7
+ # 3D and 2.5D in melonJS
8
+
9
+ > melonJS is a 2D engine that grew a real 3D tier: perspective cameras, meshes,
10
+ > instancing, glTF scenes and 3D lights. Most of what a model "knows" about 3D
11
+ > graphics comes from the OpenGL convention, and **melonJS's is the inverse**.
12
+ > Read the conventions section before writing any 3D code.
13
+
14
+ ## Coordinate conventions — the inverse of OpenGL
15
+
16
+ This is the single most important thing on this page.
17
+
18
+ | | melonJS | OpenGL convention |
19
+ |---|---|---|
20
+ | vertical | **Y-down** — higher `y` is *lower* on screen | Y-up |
21
+ | depth | **+Z forward** — higher `z` is *farther* away | −Z forward |
22
+
23
+ Rotations are extrinsic XYZ. `Camera3d` exposes two of the three: `camera.pitch`
24
+ (X, look up/down) and `camera.yaw` (Y, look left/right). **There is no `roll`**;
25
+ neither camera applies a Z-axis bank to the view, so assigning one does nothing.
26
+
27
+ The payoff is that 2D code translates directly — anywhere you used `pos.x` /
28
+ `pos.y`, add `pos.z` and the maths still holds. The cost is that every
29
+ OpenGL-shaped instinct is backwards.
30
+
31
+ **Consequence that bites immediately:** "behind everything" is the *largest*
32
+ depth when the camera looks along +Z. Put a backdrop on the wrong side and it
33
+ either paints over the whole scene (it is nearer than everything else) or
34
+ disappears without trace (it falls in front of the near plane and the GPU clips
35
+ it). Which sign means "far" depends on which side the camera sits, so check the
36
+ camera before picking a backdrop depth.
37
+
38
+ glTF assets are authored Y-up right-handed. `level.load` converts them by
39
+ rotation (`rightHanded: true` is its default), so you do not apply a flip
40
+ yourself. The **`Mesh` constructor defaults `rightHanded` to `false`**, which
41
+ bridges by mirroring instead — geometry you hand to a `Mesh` directly comes in
42
+ flipped left/right unless you pass `rightHanded: true`. See
43
+ `melonjs-3d-assets`.
44
+
45
+ ## Opting in
46
+
47
+ 3D starts with the camera class, and nothing else has to change. Set it once on
48
+ the `Application`:
49
+
50
+ ```js
51
+ import { Application, Camera3d } from "melonjs";
52
+
53
+ const app = new Application(1024, 768, {
54
+ parent: "screen",
55
+ cameraClass: Camera3d, // ← the opt-in
56
+ });
57
+ await app.init();
58
+ ```
59
+
60
+ That flips the world's sort to `"depth"`, switches the broadphase to a 3D index,
61
+ and renders sprites and meshes with perspective projection. `Camera3d` extends
62
+ `Camera2d`, so follow, fade, shake and post effects all still work.
63
+
64
+ Per-stage opt-in also works, which is useful when the loading screen is 2D:
65
+
66
+ ```js
67
+ class GameStage extends Stage {
68
+ constructor() {
69
+ super({ cameras: [new Camera3d(0, 0, 1024, 768, { fov: Math.PI / 3 })] });
70
+ }
71
+ }
72
+ ```
73
+
74
+ ## Camera traps
75
+
76
+ - **There is no sky.** The frame clears to `renderer.backgroundColor` (opaque
77
+ black unless the renderer was created transparent), and `world.backgroundColor`
78
+ clears over it when you set one — both are flat colours. Anything more is a
79
+ backdrop renderable, screen-fixed or placed at a far depth.
80
+ - **Set the clip planes for your scene scale.** Defaults are near 0.1 / far 1000.
81
+ Objects beyond the far plane clip or project with bad w-divides; a `near` that
82
+ is too small wastes depth precision and distant props z-fight. Use
83
+ `camera.setClipPlanes(near, far)`.
84
+ - **`camera.pos.set(x, y)` is 2-argument and zeroes z.** Use `camera.depth` —
85
+ the documented z accessor — or assign `pos.x`/`pos.y` individually.
86
+
87
+ ## Depth sorting
88
+
89
+ Under `Camera3d` the world sorts on `"depth"` **every frame** (recursively), so
90
+ unlike 2D you *can* assign `depth` after `addChild` and it will reorder. That is
91
+ the one place where the usual z-ordering rule is relaxed — see
92
+ `melonjs-renderables` for the 2D rules, which still apply everywhere else.
93
+
94
+ You will often *have* to. A `Container` has `autoDepth: true` by default, so
95
+ `addChild(child)` with no explicit z **overwrites `pos.z` with the child's
96
+ index** — a real world depth in a 3D scene, and never the one you wanted. Pass
97
+ it (`world.addChild(mesh, z)`), or set `mesh.depth` afterwards. The glTF
98
+ importer turns `autoDepth` off on the container it loads into for this reason.
99
+
100
+ ## Meshes
101
+
102
+ ```js
103
+ const cube = new Mesh(x, y, {
104
+ model: "cube", // a preloaded OBJ name — no built-in primitives
105
+ texture: atlas, // TextureAtlas, image, or a preloaded image name
106
+ width: 64, height: 64,
107
+ cullBackFaces: true, // the default
108
+ lit: true,
109
+ });
110
+ ```
111
+
112
+ **A mesh pivots about its model origin `(0, 0, 0)`, not an anchor point.** Under
113
+ `Camera3d` it opts out of the anchor offset entirely, so `anchorPoint` is inert
114
+ there — place the origin where you want the pivot at authoring time, or nest the
115
+ mesh under a transformed parent. The anchor is only honoured on the legacy
116
+ 2D-camera path.
117
+
118
+ **`InstancedMesh`** draws one mesh many times in a single draw call — the
119
+ difference between a hundred trees and a hundred thousand. glTF scenes using
120
+ `EXT_mesh_gpu_instancing` load as an `InstancedMesh` automatically.
121
+
122
+ ## Sprite3d and billboards
123
+
124
+ `Sprite3d` is the 2.5D workhorse: a flat sprite living at a real depth, with
125
+ `billboard` controlling how it faces the camera.
126
+
127
+ | `billboard` | behaviour |
128
+ |---|---|
129
+ | `false` (default) / `"none"` | no rotation — a flat plane in the world |
130
+ | `true` / `"cylindrical"` | yaws to face the camera, stays upright (characters, trees) |
131
+ | `"spherical"` | always fully faces the camera (particles, impostors) |
132
+
133
+ `"cylindrical"` is what you want for paper-thin characters in a 2.5D game.
134
+ Billboarding needs a `Camera3d` drawing the frame; under a 2D camera the quad
135
+ renders fixed-orientation. **Any other string falls through to the spherical
136
+ branch**, so a guessed value like `"upright"` silently gives you spherical.
137
+
138
+ ## Lighting
139
+
140
+ `Light3d` takes **one argument — the options object** (it has no `x, y, z`
141
+ pair; a light carries its own `position`). Types are `"directional"` (the
142
+ default), `"ambient"`, `"point"` and `"spot"`.
143
+
144
+ ```js
145
+ world.addChild(new Light3d({ type: "directional", direction: [0.3, 1, 0.2] }));
146
+ world.addChild(new Light3d({ type: "ambient", intensity: 0.3 }));
147
+ ```
148
+
149
+ Use **both halves**: with a key light but no ambient, the shadow side of a mesh
150
+ goes black. With no `Light3d` in the world at all, a `lit: true` mesh falls back
151
+ to a white ambient and renders fullbright — indistinguishable from unlit, which
152
+ is why "I added `lit: true` and nothing changed" is the usual first report.
153
+
154
+ Other defaults worth knowing: `intensity` 1, `color` white, `range` 1000 (point
155
+ and spot, a stylised quadratic falloff, not inverse-square),
156
+ `innerConeAngle` 0 and `outerConeAngle` π/4 (spot).
157
+
158
+ **`Light2d` is 2D-only** and produces visible artifacts under perspective
159
+ projection. Do not combine it with `Camera3d`.
160
+
161
+ Ground shadows are **on by default** (the `castGroundShadow` application
162
+ setting), and need a GPU backend and a `Camera3d`. As a blanket default they
163
+ skip geometry with no vertical extent — a ground plane. Per object,
164
+ `castGroundShadow: true`/`false` overrides the app setting and is obeyed as
165
+ given, safeguard included; `shadowGroundY` names the floor the blob lands on.
166
+
167
+ ## glTF / GLB scenes
168
+
169
+ Loaded through the same level director as everything else:
170
+
171
+ ```js
172
+ await loader.preload([{ name: "diorama", type: "glb", src: "data/diorama.glb" }]);
173
+ level.load("diorama", { scale, castGroundShadow, shadowGroundY, onLoaded });
174
+ ```
175
+
176
+ `.obj` / `.mtl` are also supported loader types.
177
+
178
+ `melonjs-3d-assets` covers the rest: every `level.load` option, which material
179
+ features are imported, imported lights and their intensity units, node-TRS
180
+ animation (and the skinning that is out of scope), and OBJ/MTL.
181
+
182
+ ## Requires a GPU backend
183
+
184
+ The whole 3D tier needs WebGPU or WebGL 2. The Canvas renderer has no depth
185
+ buffer, no perspective path and no `drawMesh`, so a `Camera3d` scene does not
186
+ render correctly there — usually a black canvas. `Light3d` and shader effects
187
+ are inert too. A `Mesh` under a *2D* camera still renders, CPU-projected by
188
+ painter's algorithm and unlit.
189
+
190
+ `Application` does warn: constructing with a `cameraClass` whose
191
+ `defaultSortOn` is `"depth"` on a renderer with no depth buffer logs a
192
+ `console.warn`. But `video.AUTO` falls back silently to Canvas, so the strong
193
+ gate is to ask for a GPU backend by name — `renderer: video.WEBGL` (or
194
+ `video.WEBGPU`) makes `await app.init()` reject instead of misrendering:
195
+
196
+ ```js
197
+ const app = new Application(1024, 768, {
198
+ parent: "screen",
199
+ renderer: video.WEBGL, // init() rejects if WebGL 2 is unavailable
200
+ cameraClass: Camera3d,
201
+ });
202
+ await app.init();
203
+ ```
204
+
205
+ To branch rather than fail, read `app.renderer.supportsDepthBuffer` after
206
+ `init()`.
207
+
208
+ ## Symptom → cause
209
+
210
+ | symptom | cause |
211
+ |---|---|
212
+ | nothing renders, or a backdrop covers everything | wrong depth sign — "far" is *larger* z when looking along +Z |
213
+ | distant objects vanish or warp | scene exceeds the default far plane; `setClipPlanes` |
214
+ | distant surfaces z-fight | `near` too small for the scene scale |
215
+ | black canvas under `Camera3d` | Canvas renderer (no depth buffer) — check the `console.warn` |
216
+ | everything flat and unlit | `lit: true` with no `Light3d` in the world (falls back to fullbright), or a mesh under a 2D camera |
217
+ | a mesh sits at the wrong depth after being added | `autoDepth` overwrote `pos.z` with the child index — pass `addChild(mesh, z)` |
218
+ | a mesh sits half its size off | `anchorPoint` — only on the 2D-camera path; a `Camera3d` mesh pivots on its model origin |
219
+ | a billboard tips over when the camera looks down | `"spherical"`, or a mistyped mode string falling through to it — use `true` / `"cylindrical"` |
220
+ | an object jumps to the camera plane | `Vector3d.set(x, y)` / `camera.pos.set(x, y)` zeroed its z |
221
+ | lighting looks wrong under a 3D camera | `Light2d` used instead of `Light3d` |
222
+
223
+ ## Related skills
224
+
225
+ - `melonjs-renderables` — the 2D z-ordering rules, anchors, custom draw
226
+ - `melonjs-getting-started` — Application settings and the renderer fallback