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.
- package/README.md +66 -22
- package/build/application/application.d.ts +6 -1
- package/build/application/application.d.ts.map +1 -1
- package/build/application/header.d.ts.map +1 -1
- package/build/application/resize.d.ts.map +1 -1
- package/build/application/settings.d.ts +13 -8
- package/build/application/settings.d.ts.map +1 -1
- package/build/audio/audio.d.ts +8 -4
- package/build/audio/audio.d.ts.map +1 -1
- package/build/audio/backend/engine.d.ts.map +1 -1
- package/build/audio/playback.d.ts +2 -2
- package/build/audio/playback.d.ts.map +1 -1
- package/build/audio/spatial.d.ts.map +1 -1
- package/build/audio/types.d.ts +15 -5
- package/build/audio/types.d.ts.map +1 -1
- package/build/camera/camera2d.d.ts +12 -9
- package/build/camera/camera2d.d.ts.map +1 -1
- package/build/camera/camera3d.d.ts +11 -8
- package/build/camera/camera3d.d.ts.map +1 -1
- package/build/camera/effects/fade_effect.d.ts.map +1 -1
- package/build/geometries/ellipse.d.ts +3 -0
- package/build/geometries/ellipse.d.ts.map +1 -1
- package/build/geometries/line.d.ts.map +1 -1
- package/build/geometries/path2d.d.ts +9 -8
- package/build/geometries/path2d.d.ts.map +1 -1
- package/build/geometries/polygon.d.ts +2 -1
- package/build/geometries/polygon.d.ts.map +1 -1
- package/build/index.d.ts +14 -3
- package/build/index.d.ts.map +1 -1
- package/build/index.js +50215 -45051
- package/build/index.js.map +4 -4
- package/build/input/gamepad.d.ts.map +1 -1
- package/build/input/keyboard.d.ts.map +1 -1
- package/build/input/pointerevent.d.ts.map +1 -1
- package/build/level/gltf/GLTFModel.d.ts.map +1 -1
- package/build/level/level.d.ts.map +1 -1
- package/build/level/tiled/TMXLayer.d.ts +50 -15
- package/build/level/tiled/TMXLayer.d.ts.map +1 -1
- package/build/level/tiled/TMXTileMap.d.ts +14 -4
- package/build/level/tiled/TMXTileMap.d.ts.map +1 -1
- package/build/level/tiled/TMXTileset.d.ts.map +1 -1
- package/build/level/tiled/TMXUtils.d.ts.map +1 -1
- package/build/level/tiled/renderer/TMXHexagonalRenderer.d.ts.map +1 -1
- package/build/level/tiled/renderer/TMXIsometricRenderer.d.ts.map +1 -1
- package/build/level/tiled/renderer/TMXObliqueRenderer.d.ts +1 -0
- package/build/level/tiled/renderer/TMXObliqueRenderer.d.ts.map +1 -1
- package/build/level/tiled/renderer/TMXOrthogonalRenderer.d.ts.map +1 -1
- package/build/level/tiled/renderer/TMXRenderer.d.ts +7 -3
- package/build/level/tiled/renderer/TMXRenderer.d.ts.map +1 -1
- package/build/level/tiled/renderer/TMXStaggeredRenderer.d.ts.map +1 -1
- package/build/lighting/light3d.d.ts +55 -0
- package/build/lighting/light3d.d.ts.map +1 -1
- package/build/loader/cache.d.ts +146 -97
- package/build/loader/cache.d.ts.map +1 -1
- package/build/loader/internal-types.d.ts +69 -0
- package/build/loader/internal-types.d.ts.map +1 -0
- package/build/loader/loader.d.ts +589 -253
- package/build/loader/loader.d.ts.map +1 -1
- package/build/loader/parsers/audio.d.ts.map +1 -1
- package/build/loader/parsers/fontface.d.ts.map +1 -1
- package/build/loader/parsers/gltf.d.ts.map +1 -1
- package/build/loader/parsers/tmx.d.ts.map +1 -1
- package/build/math/color.d.ts +4 -0
- package/build/math/color.d.ts.map +1 -1
- package/build/math/math.d.ts +6 -1
- package/build/math/math.d.ts.map +1 -1
- package/build/math/noise.d.ts +16 -16
- package/build/math/noise.d.ts.map +1 -1
- package/build/math/observableVector2d.d.ts +6 -6
- package/build/math/observableVector2d.d.ts.map +1 -1
- package/build/math/observableVector3d.d.ts +8 -8
- package/build/math/observableVector3d.d.ts.map +1 -1
- package/build/particles/emitter.d.ts +15 -3
- package/build/particles/emitter.d.ts.map +1 -1
- package/build/particles/particle.d.ts +6 -0
- package/build/particles/particle.d.ts.map +1 -1
- package/build/particles/settings.d.ts +22 -5
- package/build/particles/settings.d.ts.map +1 -1
- package/build/physics/adapter.d.ts +64 -25
- package/build/physics/adapter.d.ts.map +1 -1
- package/build/physics/builtin/body.d.ts +23 -4
- package/build/physics/builtin/body.d.ts.map +1 -1
- package/build/physics/builtin/builtin-adapter.d.ts +25 -3
- package/build/physics/builtin/builtin-adapter.d.ts.map +1 -1
- package/build/physics/builtin/detector.d.ts.map +1 -1
- package/build/physics/builtin/raycast.d.ts.map +1 -1
- package/build/physics/world.d.ts +40 -10
- package/build/physics/world.d.ts.map +1 -1
- package/build/renderable/container.d.ts +41 -6
- package/build/renderable/container.d.ts.map +1 -1
- package/build/renderable/draggable.d.ts.map +1 -1
- package/build/renderable/frameAnimation.d.ts.map +1 -1
- package/build/renderable/instanced_mesh.d.ts +16 -14
- package/build/renderable/instanced_mesh.d.ts.map +1 -1
- package/build/renderable/mesh.d.ts +62 -5
- package/build/renderable/mesh.d.ts.map +1 -1
- package/build/renderable/renderable.d.ts.map +1 -1
- package/build/renderable/sprite.d.ts +4 -2
- package/build/renderable/sprite.d.ts.map +1 -1
- package/build/renderable/text/bitmaptext.d.ts +12 -3
- package/build/renderable/text/bitmaptext.d.ts.map +1 -1
- package/build/renderable/text/text.d.ts +147 -4
- package/build/renderable/text/text.d.ts.map +1 -1
- package/build/renderable/text/textmetrics.d.ts +10 -2
- package/build/renderable/text/textmetrics.d.ts.map +1 -1
- package/build/renderable/text/textstyle.d.ts.map +1 -1
- package/build/renderable/trigger.d.ts +5 -0
- package/build/renderable/trigger.d.ts.map +1 -1
- package/build/renderable/ui/panelpaint.d.ts +5 -1
- package/build/renderable/ui/panelpaint.d.ts.map +1 -1
- package/build/renderable/ui/progressbar.d.ts +267 -95
- package/build/renderable/ui/progressbar.d.ts.map +1 -1
- package/build/renderable/ui/uibaseelement.d.ts +443 -50
- package/build/renderable/ui/uibaseelement.d.ts.map +1 -1
- package/build/renderable/ui/uicheckbox.d.ts +383 -0
- package/build/renderable/ui/uicheckbox.d.ts.map +1 -0
- package/build/renderable/ui/uifocus.d.ts +6 -0
- package/build/renderable/ui/uifocus.d.ts.map +1 -0
- package/build/renderable/ui/uilabel.d.ts +31 -0
- package/build/renderable/ui/uilabel.d.ts.map +1 -0
- package/build/renderable/ui/uipanel.d.ts +589 -116
- package/build/renderable/ui/uipanel.d.ts.map +1 -1
- package/build/renderable/ui/uiskin.d.ts +25 -0
- package/build/renderable/ui/uiskin.d.ts.map +1 -0
- package/build/renderable/ui/uislider.d.ts +518 -0
- package/build/renderable/ui/uislider.d.ts.map +1 -0
- package/build/renderable/ui/uispriteelement.d.ts +161 -85
- package/build/renderable/ui/uispriteelement.d.ts.map +1 -1
- package/build/renderable/ui/uitextbutton.d.ts +369 -63
- package/build/renderable/ui/uitextbutton.d.ts.map +1 -1
- package/build/state/stage.d.ts.map +1 -1
- package/build/system/device.d.ts +11 -2
- package/build/system/device.d.ts.map +1 -1
- package/build/system/fullscreen.d.ts.map +1 -1
- package/build/system/pool.d.ts.map +1 -1
- package/build/system/save.d.ts +2 -1
- package/build/system/save.d.ts.map +1 -1
- package/build/tweens/tween.d.ts +5 -2
- package/build/tweens/tween.d.ts.map +1 -1
- package/build/utils/fetchdata.d.ts.map +1 -1
- package/build/utils/utils.d.ts.map +1 -1
- package/build/video/canvas/canvas_renderer.d.ts +16 -19
- package/build/video/canvas/canvas_renderer.d.ts.map +1 -1
- package/build/video/canvas_factory.d.ts.map +1 -1
- package/build/video/effects/shadereffect.d.ts +127 -0
- package/build/video/effects/shadereffect.d.ts.map +1 -1
- package/build/video/renderer.d.ts +20 -4
- package/build/video/renderer.d.ts.map +1 -1
- package/build/video/renderstate.d.ts +26 -3
- package/build/video/renderstate.d.ts.map +1 -1
- package/build/video/utils/tessellation.d.ts +11 -0
- package/build/video/utils/tessellation.d.ts.map +1 -1
- package/build/video/webgl/batchers/lit_mesh_batcher.d.ts.map +1 -1
- package/build/video/webgl/webgl_renderer.d.ts +3 -6
- package/build/video/webgl/webgl_renderer.d.ts.map +1 -1
- package/build/video/webgpu/batchers/lit_mesh_batcher.d.ts.map +1 -1
- package/build/video/webgpu/batchers/primitive_batcher.d.ts.map +1 -1
- package/build/video/webgpu/webgpu_renderer.d.ts +3 -6
- package/build/video/webgpu/webgpu_renderer.d.ts.map +1 -1
- package/package.json +1 -1
- package/skills/melonjs/SKILL.md +41 -17
- package/skills/melonjs-20-migration/SKILL.md +50 -7
- package/skills/melonjs-3d/SKILL.md +138 -38
- package/skills/melonjs-3d-assets/SKILL.md +83 -33
- package/skills/melonjs-audio/SKILL.md +62 -19
- package/skills/melonjs-camera-and-drawing/SKILL.md +135 -8
- package/skills/melonjs-deployment/SKILL.md +92 -14
- package/skills/melonjs-display-and-scaling/SKILL.md +8 -3
- package/skills/melonjs-effects-and-shaders/SKILL.md +47 -15
- package/skills/melonjs-events/SKILL.md +6 -3
- package/skills/melonjs-getting-started/SKILL.md +6 -2
- package/skills/melonjs-input/SKILL.md +102 -16
- package/skills/melonjs-lighting/SKILL.md +13 -1
- package/skills/melonjs-loading-assets/SKILL.md +255 -39
- package/skills/melonjs-math/SKILL.md +26 -8
- package/skills/melonjs-particles-and-trails/SKILL.md +77 -9
- package/skills/melonjs-performance/SKILL.md +18 -8
- package/skills/melonjs-physics/SKILL.md +435 -128
- package/skills/melonjs-plugins/SKILL.md +50 -11
- package/skills/melonjs-renderables/SKILL.md +31 -7
- package/skills/melonjs-renderer-backends/SKILL.md +38 -17
- package/skills/melonjs-scenes-and-state/SKILL.md +45 -5
- package/skills/melonjs-sprites-and-animation/SKILL.md +37 -2
- package/skills/melonjs-tilemaps/SKILL.md +149 -17
- package/skills/melonjs-ui-and-text/SKILL.md +674 -42
package/skills/melonjs/SKILL.md
CHANGED
|
@@ -34,25 +34,25 @@ dependencies.
|
|
|
34
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
35
|
| [melonjs-renderables](../melonjs-renderables/SKILL.md) | Subclassing `Renderable`, custom `draw()`, draw order, anchors, `floating`, post effects on an object. |
|
|
36
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. |
|
|
37
|
+
| [melonjs-input](../melonjs-input/SKILL.md) | Keyboard actions, pointer and touch handling, drag, gamepad, virtual controls (fixed or floating sticks and buttons, tap to act). |
|
|
38
|
+
| [melonjs-physics](../melonjs-physics/SKILL.md) | Collision, bodies, movement, spatial queries, and the planck / matter / Rapier adapters. |
|
|
39
39
|
| [melonjs-math](../melonjs-math/SKILL.md) | Vectors and matrices: what mutates, what allocates, and interpolating with lerp, slerp, damp or moveTowards. |
|
|
40
|
-
| [melonjs-tilemaps](../melonjs-tilemaps/SKILL.md) | Tiled maps — TMX/TSX loading, spawning entities from objects, collision layers, isometric maps. |
|
|
40
|
+
| [melonjs-tilemaps](../melonjs-tilemaps/SKILL.md) | Tiled maps — TMX/TSX loading, spawning entities from objects, collision layers, isometric maps, reading and changing tiles at run time (a tile layer as the game board). |
|
|
41
41
|
| [melonjs-audio](../melonjs-audio/SKILL.md) | Sound effects, music, audio sprites, spatial audio, procedural tone and noise. |
|
|
42
42
|
| [melonjs-effects-and-shaders](../melonjs-effects-and-shaders/SKILL.md) | Post effects, custom GLSL/WGSL shaders, blend modes, colour grading, screen capture. |
|
|
43
43
|
| [melonjs-3d](../melonjs-3d/SKILL.md) | Anything 3D or 2.5D — `Camera3d`, meshes, instancing, `Sprite3d` billboards, `Light3d`, distance fog, glTF scenes. |
|
|
44
44
|
| [melonjs-3d-assets](../melonjs-3d-assets/SKILL.md) | Loading glTF/GLB or OBJ models — materials, imported lights, instancing, and what is not supported. |
|
|
45
45
|
| [melonjs-camera-and-drawing](../melonjs-camera-and-drawing/SKILL.md) | Camera follow, bounds, shake and fade, coordinate conversion, and immediate-mode shape drawing. |
|
|
46
|
-
| [melonjs-ui-and-text](../melonjs-ui-and-text/SKILL.md) | HUDs, buttons,
|
|
46
|
+
| [melonjs-ui-and-text](../melonjs-ui-and-text/SKILL.md) | HUDs, menus and options screens — buttons, checkboxes, sliders, progress bars, laid-out and scrolling panels — drag-and-drop, `Text` and `BitmapText`, web fonts. |
|
|
47
47
|
| [melonjs-particles-and-trails](../melonjs-particles-and-trails/SKILL.md) | `ParticleEmitter`, burst versus stream, `referenceSpace`, and the `Trail` renderable. |
|
|
48
48
|
| [melonjs-lighting](../melonjs-lighting/SKILL.md) | 2D dynamic lighting — `Light2d`, stage ambient, normal-mapped sprites. |
|
|
49
|
-
| [melonjs-deployment](../melonjs-deployment/SKILL.md) | Scaffolding a project, building, browser support and transpiling, native and mini-game platforms. |
|
|
50
|
-
| [melonjs-loading-assets](../melonjs-loading-assets/SKILL.md) | Resource descriptors, the asset type list, base URLs, cross-origin, progress events
|
|
49
|
+
| [melonjs-deployment](../melonjs-deployment/SKILL.md) | Scaffolding a project, building, browser support and transpiling, native and mini-game platforms, running with no DOM (nx.js on the Nintendo Switch, Web Workers). |
|
|
50
|
+
| [melonjs-loading-assets](../melonjs-loading-assets/SKILL.md) | Resource descriptors, the asset type list, a multi-level game's assets as bundles (`common` + one per level), loading and freeing a level's assets, base URLs, cross-origin, progress events. |
|
|
51
51
|
| [melonjs-renderer-backends](../melonjs-renderer-backends/SKILL.md) | A feature works on one machine but not another; choosing or pinning a backend; degrading gracefully. |
|
|
52
52
|
| [melonjs-display-and-scaling](../melonjs-display-and-scaling/SKILL.md) | Blurry, soft or cropped output; the design resolution, how the canvas fills its page, and pixel-perfect integer scaling. |
|
|
53
53
|
| [melonjs-events](../melonjs-events/SKILL.md) | The event bus, per-frame and lifecycle events, and subscribing without leaking. |
|
|
54
54
|
| [melonjs-performance](../melonjs-performance/SKILL.md) | Dropped frames, draw-call counts, pooling, batching, culling, baking, profiling. |
|
|
55
|
-
| [melonjs-plugins](../melonjs-plugins/SKILL.md) | Registering the debug, Spine
|
|
55
|
+
| [melonjs-plugins](../melonjs-plugins/SKILL.md) | Registering the debug, Spine, Tiled-inflate, gamepad (touch controls) or Capacitor plugins, installing a physics adapter, or writing your own plugin. |
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
## Escape hatch: the full API index
|
|
@@ -97,7 +97,9 @@ Whatever the task, these produce code that runs and is wrong:
|
|
|
97
97
|
it after does not resort (except under `Camera3d`).
|
|
98
98
|
3. **`isKinematic` defaults to `true`**, which silently excludes a renderable
|
|
99
99
|
from pointer events and from the physics broadphase. Plain `Renderable` and
|
|
100
|
-
`Sprite` subclasses need `this.isKinematic = false
|
|
100
|
+
`Sprite` subclasses with no body need `this.isKinematic = false`; adding a
|
|
101
|
+
body sets it for you, on every adapter (matter-adapter before 1.6 and
|
|
102
|
+
planck-adapter before 1.7 did not).
|
|
101
103
|
|
|
102
104
|
## Companion packages
|
|
103
105
|
|
|
@@ -109,10 +111,11 @@ Tiled inflate plugin are *required* for their use cases, not merely convenient.
|
|
|
109
111
|
|---|---|
|
|
110
112
|
| [`@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). |
|
|
111
113
|
| [`@melonjs/matter-adapter`](https://www.npmjs.com/package/@melonjs/matter-adapter) | Same, backed by matter-js. Choose one adapter per game. |
|
|
114
|
+
| [`@melonjs/rapier2d-adapter`](https://www.npmjs.com/package/@melonjs/rapier2d-adapter) | Same again, backed by Rapier compiled to WebAssembly: many bodies, per-body continuous collision, a character controller. About 3 MB loaded on demand, so make it with `await RapierAdapter.create()`. |
|
|
112
115
|
| [`@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`. |
|
|
113
116
|
| [`@melonjs/spine-plugin`](https://www.npmjs.com/package/@melonjs/spine-plugin) | Skeletal animation authored in Spine, as a melonJS renderable. |
|
|
114
117
|
| [`@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()`. |
|
|
115
|
-
| [`@melonjs/gamepad-plugin`](https://www.npmjs.com/package/@melonjs/gamepad-plugin) | On-screen touch controls for phones and tablets: sticks and buttons reported as a gamepad, so the game's `bindGamepad` bindings drive it. Use it rather than writing virtual controls. |
|
|
118
|
+
| [`@melonjs/gamepad-plugin`](https://www.npmjs.com/package/@melonjs/gamepad-plugin) | On-screen touch controls for phones and tablets: sticks and buttons reported as a gamepad, so the game's `bindGamepad` bindings drive it; fixed or floating under the thumb, hidden until touched, tap to act. Use it rather than writing virtual controls. |
|
|
116
119
|
| [`@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. |
|
|
117
120
|
| [`create-melonjs`](https://www.npmjs.com/package/create-melonjs) | Scaffolding a new project — start here rather than assembling a build by hand. |
|
|
118
121
|
|
|
@@ -136,7 +139,7 @@ const app = new Application(800, 600, {
|
|
|
136
139
|
parent: "screen",
|
|
137
140
|
// gravity is in pixels/s²; pixelsPerMeter converts it to the adapter's
|
|
138
141
|
// metres. Both are shown at their defaults; subSteps defaults to 1
|
|
139
|
-
physic:
|
|
142
|
+
physic: await PlanckAdapter.create({
|
|
140
143
|
gravity: { x: 0, y: 320 },
|
|
141
144
|
pixelsPerMeter: 32,
|
|
142
145
|
subSteps: 2,
|
|
@@ -145,15 +148,36 @@ const app = new Application(800, 600, {
|
|
|
145
148
|
await app.init();
|
|
146
149
|
```
|
|
147
150
|
|
|
151
|
+
Every adapter is made the same way, with `await X.create(options)`. A running
|
|
152
|
+
game switches adapter with `app.world.setAdapter(await X.create(options))`,
|
|
153
|
+
which rebuilds every body from its `bodyDef`; `world.adapter` itself is
|
|
154
|
+
read-only. `melonjs-physics` says which adapter suits which game.
|
|
155
|
+
|
|
148
156
|
`melonjs-plugins` covers the registry, the version gate and writing your own.
|
|
149
157
|
|
|
150
158
|
## Prefer built-in features
|
|
151
159
|
|
|
152
160
|
melonJS covers a lot that is easy to reimplement badly. Before hand-rolling,
|
|
153
|
-
check for:
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
`
|
|
159
|
-
|
|
161
|
+
check for:
|
|
162
|
+
|
|
163
|
+
- **Effects and motion:** `ParticleEmitter`, `Trail` / `Trail3d`, `Tween` with
|
|
164
|
+
easing, the built-in `ShaderEffect` presets (vignette, scanline, chromatic
|
|
165
|
+
aberration, glow, outline, dissolve, bloom and more), `Light2d` / `Light3d`,
|
|
166
|
+
`viewport.shake` / `fadeIn` / `fadeOut`.
|
|
167
|
+
- **UI:** `UIPanel` (laid out, scrolling, skinnable), `UITextButton`,
|
|
168
|
+
`UICheckbox` (a radio button with a `group`), `UISlider`, `ProgressBar`,
|
|
169
|
+
`UISpriteElement`, keyboard and gamepad navigation between widgets once one
|
|
170
|
+
has `focus()`, `NineSliceSprite`, `Draggable` / `DropTarget`, `BitmapText`.
|
|
171
|
+
- **Art:** `TextureAtlas` (TexturePacker, ShoeBox, Aseprite),
|
|
172
|
+
`CanvasRenderTarget` for bake-once drawing, `NoiseTexture2d`.
|
|
173
|
+
- **Game flow:** `state.transition()` (`"fade"`, `"mask"` or `"pixelate"`)
|
|
174
|
+
between screens, `state.pause()` / `state.resume()` behind a pause menu,
|
|
175
|
+
`save` for localStorage-backed persistence, `createPool` / `getPool` for
|
|
176
|
+
recycling.
|
|
177
|
+
- **Levels:** Tiled tile layers read and changed with `cellAt` / `setTile`,
|
|
178
|
+
and asset bundles (`loader.preload({ common: [...], level1: [...] })`, then
|
|
179
|
+
`loader.unload("level1")` / `loader.load("level1")`) to free and reload a
|
|
180
|
+
level's assets.
|
|
181
|
+
- **Physics and controls:** a rigid-body adapter (planck, matter or Rapier,
|
|
182
|
+
switched at run time with `world.setAdapter()`) rather than a hand-written
|
|
183
|
+
solver, and `@melonjs/gamepad-plugin` rather than hand-made touch sticks.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
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,
|
|
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, the deprecated exports still present, and what changed again during 20.x. Triggers on: migration, upgrade, melonJS 19, me.game, me.video.init, video.renderer, renderable.shader, Compositor, CanvasTexture, me.Math, pool.pull, pool.register, world.adapter, uvOffset, deprecated."
|
|
4
4
|
license: MIT
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -43,7 +43,13 @@ none, and anything passed is ignored (settings come from the constructor).
|
|
|
43
43
|
**`video.init(...)` no longer exists.** The `video` module now exports only the
|
|
44
44
|
four renderer constants (`AUTO`, `CANVAS`, `WEBGL`, `WEBGPU`) — there is no
|
|
45
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()`.
|
|
46
|
+
from a removed API. Build an `Application` and await `init()`. Its siblings
|
|
47
|
+
went with it: `video.renderer`, `video.createCanvas()` and `video.getParent()`
|
|
48
|
+
are now `app.renderer`, `app.renderer.createCanvas()` and
|
|
49
|
+
`app.getParentElement()`.
|
|
50
|
+
|
|
51
|
+
`init()` runs once: a second call is ignored with a console warning, and after
|
|
52
|
+
`app.destroy()` it throws. A destroyed `Application` is final; build a new one.
|
|
47
53
|
|
|
48
54
|
Note that `import * as me from "melonjs"` still works, so `me.Sprite` style is
|
|
49
55
|
fine. It is the *globals bootstrap* that is gone, not the namespace import.
|
|
@@ -77,6 +83,16 @@ Consequences:
|
|
|
77
83
|
on either GPU backend.
|
|
78
84
|
- Features needing a programmable pipeline are inert on Canvas and warn once
|
|
79
85
|
rather than throwing.
|
|
86
|
+
- Test capabilities, not the backend: `renderer.shaderLanguage` and
|
|
87
|
+
`renderer.supportsDepthBuffer` replace checks on `renderer.gl` or
|
|
88
|
+
`instanceof WebGLRenderer`, which answer "no" on WebGPU.
|
|
89
|
+
`renderer.WebGLVersion` is always `2` (deprecated), and the `preferWebGL1`
|
|
90
|
+
setting and the `#webgl1` URL flag are gone.
|
|
91
|
+
- A custom WebGL batcher extends `WebGLBatcher` (`Batcher` is now the
|
|
92
|
+
backend-neutral base), and a custom shader on a `Mesh` receives model-space
|
|
93
|
+
geometry: position with
|
|
94
|
+
`uProjectionMatrix * uViewMatrix * uModelMatrix * vec4(aVertex, 1.0)` and
|
|
95
|
+
tint with `uTint`. Sprite and post-effect shaders are unchanged.
|
|
80
96
|
|
|
81
97
|
## 4. Deprecated exports still present
|
|
82
98
|
|
|
@@ -93,8 +109,14 @@ These resolve but should not be used in new code:
|
|
|
93
109
|
| `renderable.shader = …` | 19.2.0 | `addPostEffect()` |
|
|
94
110
|
| `Entity` | 18.1.0 | `Sprite` / `Renderable` + a `Body` |
|
|
95
111
|
| `loader.onload` / `onProgress` / `onError` | 18.2.0, **removed 20.3** | the `LOADER_*` events, or `preload(assets, onloadcb)` |
|
|
96
|
-
| `response.overlap` / `overlapN` / `overlapV` |
|
|
112
|
+
| `response.overlap` / `overlapN` / `overlapV` | 19.5.0 | `response.depth` / `response.normal` |
|
|
97
113
|
| `setLineWidth()` | 17.3.0 | the `lineWidth` property |
|
|
114
|
+
| `pool.register` / `pool.pull` / `pool.push` | 18.0.0 (a console notice since 20.9) | `createPool()` / `getPool()`; `registerTiledObjectClass()` for a class a Tiled map names |
|
|
115
|
+
| `body.fromJSON()`, a shape list given to `addShape()` | 20.7.0 (the `Body` constructor form throws) | `bodyDef = { type, shapes: "<json asset>", id }` |
|
|
116
|
+
| `body.ignoreGravity` | 19.5.0 | `gravityScale = 0`, or `body.setGravityScale(0)` |
|
|
117
|
+
| `app.updateAverageDelta` | 20.0.0 | `app.lastUpdateDelta` |
|
|
118
|
+
| `loader.crossOrigin = …` / `loader.withCredentials = …` | 20.4.0 (assigning throws) | `loader.setOptions({ crossOrigin, withCredentials })` |
|
|
119
|
+
| `UITextButton#bitmapText` | 20.13.0 | `label` |
|
|
98
120
|
|
|
99
121
|
Two of these deserve emphasis:
|
|
100
122
|
|
|
@@ -128,6 +150,25 @@ feature is used. Transpile if you need older browsers, and note that transpiling
|
|
|
128
150
|
handles *syntax* only: built-in methods need separate polyfills, which a
|
|
129
151
|
bundler's `target` setting will never add.
|
|
130
152
|
|
|
153
|
+
## 8. Changed again during 20.x
|
|
154
|
+
|
|
155
|
+
Code written against an early 20.x release can still trip on these:
|
|
156
|
+
|
|
157
|
+
- **`world.adapter` is read-only** (20.14): assigning it throws a
|
|
158
|
+
`TypeError`. `app.world.setAdapter(adapter)` switches adapters, rebuilding
|
|
159
|
+
every body from its `bodyDef`.
|
|
160
|
+
- **`renderer.uvOffset` and the `textureSeamFix` setting are removed** (20.11).
|
|
161
|
+
Code that added `uvOffset` to a size should drop it.
|
|
162
|
+
- **The engine's classes are no longer in the legacy pool** (20.9):
|
|
163
|
+
`pool.pull("Sprite")`, `pool.pull("Text")` and the other built-in names
|
|
164
|
+
throw `Cannot instantiate object of type`. Call the constructor, or
|
|
165
|
+
`getPool("text")`, `getPool("tween")`, `getPool("particle")`,
|
|
166
|
+
`getPool("colorLayer")` to recycle. `pool.register(name, Class, true)` no
|
|
167
|
+
longer returns an instance to the pool on removal either; `createPool` does.
|
|
168
|
+
- **A container sorted on `"x"` or `"y"` re-sorts its children as they move**
|
|
169
|
+
(20.11, `autoSort` on by default). Turn `autoSort` off to keep an order set
|
|
170
|
+
by hand. A `"z"` sort is unchanged.
|
|
171
|
+
|
|
131
172
|
## The shipped examples are not all current
|
|
132
173
|
|
|
133
174
|
The examples in this repository are the best reference for how melonJS is
|
|
@@ -139,10 +180,11 @@ from them:
|
|
|
139
180
|
right; the comment is wrong.
|
|
140
181
|
- Several examples assign `viewport.shader = …` / `sprite.shader = …`, which is
|
|
141
182
|
deprecated. `addPostEffect()` is current.
|
|
142
|
-
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
183
|
+
- Three files (in `platformer-matter/` and `pool-matter/`) set
|
|
184
|
+
`this.z = Number.POSITIVE_INFINITY` on a HUD or a virtual joypad. That
|
|
185
|
+
property does not exist; they draw on top only because they are added last.
|
|
186
|
+
- `platformer/entities/player.ts` and `enemies.ts` read `response.overlapV`,
|
|
187
|
+
the deprecated field. Use `response.depth` / `response.normal`.
|
|
146
188
|
- Particle speeds tuned before 20.2 look wrong now: the particle transform fix
|
|
147
189
|
changed how far a burst travels, and emitters were retuned upward to match.
|
|
148
190
|
|
|
@@ -153,6 +195,7 @@ from them:
|
|
|
153
195
|
3. Is it using `renderable.shader =` instead of `addPostEffect()`?
|
|
154
196
|
4. Is it importing a deprecated symbol from the table above?
|
|
155
197
|
5. Is it referencing a global `game`?
|
|
198
|
+
6. Is it relying on something section 8 lists as changed during 20.x?
|
|
156
199
|
|
|
157
200
|
## Related skills
|
|
158
201
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
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, Trail3d, ribbon, exhaust trail, Light3d, billboard, glTF, glb, 3D, 2.5D, depth, cameraClass, fov, setClipPlanes, setFog, fog, distance fog, height fog, heightFalloff, transparent, transparency, alpha, blendMode, fade, castGroundShadow, lit, setBasis, getBasis, lookAt, up vector, gimbal, slerp, great circle, turn a direction."
|
|
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, Trail3d, ribbon, exhaust trail, Light3d, billboard, glTF, glb, 3D, 2.5D, depth, cameraClass, fov, setClipPlanes, setFog, fog, distance fog, height fog, heightFalloff, transparent, transparency, alpha, blendMode, fade, castGroundShadow, shadowGroundPoint, lit, emissive, specular, shininess, normalMap, alphaCutoff, depthTest, vertexColors, worldToScreen, followOffset, setBasis, getBasis, lookAt, up vector, gimbal, slerp, great circle, turn a direction."
|
|
4
4
|
license: MIT
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -69,7 +69,8 @@ await app.init();
|
|
|
69
69
|
|
|
70
70
|
That flips the world's sort to `"depth"`, switches the broadphase to a 3D index,
|
|
71
71
|
and renders sprites and meshes with perspective projection. `Camera3d` extends
|
|
72
|
-
`Camera2d`, so follow, fade, shake and post effects all still work
|
|
72
|
+
`Camera2d`, so follow, fade, shake and post effects all still work (follow with
|
|
73
|
+
a difference, see the camera traps).
|
|
73
74
|
|
|
74
75
|
### Keep the camera, do not fish it back out
|
|
75
76
|
|
|
@@ -193,8 +194,15 @@ class GameStage extends Stage {
|
|
|
193
194
|
sense to `lookAt`'s, and one negation apart.
|
|
194
195
|
- **`worldToLocal` does not project.** It is a 2D camera's offset subtraction.
|
|
195
196
|
To pin a label or marker to a point in the scene use
|
|
196
|
-
`camera.worldToScreen(
|
|
197
|
+
`camera.worldToScreen(point, out?)`: it takes a `Vector3d`, applies the
|
|
198
|
+
projection and returns a `Vector2d` in the camera's pixels (y down), or
|
|
197
199
|
`null` behind the camera. See `melonjs-camera-and-drawing`.
|
|
200
|
+
- **`follow()` tracks exactly.** Under a `Camera3d` the camera sits at the
|
|
201
|
+
target's position plus `followOffset` (world space, set with
|
|
202
|
+
`camera.setFollowOffset(x, y, z)`) every frame. The 2D follow's axis,
|
|
203
|
+
deadzone and damping are not applied. For a damped chase camera, leave the
|
|
204
|
+
target unset and move the camera yourself (`math.damp`, or `slerp` below for
|
|
205
|
+
its facing).
|
|
198
206
|
|
|
199
207
|
## Where an up vector earns its keep
|
|
200
208
|
|
|
@@ -299,6 +307,11 @@ index** — a real world depth in a 3D scene, and never the one you wanted. Pass
|
|
|
299
307
|
it (`world.addChild(mesh, z)`), or set `mesh.depth` afterwards. The glTF
|
|
300
308
|
importer turns `autoDepth` off on the container it loads into for this reason.
|
|
301
309
|
|
|
310
|
+
A `Container`'s depth carries to its children when they are drawn, as it
|
|
311
|
+
already did for culling and the sort: a group at depth 400 draws its sprites
|
|
312
|
+
and meshes 400 units further away. One more reason to give containers an
|
|
313
|
+
explicit z.
|
|
314
|
+
|
|
302
315
|
**`floating` does not opt out of this sort.** It skips the camera *transform*,
|
|
303
316
|
not the depth *order*. A floating child is ordered by `|pos.z|` alone — its
|
|
304
317
|
`pos.x/y` are screen pixels, and the camera does not move relative to it — so
|
|
@@ -327,8 +340,9 @@ Meshes render in two phases. The **opaque pass** writes depth in sort order; the
|
|
|
327
340
|
depth. A draw lands in the second whenever its alpha is fractional.
|
|
328
341
|
|
|
329
342
|
That default matters because the opaque path writes premultiplied colour with
|
|
330
|
-
blending off, so
|
|
331
|
-
rather than see-through — the background
|
|
343
|
+
blending off, so a faded mesh that stays there (as every one did before 20.4)
|
|
344
|
+
comes out **darkened toward black** rather than see-through — the background
|
|
345
|
+
contributes nothing.
|
|
332
346
|
|
|
333
347
|
**`transparent: true`** when the transparency is in the TEXTURE rather than the
|
|
334
348
|
opacity — a soft-edged glow, smoke, a glTF material with `alphaMode: "BLEND"`.
|
|
@@ -376,8 +390,9 @@ const halo = new Sprite3d(0, 0, {
|
|
|
376
390
|
});
|
|
377
391
|
```
|
|
378
392
|
|
|
379
|
-
Honoured in the transparent pass on both GPU backends
|
|
380
|
-
|
|
393
|
+
Honoured in the **transparent pass only**, on both GPU backends: a mesh drawn
|
|
394
|
+
in the opaque pass ignores it, so pair it with `transparent: true` as above.
|
|
395
|
+
The Canvas renderer has no depth buffer and ignores it.
|
|
381
396
|
|
|
382
397
|
Blending uses the renderable's existing `blendMode`, so a glow is one property.
|
|
383
398
|
The advanced modes (`"overlay"`, `"difference"`, and the rest that need a
|
|
@@ -482,6 +497,8 @@ the built-in ones:
|
|
|
482
497
|
uniform vec3 uFogColor; // straight (unpremultiplied) fog colour
|
|
483
498
|
uniform vec4 uFogParams; // x = mode (0 off / 1 linear / 2 exp2),
|
|
484
499
|
// y = near, z = 1/(far - near), w = density
|
|
500
|
+
uniform vec4 uFogHeight; // height falloff: xyz = falloff x world-up axis,
|
|
501
|
+
// in VIEW space; w = pre-baked altitude term
|
|
485
502
|
```
|
|
486
503
|
|
|
487
504
|
Your vertex stage computes the distance itself — `length((uViewMatrix *
|
|
@@ -490,6 +507,12 @@ camera turns — and the blend must scale the fog colour by the fragment's own
|
|
|
490
507
|
alpha, `mix(uFogColor * a, rgb, f)`, because `vColor` arrives premultiplied.
|
|
491
508
|
Mixing toward the unscaled colour haloes every alpha-cutout edge.
|
|
492
509
|
|
|
510
|
+
`uFogHeight` is only needed to honour `heightFalloff`, and is fed only to a
|
|
511
|
+
program that also declares `uFogParams`. The engine's own shaders multiply the
|
|
512
|
+
distance by `uFogHeight.w * (exp(k) - 1.0) / k`, with `k = dot(uFogHeight.xyz,
|
|
513
|
+
viewPos)` and the factor taken as `uFogHeight.w` when `k` is near zero. Leave it
|
|
514
|
+
out and your mesh fogs uniformly at every altitude.
|
|
515
|
+
|
|
493
516
|
The flip side is the reason fog costs nothing when unused: with no camera fog,
|
|
494
517
|
the mesh programs are compiled without any of it, on both backends. It is not a
|
|
495
518
|
branch that is skipped at runtime — the code is not there.
|
|
@@ -510,7 +533,32 @@ const cube = new Mesh(x, y, {
|
|
|
510
533
|
`Camera3d` it opts out of the anchor offset entirely, so `anchorPoint` is inert
|
|
511
534
|
there — place the origin where you want the pivot at authoring time, or nest the
|
|
512
535
|
mesh under a transformed parent. The anchor is only honoured on the legacy
|
|
513
|
-
2D-camera path.
|
|
536
|
+
2D-camera path. `Sprite3d` is the exception: it bakes its `anchorPoint` into
|
|
537
|
+
the quad's vertices, so a `"bottom"` anchor works under either camera.
|
|
538
|
+
|
|
539
|
+
### Material settings
|
|
540
|
+
|
|
541
|
+
What a material file can state is also a setting, so a hand-built mesh gets the
|
|
542
|
+
same surface. All but `baseColorFactor` are GPU-only; the Canvas renderer
|
|
543
|
+
ignores them.
|
|
544
|
+
|
|
545
|
+
| setting | what it does | needs |
|
|
546
|
+
|---|---|---|
|
|
547
|
+
| `emissive: [r, g, b]` | self-illumination added on top, 0..1 (above 1 for an HDR glow) | nothing, lit or unlit |
|
|
548
|
+
| `specular: [r, g, b]` + `shininess` | a highlight; `shininess` 0, the default, turns it off however bright `specular` is | `lit`, a `Light3d`, normals |
|
|
549
|
+
| `normalMap` | tangent-space relief, a loader key or image (see Lighting below) | `lit` and a `Camera3d` |
|
|
550
|
+
| `alphaCutoff` | discard texels below this alpha: foliage, fences | nothing |
|
|
551
|
+
| `alphaMap` | per-texel opacity, multiplied in before the cutoff | a non-zero `alphaCutoff` |
|
|
552
|
+
| `baseColorFactor` | a LINEAR colour, encoded into `tint` (see `melonjs-3d-assets`) | nothing |
|
|
553
|
+
|
|
554
|
+
`emissive`, `specular` and `shininess` can be changed after construction too;
|
|
555
|
+
`setBaseColorFactor()` is the method form of the last row.
|
|
556
|
+
|
|
557
|
+
A `ShaderEffect` can shade a mesh as well: `mesh.addPostEffect(fx)` splices it
|
|
558
|
+
into the mesh shader as a colour hook on both GPU backends, so the mesh keeps its
|
|
559
|
+
placement, cutout, lighting and fog. A few builtins are unavailable there, and an
|
|
560
|
+
`InstancedMesh` cannot host one; both warn once. See
|
|
561
|
+
`melonjs-effects-and-shaders`.
|
|
514
562
|
|
|
515
563
|
### InstancedMesh, and when it is the wrong tool
|
|
516
564
|
|
|
@@ -578,9 +626,9 @@ vertices. Want smooth: share them.
|
|
|
578
626
|
An explicit `settings.normals` always wins, and an unlit mesh gets none — there
|
|
579
627
|
would be nothing to read them.
|
|
580
628
|
|
|
581
|
-
**A lit mesh with no normals used to render fullbright
|
|
582
|
-
lighting is broken rather than absent. If an older scene suddenly
|
|
583
|
-
shading, that is why.
|
|
629
|
+
**A lit mesh with no normals used to render fullbright** (before 20.4), which
|
|
630
|
+
looks like the lighting is broken rather than absent. If an older scene suddenly
|
|
631
|
+
picks up shading, that is why.
|
|
584
632
|
|
|
585
633
|
## Colouring a mesh
|
|
586
634
|
|
|
@@ -591,7 +639,7 @@ There are four levels, and picking the wrong one is the usual reason a colour
|
|
|
591
639
|
|---|---|---|
|
|
592
640
|
| whole object | `mesh.setTint("#ff8800")`, or `mesh.tint.setColor(r, g, b)` | flash on hit, team colour, fading one object |
|
|
593
641
|
| per vertex | `settings.vertexColors`, or `mesh.setVertexColor(i, color)` | a gradient *within* one mesh — distance haze, a darker crease |
|
|
594
|
-
| per material |
|
|
642
|
+
| per material | a multi-material OBJ + MTL | a model whose parts differ: each `Kd` is baked into the vertex colours, and only a different `map_Kd` costs a draw (one per `textureGroups` entry) |
|
|
595
643
|
| per instance | `new InstancedMesh(…, { instanceColors: true })` then `setInstanceColor(i, color)` | a thousand copies that differ |
|
|
596
644
|
|
|
597
645
|
**`tint` is per object.** That is the trap: build a terrain as one big mesh and
|
|
@@ -629,10 +677,11 @@ On a lit mesh the colour multiplies the **lit** result, so it behaves as albedo
|
|
|
629
677
|
rather than as an emissive override — a vertex colour will not make an unlit
|
|
630
678
|
face bright.
|
|
631
679
|
|
|
632
|
-
`alpha` hides a mesh as it hides anything else:
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
680
|
+
`alpha` hides a mesh as it hides anything else: below 1/255 the draw is skipped.
|
|
681
|
+
A fractional `alpha` fades it, through the transparent pass described under
|
|
682
|
+
Transparency above, which needs a `Camera3d` on a GPU backend. Without that pass
|
|
683
|
+
(a 2D camera on a GPU backend, or `transparent: false`) the mesh path does not
|
|
684
|
+
blend, and a faded mesh darkens instead of turning see-through.
|
|
636
685
|
|
|
637
686
|
## Moving a mesh in 3D
|
|
638
687
|
|
|
@@ -649,6 +698,12 @@ rotates about that axis. Both write to `currentTransform`, a **`Matrix3d`**,
|
|
|
649
698
|
which `Mesh` folds into its model matrix — so orienting a mesh costs a matrix
|
|
650
699
|
update, not new geometry.
|
|
651
700
|
|
|
701
|
+
Under a `Camera3d` on a GPU backend the geometry is uploaded once and redrawn
|
|
702
|
+
from the GPU, so moving, turning, scaling or re-tinting needs no signal. Editing the geometry
|
|
703
|
+
itself does: after writing into `originalVertices`, the UVs, normals or
|
|
704
|
+
indices, set `mesh.needsUpdate = true`, or the change shows under a 2D camera and
|
|
705
|
+
not under the 3D one.
|
|
706
|
+
|
|
652
707
|
This matters most for the case it is least obvious for: a horizontal plane.
|
|
653
708
|
`Sprite3d` with `billboard: false` is a quad in the sprite plane — upright —
|
|
654
709
|
and the way to lay one flat (water, a road, a shadow decal) is to rotate it a
|
|
@@ -657,13 +712,14 @@ geometry instead is tiling: a `Sprite3d` bakes its UVs 0..1 from its atlas
|
|
|
657
712
|
frame, so a surface that needs `textureRepeat` across many world units still
|
|
658
713
|
wants an explicit `vertices`/`uvs` mesh.
|
|
659
714
|
|
|
660
|
-
## The
|
|
715
|
+
## The opaque pass does not blend
|
|
661
716
|
|
|
662
717
|
Worth stating plainly, because the symptom does not look like a blending
|
|
663
|
-
problem: **the mesh pass disables blending
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
718
|
+
problem: **the opaque mesh pass disables blending**, and a draw goes there
|
|
719
|
+
unless its alpha is fractional or it says `transparent: true`. A soft-edged
|
|
720
|
+
texture — a glow, a sun, a halo, anything with a gradient alpha — drawn at full
|
|
721
|
+
opacity composites as a hard-edged disc with a grey rim, which reads as a broken
|
|
722
|
+
texture rather than as a missing feature.
|
|
667
723
|
|
|
668
724
|
`transparent: true` routes it through the transparent pass, and `blendMode:
|
|
669
725
|
"additive"` on top of that makes a light source add to the sky instead of
|
|
@@ -741,11 +797,13 @@ world.addChild(new Light3d({ type: "spot", position: torch.pos, range: 400 }));
|
|
|
741
797
|
```
|
|
742
798
|
|
|
743
799
|
`direction` and `position` take an `[x, y, z]` array **or** a `Vector3d`, and
|
|
744
|
-
`color` takes a `Color`, a CSS string or an `[r, g, b]` array
|
|
745
|
-
|
|
746
|
-
|
|
800
|
+
`color` takes a `Color`, a CSS string or an `[r, g, b]` array in **0..1** (the
|
|
801
|
+
glTF convention, not 0..255) — so a value the game already holds can go straight
|
|
802
|
+
in. The vectors are read, not retained: move your vector afterwards and the
|
|
803
|
+
light stays where it was. A `Color` is kept as given, so mutating it recolours
|
|
804
|
+
the light.
|
|
747
805
|
|
|
748
|
-
|
|
806
|
+
Three things still bite, all silently:
|
|
749
807
|
|
|
750
808
|
- `new Light3d(0, 0, {…})` — the constructor takes **options alone**. JavaScript
|
|
751
809
|
drops the extra arguments, so `options` becomes the number `0` and every
|
|
@@ -766,6 +824,10 @@ Two things still bite, both silently:
|
|
|
766
824
|
|
|
767
825
|
`position` follows the same convention: a lamp above the floor has a
|
|
768
826
|
**smaller** y than the floor.
|
|
827
|
+
- **`position` and `direction` are in world coordinates, wherever the light
|
|
828
|
+
sits in the tree.** A `Light3d` added under a container does not move or turn
|
|
829
|
+
with it, and its own `pos` is never read. To carry a lamp with a car or a
|
|
830
|
+
torch, write the object's world position into `light.position` each frame.
|
|
769
831
|
|
|
770
832
|
Use **both halves**: with a key light but no ambient, the shadow side of a mesh
|
|
771
833
|
goes black. With no `Light3d` in the world at all, a `lit: true` mesh falls back
|
|
@@ -776,6 +838,10 @@ Other defaults worth knowing: `intensity` 1, `color` white, `range` 1000 (point
|
|
|
776
838
|
and spot, a stylised quadratic falloff, not inverse-square),
|
|
777
839
|
`innerConeAngle` 0 and `outerConeAngle` π/4 (spot).
|
|
778
840
|
|
|
841
|
+
Up to **32** directional, point and spot lights shade a mesh; ambient lights are
|
|
842
|
+
summed into one fill and do not count. Lights past the 32nd are dropped without
|
|
843
|
+
a warning.
|
|
844
|
+
|
|
779
845
|
**`Light2d` is 2D-only** and produces visible artifacts under perspective
|
|
780
846
|
projection. Do not combine it with `Camera3d`.
|
|
781
847
|
|
|
@@ -858,7 +924,10 @@ the fade clamps to full strength and the blob never fades at all; and a point
|
|
|
858
924
|
on the wrong side of the caster reads as a large height, so the blob
|
|
859
925
|
disappears outright rather than thinning to a ring the way a backwards
|
|
860
926
|
`shadowGroundY` does. It is also the one shadow setting that THROWS rather
|
|
861
|
-
than clamping or hiding: a non-finite component is rejected on the spot.
|
|
927
|
+
than clamping or hiding: a non-finite component is rejected on the spot. A
|
|
928
|
+
two-component point (a `Vector2d`, a 2-element array) does not throw: its z
|
|
929
|
+
silently becomes 0. The point is copied, so moving the vector you passed moves
|
|
930
|
+
nothing; assign it again.
|
|
862
931
|
|
|
863
932
|
The blob is an ellipse sized to the caster's own footprint and placed at the
|
|
864
933
|
caster's x/z, or at `shadowGroundPoint` when one is set. So a tall or narrow object (a character, a tree, a pickup) shows
|
|
@@ -1028,7 +1097,9 @@ level.load("diorama", {
|
|
|
1028
1097
|
An **animated** asset instantiates as a `GLTFModel`, which is a game object as
|
|
1029
1098
|
much as a scene: construct it straight from the parsed descriptor, and place it
|
|
1030
1099
|
with `pos` / `depth` / `rotate` / `scale` like any other renderable — the
|
|
1031
|
-
placement drives the whole rig and composes with the playing clip
|
|
1100
|
+
placement drives the whole rig and composes with the playing clip, and still
|
|
1101
|
+
applies while the clip is paused, finished or was never played. `scale()`
|
|
1102
|
+
multiplies the `scale` option it was built with.
|
|
1032
1103
|
|
|
1033
1104
|
```js
|
|
1034
1105
|
const model = new GLTFModel(loader.getGLTF("boat"), { scale: 40, lit: false });
|
|
@@ -1048,14 +1119,20 @@ animation (and the skinning that is out of scope), and OBJ/MTL.
|
|
|
1048
1119
|
|
|
1049
1120
|
## Requires a GPU backend
|
|
1050
1121
|
|
|
1051
|
-
The
|
|
1052
|
-
|
|
1053
|
-
render
|
|
1054
|
-
are inert too.
|
|
1055
|
-
|
|
1122
|
+
The 3D tier is built for WebGPU or WebGL 2: target one of them. The Canvas
|
|
1123
|
+
renderer has no depth buffer and no perspective path, so a `Camera3d` scene
|
|
1124
|
+
does not render there — usually a black canvas. `Light3d` and shader effects
|
|
1125
|
+
are inert too.
|
|
1126
|
+
|
|
1127
|
+
A `Mesh` under a *2D* camera does render on Canvas, but only as a last resort:
|
|
1128
|
+
textured, CPU-projected, sorted back to front a triangle at a time (painter's
|
|
1129
|
+
algorithm) and unlit. Overlapping parts can show slivers of the wrong
|
|
1130
|
+
triangle, large textured faces are mapped without perspective correction, and
|
|
1131
|
+
it slows down as the triangle count grows. It keeps a 2D-camera game from going
|
|
1132
|
+
blank on a device with no GPU backend; do not design for it or tune on it.
|
|
1056
1133
|
|
|
1057
|
-
`Application` does warn:
|
|
1058
|
-
`defaultSortOn` is `"depth"
|
|
1134
|
+
`Application` does warn: `await app.init()` with a `cameraClass` whose
|
|
1135
|
+
`defaultSortOn` is `"depth"`, on a renderer with no depth buffer, logs a
|
|
1059
1136
|
`console.warn`. But `video.AUTO` falls back silently to Canvas, so the strong
|
|
1060
1137
|
gate is to ask for a GPU backend by name — `renderer: video.WEBGL` (or
|
|
1061
1138
|
`video.WEBGPU`) makes `await app.init()` reject instead of misrendering:
|
|
@@ -1070,23 +1147,42 @@ await app.init();
|
|
|
1070
1147
|
```
|
|
1071
1148
|
|
|
1072
1149
|
To branch rather than fail, read `app.renderer.supportsDepthBuffer` after
|
|
1073
|
-
`init()
|
|
1150
|
+
`init()`: a `Camera3d` game should refuse Canvas there with a message, while a
|
|
1151
|
+
game whose meshes sit under a 2D camera can let it through as the fallback.
|
|
1152
|
+
|
|
1153
|
+
```js
|
|
1154
|
+
const app = new Application(1024, 768, { parent: "screen", renderer: video.AUTO });
|
|
1155
|
+
await app.init();
|
|
1156
|
+
if (!app.renderer.supportsDepthBuffer) {
|
|
1157
|
+
// the Canvas fallback: no GPU backend on this device. Meshes under the
|
|
1158
|
+
// 2D camera still draw (CPU-projected, unlit); keep the scene small, or
|
|
1159
|
+
// tell the player the game needs WebGL 2 or WebGPU.
|
|
1160
|
+
}
|
|
1161
|
+
```
|
|
1074
1162
|
|
|
1075
1163
|
## Symptom → cause
|
|
1076
1164
|
|
|
1077
1165
|
| symptom | cause |
|
|
1078
1166
|
|---|---|
|
|
1079
1167
|
| scene lit from underneath | `direction` Y sign — this is Y-down, so a sun overhead is **+Y** |
|
|
1080
|
-
|
|
|
1168
|
+
| `model.scale(2)` throws "not a function" on a `GLTFModel` (before 20.14) | the `scale` option hid the method: update |
|
|
1169
|
+
| a `GLTFModel` ignores `pos` / `rotate` once its clip is paused or finished (before 20.14) | it was only re-posed while a clip played: update |
|
|
1170
|
+
| a sprite or mesh in a container draws too near under `Camera3d`, and pops in and out at the wrong time (before 20.14) | the container's depth was used to cull and sort its children but not to draw them: update |
|
|
1171
|
+
| a lit mesh inside a moved or turned container is lit as if the container were at the origin (before 20.14) | lights were not taken into the container's frame: update. Under a *scaled* container, a point light's range is measured in the container's units |
|
|
1172
|
+
| objects at the screen edge pop in a frame late while the camera turns, or a camera cut shows one empty frame (before 20.14) | culling used the camera as it was at the last `camera.update()`: update |
|
|
1173
|
+
| a `lit` mesh renders fullbright | no `Light3d` in the world, or a 2D camera (which warns once). Before 20.4 a mesh with no normals did it too; they are generated now |
|
|
1081
1174
|
| a gradient across one mesh is impossible | `tint` is per object — use `vertexColors` / `setVertexColor` |
|
|
1082
|
-
| a mesh stays solid as you fade it out | meshes render opaque; only `alpha` 0 (hidden) and 1 differ |
|
|
1083
1175
|
| a glow is cut along a hard straight line, worst near a round object's limb | a flat billboard being depth tested against the geometry behind it — `depthTest: false` |
|
|
1084
|
-
|
|
|
1176
|
+
| `depthTest: false` changes nothing | the mesh draws in the opaque pass, which ignores it — add `transparent: true` |
|
|
1177
|
+
| `specular` is set but no highlight appears | `shininess` is 0 (the default), or the mesh is not `lit` |
|
|
1178
|
+
| `setInstanceColor` does nothing | the set was built without `instanceColors: true`; the slot does not exist |
|
|
1179
|
+
| a vertex colour or a geometry edit applies under a 2D camera but not `Camera3d` | wrote the array directly without setting `needsUpdate` |
|
|
1085
1180
|
| `Mesh: vertexColors has N entries, expected M` | one colour per *vertex*, not per triangle or per index |
|
|
1086
1181
|
| nothing renders, or a backdrop covers everything | wrong depth sign — "far" is *larger* z when looking along +Z |
|
|
1087
1182
|
| distant objects vanish or warp | scene exceeds the default far plane; `setClipPlanes` |
|
|
1088
1183
|
| distant surfaces z-fight | `near` too small for the scene scale |
|
|
1089
1184
|
| black canvas under `Camera3d` | Canvas renderer (no depth buffer) — check the `console.warn` |
|
|
1185
|
+
| a 2D-camera mesh shows slivers where it overlaps itself, or slows with many triangles | the Canvas fallback, a last resort: ask for `video.WEBGL` or `video.WEBGPU` |
|
|
1090
1186
|
| everything flat and unlit | `lit: true` with no `Light3d` in the world (falls back to fullbright), or a mesh under a 2D camera |
|
|
1091
1187
|
| a faded mesh goes dark instead of see-through | `transparent: false` on it, or a 2D camera — the transparent pass needs a `Camera3d` |
|
|
1092
1188
|
| a soft-edged glow has hard edges | `alphaCutoff` discarded the soft texels; lower it |
|
|
@@ -1114,9 +1210,13 @@ To branch rather than fail, read `app.renderer.supportsDepthBuffer` after
|
|
|
1114
1210
|
| `setBasis` throws "forward must have a non-zero length" | `forward` is all zeros, the one case that names no direction; a short one is fine, so a surface frame that shrank as it drifted still works |
|
|
1115
1211
|
| roll is ignored when the target is straight up or down | no rotation about the view axis is determined there, so `lookAt` keeps the roll it had and `setBasis` falls back to the `right` axis |
|
|
1116
1212
|
| an object jumps to the camera plane | `Vector3d.set(x, y)` / `camera.pos.set(x, y)` zeroed its z |
|
|
1213
|
+
| a follow camera ignores its deadzone and damping | `Camera3d` follows exactly, at the target plus `followOffset`; damp it yourself with no target set |
|
|
1214
|
+
| a `Light3d` parented to a moving object stays behind | `position` is in world coordinates and its container is not applied; copy the world position into it each frame |
|
|
1117
1215
|
| lighting looks wrong under a 3D camera | `Light2d` used instead of `Light3d` |
|
|
1118
1216
|
|
|
1119
1217
|
## Related skills
|
|
1120
1218
|
|
|
1219
|
+
- `melonjs-3d-assets` — glTF/GLB and OBJ/MTL loading, imported materials and lights
|
|
1220
|
+
- `melonjs-effects-and-shaders` — a `ShaderEffect` hosted on a mesh, and custom mesh shaders
|
|
1121
1221
|
- `melonjs-renderables` — the 2D z-ordering rules, anchors, custom draw
|
|
1122
1222
|
- `melonjs-getting-started` — Application settings and the renderer fallback
|