#225 by GitHub stars
melonjs/melonJS
A modern & fully featured HTML5 game engine (2D & 3D) for JavaScript/TypeScript, with WebGL/WebGPU rendering, built-in physics, Tiled map & glTF support and WebAudio.
History
Review weekly changes to SKILL.md before updating. Dates mark the weeks in which we observed each version; checks apply to the recorded commits.
View weekly changes
packages/melonjs/skills/melonjs/SKILL.md
Week of Nov 2, 2026 · +3 / −2 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
- 37 | [melonjs-input](../melonjs-input/SKILL.md) | Keyboard actions, pointer and touch handling, drag, gamepad, virtual controls. |
+ 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). |
- 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). |
+ 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; fixed or floating under the thumb, hidden until touched, tap to act. Use it rather than writing virtual controls. |
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-20-migration/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-3d/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-3d-assets/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-audio/SKILL.md
Week of Nov 2, 2026 · +7 / −5 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
- 466 **Credentials use the same global switch as every other asset type** —
- 467 `loader.setOptions({ withCredentials: true })`, not an audio-specific option.
- 468 Buffered audio fetches through the shared loader path, so it honours it exactly
- 469 as an image or a JSON file does. A streamed clip (`stream: true`, or
+ 466 **Credentials work as for every other asset type.** Buffered audio on the
+ 467 game's own origin carries its cookies and HTTP auth with no option; a clip on
+ 468 another origin behind a login needs `loader.setOptions({ withCredentials: true })`,
+ 469 not an audio-specific option, and that server must allow credentials. Buffered
+ 470 audio fetches through the shared loader path, so it behaves exactly as an image
+ 471 or a JSON file does. A streamed clip (`stream: true`, or
- 501 | audio behind a login fails, or the preload hangs | `loader.setOptions({ withCredentials: true })` — the same switch every asset type uses |
+ 503 | audio on another origin behind a login fails, or the preload hangs | `loader.setOptions({ withCredentials: true })` — the same switch every asset type uses. Audio on the game's own origin needs nothing (before 20.13 it needed it too) |
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-camera-and-drawing/SKILL.md
Week of Nov 2, 2026 · +12 / −0 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
+ 208 A stage's cameras draw in the order they were added, each over the ones before
+ 209 it, so a full-screen second camera is a layer: a `Camera3d` drawing a 3D
+ 210 background first, the game's own camera over it, each kept to its part of the
+ 211 world with `visibilityLayer` / `cullMask` (below). A camera's post effects
+ 212 apply to what that camera draws: the first camera's pass starts the frame, and
+ 213 a later camera's is blended over what is already there (20.13 and later;
+ 214 before, it wiped out the cameras before it).
+ 215
+ 239 - Particles are on their emitter's layers, and follow a change to them on the
+ 240 emitter's next update, so a camera that draws only the emitter's layer draws
+ 241 its particles too.
+ 397 | a second camera's post effect wipes out what the first camera drew | before 20.13 a later camera's post-effect pass replaced the whole frame; update, or put the effects on a container instead of the camera |
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-deployment/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-display-and-scaling/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-effects-and-shaders/SKILL.md
Week of Nov 2, 2026 · +24 / −8 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
- 157 camera's effect, a mesh's texture. Do not pass `textureSize` to get this: a
+ 157 camera's effect, a mesh's texture. With other effects after it, it still
+ 158 measures in the sprite's own pixels, at any scale and under a camera's zoom
+ 159 (on a container, in the container's own), so adding a second effect never
+ 160 changes how wide the first comes out. Do not pass `textureSize` to get this: a
- 162 // 2 pixels of the sprite's art, whatever the size of its atlas
+ 165 // 2 pixels of the sprite's art, whatever the size of its atlas, its scale,
+ 166 // the camera's zoom, or the effects after it
- 164 ```
+ 168 sprite.addPostEffect(new GlowEffect(app.renderer, { width: 6 }));
+ 169 ```
+ 170
+ 171 With two or more effects, the sprite is drawn into a capture and each effect
+ 172 reads that, at the game's texture filter, as a sprite reads its own texture:
+ 173 under `"nearest"` (or `antiAlias` off) a width that lands between two screen
+ 174 pixels, such as 2 pixels of a sprite drawn at 0.3, stays crisp, and under
+ 175 `"linear"` it blends, on WebGL and WebGPU alike. The result lands inside the
+ 176 clip the sprite is drawn under, a minimap camera's view or a clipping
+ 177 container, as with one effect.
- 721 `ShaderEffect` on a Canvas renderer logs a warning, leaves `enabled = false`, and
- 722 turns every method into a no-op. Nothing throws. The same happens on a GPU
- 723 backend when no body matches its language — a GLSL-only effect under WebGPU.
- 724
- 725 That is fine for decoration. It is **not** fine when the shader draws your
+ 734 `ShaderEffect` on a Canvas renderer leaves `enabled = false` and turns every
+ 735 method into a no-op. Nothing throws, and the console gets one warning, from the
+ 736 first such effect; the rest stay quiet. The same happens on a GPU backend when
+ 737 no body matches its language — a GLSL-only effect under WebGPU.
+ 738
+ 739 That is fine for decoration, which needs no guard: create and add the effect as
+ 740 on any renderer. It is **not** fine when the shader draws your
+ 761 | a camera's post effect hides another camera drawn before it | before 20.13 a later camera's pass replaced the whole frame; update. Since then each camera's effects apply to what it draws, over the cameras before it |
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-events/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-getting-started/SKILL.md
Week of Nov 2, 2026 · +1 / −2 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
- 140 loader.setOptions({ crossOrigin: "anonymous" }); // needed for remote assets
- 176 | cross-origin textures fail to load | missing `loader.setOptions({ crossOrigin: "anonymous" })` |
+ 175 | an asset on another origin fails to load, the error naming it | that server sends no `Access-Control-Allow-Origin` header (see melonjs-loading-assets) |
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-input/SKILL.md
Week of Nov 2, 2026 · +61 / −3 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
- 3 description: "Use this skill for keyboard, pointer, mouse, touch and gamepad input in melonJS. Covers the bindKey action indirection, registerPointerEvent on regions, the isKinematic requirement that silently blocks pointer events, which of several overlapping objects receives an event and how to consume it, world vs screen pointer coordinates, and gamepad mapping onto the same actions. Triggers on: input, bindKey, isKeyPressed, KEY, registerPointerEvent, releasePointerEvent, pointerdown, pointerup, pointermove, POINTERMOVE, gamepad, bindGamepad, triggerKeyEvent, KEYDOWN, KEYUP, press any key, splash screen, click, touch, drag, hit test, event propagation, stop propagating, overlapping, which object gets the click."
+ 3 description: "Use this skill for keyboard, pointer, mouse, touch and gamepad input in melonJS. Covers the bindKey action indirection, registerPointerEvent on regions, the isKinematic requirement that silently blocks pointer events, which of several overlapping objects receives an event and how to consume it, world vs screen pointer coordinates, and gamepad mapping onto the same actions. Triggers on: input, bindKey, isKeyPressed, KEY, registerPointerEvent, releasePointerEvent, pointerdown, pointerup, pointermove, POINTERMOVE, gamepad, bindGamepad, triggerKeyEvent, virtual gamepad, touch controls, joystick, gamepad-plugin, floating stick, floating button, floating joystick, two thumbs, tap to fire, hideAtRest, mobile controls, KEYDOWN, KEYUP, press any key, splash screen, click, touch, drag, hit test, event propagation, stop propagating, overlapping, which object gets the click."
- 276 On-screen buttons synthesise key events, again reaching the same actions:
+ 276 For on-screen touch controls, use `@melonjs/gamepad-plugin` rather than
+ 277 writing them: sticks and buttons drawn over the game and reported as a pad in
+ 278 a gamepad slot, so the `bindGamepad` bindings above answer to them unchanged.
+ 279
+ 280 ```js
+ 281 import { GamepadPlugin } from "@melonjs/gamepad-plugin";
+ 282
+ 283 // once the application is created: a stick and two buttons, on touch screens
+ 284 plugin.register(GamepadPlugin, "gamepad", {
+ 285 buttons: [{ label: "A" }, { label: "B" }],
+ 286 });
+ 287 ```
+ 288
+ 289 The left stick presses the D-pad buttons (`GAMEPAD.BUTTONS.UP` ...) in 8
+ 290 directions and reports `AXES.LX`/`LY`; the buttons press `FACE_1`, `FACE_2`...
+ 291 in turn, or a key with `{ key: input.KEY.SPACE }`. Each finger is followed on
+ 292 its own, a touch starting on the controls does not reach the game, and they
+ 293 hide while a real pad is in use. `plugin.cache.gamepad.visible` says whether
+ 294 they show, to word a prompt ("tap" or a key name).
+ 295
+ 296 Sticks and buttons are fixed in a corner by default. **`floating: true`**
+ 297 puts one under the finger wherever it lands inside its `area` (`"half"`, its
+ 298 own half of the screen, by default; `"screen"`; or `{ x, y, width, height }`),
+ 299 and **`hideAtRest: true`** draws it only while held. The usual mobile
+ 300 two-thumb layout, nothing on screen until touched (1.1):
+ 301
+ 302 ```js
+ 303 plugin.register(GamepadPlugin, "gamepad", {
+ 304 sticks: [{ floating: true, hideAtRest: true }], // left half
+ 305 buttons: [{ floating: true, hideAtRest: true, label: "A" }], // right half
+ 306 });
+ 307 ```
+ 308
+ 309 Or one thumb for both: a stick over the whole screen whose quick tap (lifted
+ 310 within `tap.time`, 250 ms, without leaning to `dpadThreshold`) presses a key
+ 311 or button for one frame, and no button at all:
+ 312
+ 313 ```js
+ 314 plugin.register(GamepadPlugin, "gamepad", {
+ 315 sticks: [{ floating: true, area: "screen", hideAtRest: true,
+ 316 tap: { key: input.KEY.SPACE } }],
+ 317 buttons: 0,
+ 318 });
+ 319 ```
+ 320
+ 321 Where areas overlap, a finger takes the first free control there: fixed
+ 322 buttons, fixed sticks, floating buttons, floating sticks. So a floating button
+ 323 on its `"half"` carves the right half out of a `"screen"` stick, and several
+ 324 floating buttons sharing an area split it by distance to where each rests.
+ 325 Every press lasts at least one frame, so a 15 ms thumb tap still reaches
+ 326 `isKeyPressed`, and Safari's pinch gesture is cancelled while the controls
+ 327 show, so a second thumb works on iOS.
+ 328
+ 329 A single key can also be pressed directly, reaching the same actions:
+ 349 | floating stick ignores the right half of the screen | its `area` defaults to `"half"`, its own side — use `area: "screen"` |
+ 350 | `area: "screen"` stick still ignores part of the screen | a floating button's area comes first there — the overlap order is fixed buttons, fixed sticks, floating buttons, floating sticks |
+ 351 | a quick tap on a stick moves instead of acting | it leaned past `dpadThreshold` or outlasted `tap.time` before lifting |
- 298 | a widget under an overlapping panel still reacts | the panel consumes nothing — return `false` from its `onClick` and `onOver` |
+ 354 | a widget under an overlapping panel still lights up | the panel consumes no hover: return `false` from its `onOver` (presses already stop at UI elements; `UIPanel` with `blocking` does both) |
+ 358 | touch controls do nothing | nothing bound to their slot — `bindGamepad` on the plugin's `index` (0 by default), or give the buttons a `key` |
+ 359 | touch controls never show on a desktop | the gamepad plugin's `enabled` defaults to `device.touch` — pass `enabled: true` to try them there |
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-lighting/SKILL.md
Week of Nov 2, 2026 · +4 / −3 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
- 177 `renderer.setLightUniforms()` is a no-op there, and the first frame that passes a
- 178 non-empty light list logs a one-shot warning. Normal-mapped sprites simply render
- 179 unlit — no error.
+ 177 `renderer.setLightUniforms()` is a no-op there, and the first normal-mapped
+ 178 sprite drawn while lights are on logs a one-shot warning (a scene with lights
+ 179 and no normal maps stays quiet). Normal-mapped sprites simply render unlit — no
+ 180 error.
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-loading-assets/SKILL.md
Week of Nov 2, 2026 · +36 / −12 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
- 15
- 16 loader.setOptions({ crossOrigin: "anonymous" }); // needed for remote assets
- 380 Two settings, both global and both applying to **every** asset type — there is
- 381 no per-asset or per-type spelling to remember:
+ 378 **Nothing to set for the usual cases.** Every fetched asset (image, json,
+ 379 binary, tmx, tsx, shader, gltf/glb, obj, mtl, aseprite, buffered audio) is
+ 380 requested the same way:
+ 381
+ 382 - **On the game's own origin**, it carries the browser's cookies and HTTP
+ 383 auth, as the page and its scripts do. A game behind a login or a session
+ 384 cookie loads its own assets with no option.
+ 385 - **On another origin** (a CDN), it is a CORS request: it loads when that
+ 386 server sends `Access-Control-Allow-Origin`, and fails at load when not, with
+ 387 an error naming the asset and the header it needs. No `crossOrigin` needed.
+ 388
+ 389 | asset on… | default | `withCredentials: true` |
+ 390 |---|---|---|
+ 391 | the game's own origin | loads, with its cookies | loads, with its cookies |
+ 392 | another origin sending `Access-Control-Allow-Origin` | loads, no cookies | **blocked** if it answers `*`; needs the page's exact origin plus `Access-Control-Allow-Credentials: true` |
+ 393 | another origin allowing credentials for the page | loads, no cookies | loads, with that origin's cookies |
+ 394 | another origin with no CORS headers | fails at load, naming the asset | fails at load, naming the asset |
+ 395
+ 396 Two global settings cover the rest, for every asset type — there is no
+ 397 per-asset or per-type spelling to remember:
- 385 crossOrigin: "anonymous", // CORS mode for remote assets
- 386 withCredentials: true, // send cookies / auth with the request
+ 401 withCredentials: true, // send cookies / auth to OTHER origins too
+ 402 crossOrigin: "anonymous", // attribute of the <video>, <script> and glTF
+ 403 // image elements the loader creates
- 390 `withCredentials` is what an asset behind a session cookie or an
- 391 `Authorization`-style login needs. Every fetched asset — image, json, binary,
- 392 tmx, tsx, shader, gltf/glb, obj, mtl, aseprite, video — carries it, and so does
- 393 buffered audio.
+ 407 `withCredentials` is for assets on **another** origin behind a session cookie
+ 408 or a login; that server must then allow credentials for the page's origin, or
+ 409 the browser blocks the request. `crossOrigin: "use-credentials"` does the same
+ 410 for fetched assets, and sets the attribute on the elements.
+ 411
+ 412 Before 20.13 both were needed far more often: assets on the game's own origin
+ 413 went out with no cookies unless `withCredentials` was set (a 401 or 403 behind
+ 414 a login), and an asset on another origin without `crossOrigin: "anonymous"`
+ 415 was read as an empty response, failing later with "Unexpected end of input" or
+ 416 "The source image could not be decoded" even when its server allowed it.
- 411 | cross-origin textures fail | missing `loader.setOptions({ crossOrigin: "anonymous" })` |
- 412 | assets behind a login 401 / audio preload hangs | missing `loader.setOptions({ withCredentials: true })` — one switch, all asset types |
+ 434 | `Failed to load "…" (Failed to fetch). An asset on another origin loads only if its server allows it…` | that origin sends no `Access-Control-Allow-Origin` header — or, with `withCredentials`, sends `*` or no `Access-Control-Allow-Credentials: true`. Fix the server's headers, or serve the asset from the game's own origin |
+ 435 | an asset on another origin behind a login 401s / audio preload hangs | missing `loader.setOptions({ withCredentials: true })` — one switch, all asset types. Assets on the game's own origin need nothing (before 20.13 they needed it too) |
+ 436 | a remote JSON fails with "Unexpected end of input", or an image with "The source image could not be decoded" | melonJS before 20.13, which read assets on another origin without CORS unless `crossOrigin: "anonymous"` was set |
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-math/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-particles-and-trails/SKILL.md
Week of Nov 2, 2026 · +72 / −8 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
- 3 description: "Use this skill for particle effects and motion trails in melonJS — ParticleEmitter configuration, burst versus stream emission, the referenceSpace frame of reference introduced in 20.2, 3D particle motion through elevation and minSpread/maxSpread in 20.8, and the Trail renderable. Covers the emitter that silently does nothing until you call an emit method. Triggers on: Trail3d, ribbon, exhaust trail, speed streak, ski track, tyre mark, ribbonNormal, ParticleEmitter, particles, burstParticles, streamParticles, referenceSpace, ParticleEmitterSettings, elevation, minSpread, maxSpread, spawn area, Trail, explosion, smoke, sparks, debris, ring, exhaust, emitter, tintOverLife, colour over life, color over life, flame, fire."
+ 3 description: "Use this skill for particle effects and motion trails in melonJS — ParticleEmitter configuration, burst versus stream emission, the referenceSpace frame of reference introduced in 20.2, 3D particle motion through elevation and minSpread/maxSpread in 20.8, and the Trail renderable. Covers the emitter that silently does nothing until you call an emit method. Triggers on: Trail3d, ribbon, exhaust trail, speed streak, ski track, tyre mark, ribbonNormal, ParticleEmitter, particles, particle editor, tune particles, spawn depth, volume, burstParticles, streamParticles, referenceSpace, ParticleEmitterSettings, elevation, minSpread, maxSpread, spawn area, Trail, explosion, smoke, sparks, debris, ring, exhaust, emitter, tintOverLife, colour over life, color over life, flame, fire."
+ 30
+ 31 Without an `image`, particles are white squares of `textureSize` pixels (8 by
+ 32 default), coloured by `tint`. Every such emitter draws the renderer's one
+ 33 shared white pixel, stretched, so an emitter per explosion or a `reset()` on
+ 34 every tweak costs no texture.
+ 35
+ 36 ## Tuning an effect: the Particle Editor
+ 37
+ 38 Settings are easier to find by eye than by reasoning. The
+ 39 [Particle Editor](https://melonjs.github.io/melonJS/examples/#/particle-editor)
+ 40 runs one emitter live, with every setting on a slider, from a preset (fire,
+ 41 smoke, rain, explosions, 3D bursts and rings…), a built-in texture or a sprite
+ 42 (sheet) of your own, under a 2D camera or an orbiting 3D one. It writes out the
+ 43 matching `new ParticleEmitter(...)` call, listing only what differs from the
+ 44 defaults, and the same settings as JSON, in the emitter's own units, to load at
+ 45 run time:
+ 46
+ 47 ```js
+ 48 // preloaded with { name: "smoke-fx", type: "json", src: "data/fx/smoke.json" }
+ 49 const effect = loader.getJSON("smoke-fx");
+ 50 const emitter = new ParticleEmitter(x, y, {
+ 51 ...effect.settings,
+ 52 // no `image` for the plain square: `getImage` would give null
+ 53 ...(effect.image ? { image: loader.getImage(effect.image) } : {}),
+ 54 });
+ 55 ```
+ 56
+ 57 Point a user there when they are tuning numbers by trial and error.
+ 58
+ 59 It covers every setting that changes how one emitter looks, but not:
+ 60
+ 61 - **Layered effects.** It shows one emitter at a time. A campfire (flames,
+ 62 sparks, smoke) or an explosion (flash, debris, smoke) is several emitters
+ 63 at the same spot: tune each in the editor, then add them side by side,
+ 64 the one drawn on top last (or with a higher `z`).
+ 65 - **Trails.** `Trail` and `Trail3d` are separate renderables; see below.
+ 66 - **Code-only settings.** `onComplete`, `autoDestroyOnComplete`,
+ 67 `accurateBounds`, and a `Container` as `referenceSpace` (it offers
+ 68 `"local"` and `"world"`). `textureAdditive` is left out: `blendMode`
+ 69 replaces it.
+ 70 - **Changes at run time.** Calling `burstParticles()` when something
+ 71 happens, or assigning `emitter.blendMode` while particles are alive, is
+ 72 game code. Its "moving emitter" option previews the common case: an
+ 73 emitter attached to something that moves.
- 110 Give it the size of whatever broke. The area is measured from the emitter's own
- 111 position, NOT centred on it, so offset by half or the whole burst sits down and
- 112 to the right of its source:
+ 154 Give it the size of whatever broke. The constructor centres the area on the
+ 155 point it is given, so pass the centre of the source:
- 116 const emitter = new ParticleEmitter(x - area / 2, y - area / 2, {
- 117 width: area, height: area,
- 118 });
+ 159 const emitter = new ParticleEmitter(x, y, { width: area, height: area });
+ 160 ```
+ 161
+ 162 After that, `pos` is the area's top-left corner, as on any renderable. To move
+ 163 the emitter to a new source later, offset by half, or the burst sits down and
+ 164 to the right of it:
+ 165
+ 166 ```js
+ 167 emitter.pos.set(x - area / 2, y - area / 2); // re-aimed at (x, y)
+ 168 emitter.burstParticles();
+ 169 ```
+ 170
+ 171 Under a `Camera3d`, `depth` (20.13) gives the area its third side: each
+ 172 particle is born at a random depth within it, centered on the emitter's own
+ 173 depth, unlike `width` and `height`. Without it every particle starts on one
+ 174 plane facing the camera, so rain or dust seen from the side is a flat sheet. A
+ 175 2D camera does not show depth, though with an order-dependent blend the
+ 176 particles are still sorted by it. It is the spawn box's size, not the
+ 177 emitter's `depth` property, which is where the emitter sits along Z.
+ 178
+ 179 ```js
+ 180 new ParticleEmitter(x, y, { width: 600, height: 20, depth: 400 }); // a volume of rain
+ 386 | a camera that draws only the emitter's layer shows no particles | before 20.13 particles stayed on layer 1 whatever their emitter was on; update |
- 338 | the burst sits down-right of its source | the spawn area starts at the emitter's position; offset by half |
+ 401 | the burst sits down-right of its source | the emitter was moved by setting `pos` to the source: `pos` is the area's top-left corner, so offset by half (only the constructor centres it) |
+ 402 | the burst sits up-left of its source | the constructor was given the top-left corner: it centres the area on (x, y), so pass the centre |
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-performance/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-physics/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-plugins/SKILL.md
Week of Nov 2, 2026 · +25 / −1 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
- 3 description: "Use this skill when adding a melonJS plugin or adapter — the debug panel, Spine skeletal animation, compressed Tiled map support, Capacitor packaging — or when writing your own plugin. Covers plugin.register and its version gate, plugin.cache, plugin.patch, and why physics adapters are not plugins. Triggers on: plugin, plugin.register, plugin.cache, plugin.get, plugin.patch, BasePlugin, debug-plugin, DebugPanelPlugin, SpinePlugin, TiledInflatePlugin, CapacitorPlugin, adapter, custom plugin, plugin version mismatch, already registered."
+ 3 description: "Use this skill when adding a melonJS plugin or adapter — the debug panel, Spine skeletal animation, compressed Tiled map support, on-screen touch controls, Capacitor packaging — or when writing your own plugin. Covers plugin.register and its version gate, plugin.cache, plugin.patch, and why physics adapters are not plugins. Triggers on: plugin, plugin.register, plugin.cache, plugin.get, plugin.patch, BasePlugin, debug-plugin, DebugPanelPlugin, SpinePlugin, TiledInflatePlugin, GamepadPlugin, gamepad-plugin, touch controls, virtual joystick, floating joystick, floating button, CapacitorPlugin, adapter, custom plugin, plugin version mismatch, already registered."
+ 91 ### `@melonjs/gamepad-plugin`
+ 92
+ 93 On-screen touch controls, reported as a gamepad: one or two sticks and any
+ 94 number of buttons, drawn over the game and read by the engine as a pad in a
+ 95 gamepad slot. The game's `bindGamepad` bindings drive it unchanged, so one set
+ 96 of bindings covers a real pad and a touch screen.
+ 97
+ 98 ```js
+ 99 import { GamepadPlugin } from "@melonjs/gamepad-plugin";
+ 100 plugin.register(GamepadPlugin, "gamepad", {
+ 101 buttons: [{ label: "A" }, { label: "B" }],
+ 102 });
+ 103 // plugin.cache.gamepad.visible — showing, to word prompts ("tap" or a key)
+ 104 ```
+ 105
+ 106 Shown on touch screens by default (`enabled`), hidden while a real pad is in
+ 107 use. The left stick also presses the D-pad; a button can press a key instead
+ 108 of a pad button. Since 1.1 a stick or button can be `floating` (shows up
+ 109 under the finger anywhere in its `area`), `hideAtRest` (drawn only while
+ 110 held), and a stick can take a `tap` (a quick touch that does not steer presses
+ 111 a key or button) — so the mobile layouts, two thumbs or one thumb with
+ 112 tap-to-act, need no code of their own. See `melonjs-input` for the bindings,
+ 113 the layouts and the overlap rules.
+ 114
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-renderables/SKILL.md
Week of Nov 2, 2026 · +4 / −3 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
- 177 the Canvas renderer (`renderer.shaderLanguage === null`) logs a warning, stays
- 178 at `enabled === false` and no-ops every method rather than throwing — and
- 179 `beginPostEffect` filters disabled effects out. Since `video.AUTO` picks the
+ 177 the Canvas renderer (`renderer.shaderLanguage === null`) stays at
+ 178 `enabled === false` and no-ops every method rather than throwing — and
+ 179 `beginPostEffect` filters disabled effects out. The first one logs a warning,
+ 180 the rest stay quiet, so a decorative effect needs no renderer check. Since `video.AUTO` picks the
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-renderer-backends/SKILL.md
Week of Nov 2, 2026 · +2 / −2 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
- 50 warns once (`Light2d normal-map lighting requires the WebGL renderer`) and then
- 51 renders sprites unlit. A `Mesh` still draws too, sorted with the painter's
+ 50 warns once (`Light2d normal-map lighting requires a GPU backend`), the first time
+ 51 a normal-mapped sprite is drawn under a light, and then renders sprites unlit. A `Mesh` still draws too, sorted with the painter's
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-scenes-and-state/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-sprites-and-animation/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-tilemaps/SKILL.md
Week of Nov 2, 2026 · +74 / −2 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
- 3 description: "Use this skill for Tiled maps in melonJS — loading TMX/TSX levels, spawning entities from Tiled objects, collision shapes authored in Tiled, isometric and hexagonal maps, and image layers. Covers registerTiledObjectClass and the pool.register name contract, camera bounds, compressed maps needing the inflate plugin, and the level director API. Triggers on: Tiled, TMX, TSX, tilemap, level.load, level.load async, await level.load, tileset, ImageLayer, isometric, hexagonal, staggered, pool.register, Collectable, Trigger, object layer, collision layer, parallax, registerTiledObjectClass, registerTiledObjectFactory, TMXObject, resolvedProperty, resolvedProperties, tile class, tile properties."
+ 3 description: "Use this skill for Tiled maps in melonJS — loading TMX/TSX levels, spawning entities from Tiled objects, collision shapes authored in Tiled, isometric and hexagonal maps, and image layers, and reading or changing tiles while the game runs. Covers registerTiledObjectClass and the pool.register name contract, camera bounds, compressed maps needing the inflate plugin, and the level director API. Triggers on: Tiled, TMX, TSX, tilemap, setTile, clearTile, cellAt, getTile, getTileById, change a tile, tile at run time, game board, grid, tile properties at run time, getTileProperties, map properties, level.load, level.load async, await level.load, tileset, ImageLayer, isometric, hexagonal, staggered, pool.register, Collectable, Trigger, object layer, collision layer, parallax, registerTiledObjectClass, registerTiledObjectFactory, TMXObject, resolvedProperty, resolvedProperties, tile class, tile properties."
+ 188 ## Reading and changing tiles at run time
+ 189
+ 190 A tile layer is a live grid, not just a picture: read it as the game board,
+ 191 and change cells while the game runs — a door opening, a floor panel lighting
+ 192 up, a wall blown away. A loaded tile layer is a `TMXLayer` in the world, under
+ 193 the name it has in Tiled:
+ 194
+ 195 ```js
+ 196 await level.load("map1", { container: this.app.world, async: true });
+ 197 const board = this.app.world.getChildByName("ground")[0]; // a TMXLayer
+ 198 board.cols; board.rows; // the grid, in cells
+ 199 board.tilewidth; board.tileheight; // a cell, in pixels
+ 200 ```
+ 201
+ 202 Two coordinate systems, and the methods do not share one:
+ 203
+ 204 | method | takes | returns |
+ 205 |---|---|---|
+ 206 | `cellAt(col, row)` | column and row | the `Tile` there, or `null` for an empty cell or outside the grid |
+ 207 | `getTile(x, y)` | **world pixels** | the same `Tile` object `cellAt` gives, or `null` |
+ 208 | `setTile(tile, col, row)` | column and row | puts `tile` there, and returns it |
+ 209 | `clearTile(col, row)` | column and row | empties the cell: `cellAt` then returns `null` |
+ 210 | `getTileById(gid, col, row)` | a global tile id, column and row | a new `Tile`, to pass to `setTile` |
+ 211
+ 212 A `Tile` carries `tileId` (its **global** id), `col`, `row` and `tileset`.
+ 213 Tiled shows a tile's *local* id in the tileset editor; the global id is
+ 214 `tileset.firstgid + localId`, and only the global one works with `setTile`.
+ 215 The tile's custom properties and class, set in Tiled's tileset editor, come
+ 216 from its tileset by global id:
+ 217
+ 218 ```js
+ 219 const tile = board.cellAt(col, row);
+ 220 const props = tile && tile.tileset.getTileProperties(tile.tileId); // { kind: "floor" } or undefined
+ 221 const cls = tile && tile.tileset.getTileClass(tile.tileId);
+ 222 ```
+ 223
+ 224 To swap a cell for another tile of the tileset, build the tile and set it. Look
+ 225 global ids up by property once, rather than hard-coding them, so a designer
+ 226 can rearrange the tileset:
+ 227
+ 228 ```js
+ 229 const tileset = board.tilesets.getTilesetByIndex(0); // the layer's first tileset
+ 230 const gidByKind = new Map();
+ 231 for (let gid = tileset.firstgid; gid <= tileset.lastgid; gid++) {
+ 232 const kind = tileset.getTileProperties(gid)?.kind;
+ 233 if (kind !== undefined) gidByKind.set(kind, gid);
+ 234 }
+ 235
+ 236 // light a floor panel up
+ 237 board.setTile(board.getTileById(gidByKind.get("floor-lit"), col, row), col, row);
+ 238 // knock a wall down
+ 239 board.clearTile(col, row);
+ 240 ```
+ 241
+ 242 The layer redraws the changed cell by itself. What it does **not** change is
+ 243 collision: solid ground comes from collision object layers (below), so a tile
+ 244 set or cleared changes what is drawn and what `cellAt` returns, not what a body
+ 245 runs into. Keep a layer you edit often off `preRender` (see the symptom table).
+ 246
+ 247 The map's own custom properties (Map → Map Properties in Tiled) are set on the
+ 248 map object, which `level.getCurrentLevel()` returns once it is loaded: a
+ 249 `theme` string property is `level.getCurrentLevel().theme`. They are set
+ 250 **over** the map's own fields, so a property named like one replaces it: a
+ 251 custom `name` property becomes the level's `name`. Give level settings names of
+ 252 their own (`title`, not `name`).
+ 253
+ 413 | objects a screen added just before `level.load` draw in the order they were added (a background over everything) | before 20.13 the reset inside `level.load` dropped the sort still pending for the persistent children it kept; update, or call `sort()` on their container once the level is loaded |
- 364 | a tileset's transparent color (`trans`) still shows (the console says it could not be applied) | the image cannot be read back: one from another origin needs CORS headers on the server and `loader.setOptions({ crossOrigin: "anonymous" })` (without them WebGL and WebGPU cannot draw it at all), and a compressed texture cannot be changed: export it with an alpha channel instead |
+ 431 | a tileset's transparent color (`trans`) still shows (the console says it could not be applied) | the image cannot be read back: an image the game made itself from another origin without CORS (an `<img>` with no `crossOrigin`) cannot be, so load it with the loader, which only loads an image another origin's server allows (its CORS headers) and can always read back; and a compressed texture cannot be changed: export it with an alpha channel instead |
+ 432 | `cellAt` returns `null` (or the wrong tile) for a cell that has one | it was given pixels: `cellAt`, `setTile` and `clearTile` take column and row, only `getTile` takes world pixels |
+ 433 | `setTile` shows the wrong tile, or nothing | it was given Tiled's local tile id: use the global id, `tileset.firstgid + localId`, through `getTileById` |
+ 434 | a layer is `undefined` from `getChildByName(name)[0]` | the level is not in the world yet (await `level.load(id, { async: true })`), or the name differs from the layer's in Tiled |
+ 435 | a tile set or cleared at run time does not block or free movement | tile layers carry no collision: collision comes from collision object layers |
+ 436 | the level's `name` is not its id after loading | a map custom property named `name` replaced it: map properties are set over the map's own fields |
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
packages/melonjs/skills/melonjs-ui-and-text/SKILL.md
Week of Nov 2, 2026 · +519 / −24 lines
Before Network or broad shell → After Network or broad shell
05ed64b14baa → a41d6a328557
- 3 description: "Use this skill for HUDs, buttons, menus, dialogue panels, progress bars and on-screen text in melonJS. Covers UIBaseElement/UISpriteElement/UITextButton, ProgressBar, UIPanel, Draggable and DropTarget, the floating screen-space container pattern, which of two overlapping panels gets the pointer, Text and BitmapText, web font loading, and NineSliceSprite panels. Triggers on: UI, HUD, button, UIBaseElement, UISpriteElement, UITextButton, ProgressBar, progress bar, health bar, gauge, Draggable, DropTarget, menu, dialogue, overlapping panels, moveToTop, onOver, onClick, bindKey, keyboard shortcut, button keyboard, Tween, easing, animate a label, wavy text, per-glyph effect, glyphEffect, shake text, rainbow text, Text, BitmapText, fillStyle, fillGradient, gradient text, tint, font, fontface, wordWrapWidth, NineSliceSprite, score display, floating., fullscreen, full screen, requestFullscreen, exitFullscreen, isFullscreen, fullscreen button, fullscreen option"
+ 3 description: "Use this skill for HUDs, buttons, menus, options screens, dialogue panels, progress bars and on-screen text in melonJS. Covers UIBaseElement/UISpriteElement/UITextButton, UICheckbox, UISlider, ProgressBar, UIPanel (skins, layout, scrolling), Draggable and DropTarget, the floating screen-space container pattern, which of two overlapping panels gets the pointer, Text and BitmapText, web font loading, and NineSliceSprite panels. Triggers on: UI, HUD, button, checkbox, radio button, UICheckbox, slider, UISlider, volume slider, options menu, settings screen, scrolling list, scroll panel, layout, column, grid, UI skin, UIBaseElement, UISpriteElement, UITextButton, ProgressBar, progress bar, health bar, gauge, Draggable, DropTarget, menu, dialogue, overlapping panels, moveToTop, onOver, onClick, bindKey, keyboard shortcut, button keyboard, Tween, easing, animate a label, wavy text, per-glyph effect, glyphEffect, shake text, rainbow text, Text, BitmapText, fillStyle, fillGradient, gradient text, tint, font, fontface, wordWrapWidth, NineSliceSprite, score display, floating., fullscreen, full screen, requestFullscreen, exitFullscreen, isFullscreen, fullscreen button, fullscreen option"
- 9 ## Outlined text: the stroke eats into the glyph
- 10
- 11 `Text` draws `fillText` and then `strokeText`, so the outline lands **on top of
- 12 the fill** and is centred on the glyph edge — half of it inward. On a small or
- 13 chunky face a `lineWidth` of 3 leaves the letters solid black. Keep it to 1,
- 14 and raise the font size rather than the stroke.
+ 9 ## Outlined text: behind the glyphs, or over them
+ 10
+ 11 An outline is centred on the glyph's edge, so half of it lies inside the
+ 12 glyph. `Text` paints it **behind** the glyphs by default (`paintOrder:
+ 13 "stroke"`): the letters stay whole and the outline shows only around them, so
+ 14 a thick outline works on any face. What shows is half of `lineWidth`: ask for
+ 15 twice the width you want to see.
+ 16
+ 17 `paintOrder: "fill"` paints the glyphs first and the outline over them, as a
+ 18 plain canvas does with `fillText` then `strokeText`, and as melonJS did before
+ 19 20.13. Its inner half then covers the letters: on a small or thin face a
+ 20 `lineWidth` of 3 already leaves them solid outline colour.
+ 21
+ 22 ```js
+ 23 const style = {
+ 24 font: "sans-serif", size: 32,
+ 25 fillStyle: "#ffd23f", strokeStyle: "#1b1b1b", lineWidth: 6,
+ 26 };
+ 27 new Text(x, y, { ...style, text: "BEHIND" }); // the default
+ 28 new Text(x, y, { ...style, paintOrder: "fill", text: "OVER" }); // the old look
+ 29 ```
+ 47 The outline's corners are set by `lineJoin`, the same property a canvas
+ 48 context has, and `miterLimit`:
+ 49
+ 50 | setting | corners | use it for |
+ 51 |---|---|---|
+ 52 | `lineJoin: "round"` (default) | rounded: the outline is the same width all around | almost everything: HUDs, buttons, titles |
+ 53 | `lineJoin: "bevel"` | cut flat | a harder edge with no spikes |
+ 54 | `lineJoin: "miter"` | pointed, as a plain canvas strokes text | a sharp, angular look |
+ 55 | `miterLimit: n` (default 10) | with `"miter"` only: a corner pointing further than `n` half line widths is cut flat instead | taming the spikes `"miter"` grows on "A", "V", "M" |
+ 56
+ 57 At the canvas default of 10, a thick `"miter"` outline grows spikes several
+ 58 times its width from sharp glyphs; 2 to 4 keeps the corners pointed and the
+ 59 spikes short:
+ 60
+ 61 ```js
+ 62 const outline = {
+ 63 font: "sans-serif", size: 48,
+ 64 fillStyle: "#ffffff", strokeStyle: "#000000", lineWidth: 6,
+ 65 };
+ 66 new Text(x, y, { ...outline, text: "ROUND" }); // the default
+ 67 new Text(x, y, { ...outline, lineJoin: "bevel", text: "BEVEL" });
+ 68 new Text(x, y, { ...outline, lineJoin: "miter", text: "MITER" }); // long spikes
+ 69 new Text(x, y, { ...outline, lineJoin: "miter", miterLimit: 3, text: "MITER 3" });
+ 70 ```
+ 71
+ 72 Whichever you pick, the bake leaves room for it on all four sides, so no corner
+ 73 is cut and the label's position and bounds do not move; pointed corners just
+ 74 cost a bigger texture. Changed on a live label, they show from the next
+ 75 `setText()`.
+ 76
- 145 | stroke | `strokeStyle` + `lineWidth` | none |
+ 190 | stroke | `strokeStyle` + `lineWidth`, behind or over the glyphs with `paintOrder`, corners with `lineJoin` / `miterLimit` | none |
+ 338 ### Which widget for what
+ 339
+ 340 | you want | use | notes |
+ 341 |---|---|---|
+ 342 | a button with a label | `UITextButton` | drawn, or skinned from an atlas; `onClick` setting |
+ 343 | an image-only button or icon | `UISpriteElement` | a `UIBaseElement` holding a `Sprite` (`sprite`); override `onClick` |
+ 344 | an on/off option, or one of several | `UICheckbox` | a radio button with `group` |
+ 345 | a value in a range: volume, sensitivity | `UISlider` | horizontal or vertical |
+ 346 | health, shield, cooldown, loading | `ProgressBar` | not clickable; `value` redraws |
+ 347 | a frame, dialog or menu card | `UIPanel` | skin, title, layout, scrolling, drag, shadow |
+ 348 | your own clickable widget | extend `UIBaseElement` | pointer handlers, `enabled`, focus, bounce |
+ 349 | a group with nothing drawn | `Container` | set `floating` for screen space |
+ 350
+ 351 ### A whole options menu
+ 352
+ 353 Everything below in one place: a skinned panel that lays its widgets out
+ 354 as a column, a checkbox, a slider, two buttons, a drop shadow, a little
+ 355 bounce, and keyboard / gamepad play. Each piece has its own section after
+ 356 this.
+ 357
+ 358 ```js
+ 359 import {
+ 360 UICheckbox, UIPanel, UISlider, UITextButton, audio, state,
+ 361 } from "melonjs";
+ 362
+ 363 // one style object for every widget's text
+ 364 const FONT = { font: "kenpixel", fontSize: 14, labelFillStyle: "black" };
+ 365
+ 366 const menu = new UIPanel(40, 40, {
+ 367 width: 360, height: 100, // autoSize grows the height to fit
+ 368 skin: { atlas, region: "grey_panel", insetx: 10, insety: 10 },
+ 369 title: "OPTIONS", titleFont: "kenpixel", titleFontSize: 20,
+ 370 layout: "column", padding: 16, gap: 12, align: "stretch", autoSize: true,
+ 371 shadowColor: "#00000059", shadowOffsetY: 6, shadowBlur: 10, radius: 6,
+ 372 });
+ 373
+ 374 const music = menu.addChild(new UICheckbox(0, 0, {
+ 375 ...FONT,
+ 376 labelOn: "Music ON", labelOff: "Music OFF",
+ 377 checked: settings.music,
+ 378 onChange: (on) => { settings.music = on; }, // user input only
+ 379 }));
+ 380
+ 381 menu.addChild(new UISlider(0, 0, {
+ 382 ...FONT,
+ 383 label: "Volume", showValue: true,
+ 384 valueFormat: (v, ratio) => `${Math.round(ratio * 100)}%`,
+ 385 value: audio.getVolume(),
+ 386 onChange: (v) => audio.setVolume(v), // while dragging
+ 387 onChangeEnd: () => saveSettings(), // once, on release
+ 388 }));
+ 389
+ 390 menu.addChild(new UITextButton(0, 0, {
+ 391 ...FONT, text: "Back", height: 40,
+ 392 hoverScale: 1.04, pressScale: 0.96, // the bounce
+ 393 onClick: () => state.change(state.MENU), // a completed click
+ 394 }));
+ 395
+ 396 app.world.addChild(menu, 10);
This preview is limited. See the complete change on GitHub.
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → 05ed64b14baa
No earlier version was observed for comparison.
Verified commit a41d6a328557d69a0441d79bbeb9cd6c430275b5
git clone --filter=blob:none --no-checkout https://github.com/melonjs/melonJS.git .hotskills/melonjs-melonjs && git -C .hotskills/melonjs-melonjs checkout --detach a41d6a328557d69a0441d79bbeb9cd6c430275b5
# Copy each selected skill directory from .hotskills/melonjs-melonjs into .claude/skills/<skill-name>/git clone --filter=blob:none --no-checkout https://github.com/melonjs/melonJS.git .hotskills/melonjs-melonjs && git -C .hotskills/melonjs-melonjs checkout --detach a41d6a328557d69a0441d79bbeb9cd6c430275b5
# Copy each selected skill directory from .hotskills/melonjs-melonjs into .agents/skills/<skill-name>/Heat
4.3- Star growth, last 7 daysAhead of 52% of tracked repositories
- Star growth, last 24 hoursAhead of 5% of tracked repositories
- Rank movement, last 7 daysAhead of 57% of tracked repositories
- Commits, last 30 daysAhead of 94% of tracked repositories
- Accounts asking about it through MCP, last 7 daysNot available
- Hot votes this weekAhead of 0% of tracked repositories
Heat never changes the order by stars, and sponsorship never touches it. How heat works
Stars over time
Individual skills in this repository
- melonjs
packages/melonjs/skills/melonjs - melonjs-20-migration
packages/melonjs/skills/melonjs-20-migration - melonjs-3d
packages/melonjs/skills/melonjs-3d - melonjs-3d-assets
packages/melonjs/skills/melonjs-3d-assets - melonjs-audio
packages/melonjs/skills/melonjs-audio - melonjs-camera-and-drawing
packages/melonjs/skills/melonjs-camera-and-drawing - melonjs-deployment
packages/melonjs/skills/melonjs-deployment - melonjs-display-and-scaling
packages/melonjs/skills/melonjs-display-and-scaling - melonjs-effects-and-shaders
packages/melonjs/skills/melonjs-effects-and-shaders - melonjs-events
packages/melonjs/skills/melonjs-events - melonjs-getting-started
packages/melonjs/skills/melonjs-getting-started - melonjs-input
packages/melonjs/skills/melonjs-input - melonjs-lighting
packages/melonjs/skills/melonjs-lighting - melonjs-loading-assets
packages/melonjs/skills/melonjs-loading-assets - melonjs-math
packages/melonjs/skills/melonjs-math - melonjs-particles-and-trails
packages/melonjs/skills/melonjs-particles-and-trails - melonjs-performance
packages/melonjs/skills/melonjs-performance - melonjs-physics
packages/melonjs/skills/melonjs-physics - melonjs-plugins
packages/melonjs/skills/melonjs-plugins - melonjs-renderables
packages/melonjs/skills/melonjs-renderables - melonjs-renderer-backends
packages/melonjs/skills/melonjs-renderer-backends - melonjs-scenes-and-state
packages/melonjs/skills/melonjs-scenes-and-state - melonjs-sprites-and-animation
packages/melonjs/skills/melonjs-sprites-and-animation - melonjs-tilemaps
packages/melonjs/skills/melonjs-tilemaps - melonjs-ui-and-text
packages/melonjs/skills/melonjs-ui-and-text
How it works
melonjs
When your agent uses it
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.
What it loads into context
Frontmatter
177 tokensAlways available to the agent
SKILL.md
2,971 tokensWhen the skill is activated
Reference documents
127,214 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- How to use this skill
- Skill router
- Escape hatch: the full API index
- The three rules that catch everyone
- Companion packages
- Prefer built-in features
Files
../../../../.claude-plugin/marketplace.jsonasset431 bytes../../../../.claude-plugin/marketplace.jsonasset431 bytes../../../../.claude-plugin/plugin.jsonasset1,760 bytes../melonjs-20-migration/SKILL.mddoc7,594 bytes../melonjs-3d-assets/SKILL.mddoc26,460 bytes../melonjs-3d/SKILL.mddoc56,504 bytes../melonjs-audio/SKILL.mddoc26,478 bytes../melonjs-camera-and-drawing/SKILL.mddoc20,373 bytes../melonjs-deployment/SKILL.mddoc4,577 bytes../melonjs-display-and-scaling/SKILL.mddoc19,677 bytes../melonjs-effects-and-shaders/SKILL.mddoc39,462 bytes../melonjs-events/SKILL.mddoc7,173 bytes../melonjs-getting-started/SKILL.mddoc7,012 bytes../melonjs-input/SKILL.mddoc18,082 bytes../melonjs-lighting/SKILL.mddoc10,771 bytes../melonjs-loading-assets/SKILL.mddoc22,006 bytes../melonjs-math/SKILL.mddoc13,549 bytes../melonjs-particles-and-trails/SKILL.mddoc20,859 bytes../melonjs-performance/SKILL.mddoc19,442 bytes../melonjs-physics/SKILL.mddoc42,524 bytes../melonjs-plugins/SKILL.mddoc9,478 bytes../melonjs-renderables/SKILL.mddoc15,438 bytes../melonjs-renderer-backends/SKILL.mddoc9,678 bytes../melonjs-scenes-and-state/SKILL.mddoc17,964 bytes../melonjs-sprites-and-animation/SKILL.mddoc8,296 bytes../melonjs-tilemaps/SKILL.mddoc24,480 bytes../melonjs-ui-and-text/SKILL.mddoc54,522 bytesSKILL.mdcore11,519 bytesSKILL.mdcore11,519 bytesSKILL.mdcore11,519 bytes
Read SKILL.md
# melonJS
Entry point for the melonJS skill collection. melonJS is an open-source HTML5
game engine for indie developers, covering 2D, 2.5D and 3D — perspective and
orthogonal cameras, GPU-accelerated tilemap rendering, post-processing effects,
custom shaders, 3D meshes, polygon-accurate physics and modern Tiled workflows.
It runs on WebGPU, WebGL 2 or Canvas with automatic fallback, and has no runtime
dependencies.
## How to use this skill
1. Find the specialised skill below that matches the task and follow it.
2. If the task involves anything 3D, read `melonjs-3d` **first** — melonJS's
coordinate conventions are the inverse of OpenGL's, so untutored 3D instinctsView the complete source on GitHubmelonjs-20-migration
When your agent uses it
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.
What it loads into context
Frontmatter
126 tokensAlways available to the agent
SKILL.md
1,960 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- 1. `Application.init()` is mandatory and asynchronous
- 2. Post effects replaced the `shader` property
- 3. WebGL 2 is the baseline; WebGPU is the default attempt
- 4. Deprecated exports still present
- 5. The global `game` is not the modern shape
- 6. Node and SSR
- 7. Browser support
- The shipped examples are not all current
- Checklist when code "should work" but doesn't
- Related skills
Files
SKILL.mdcore7,594 bytes
Read SKILL.md
# Migrating to melonJS 20.x
> What changed in melonJS 20.x, and which older APIs are gone, deprecated, or
> renamed. Read this before writing melonJS code from memory — much of what is
> published about melonJS predates 20.0.
**Why this skill exists:** most melonJS material in circulation describes 19.x or
earlier. Code written from that knowledge looks correct and fails at runtime.
The items below are ordered by how likely they are to be reproduced from memory.
## 1. `Application.init()` is mandatory and asynchronous
Since 20.0, constructing an `Application` no longer initialises it.
View the complete source on GitHubmelonjs-3d
When your agent uses it
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.
What it loads into context
Frontmatter
220 tokensAlways available to the agent
SKILL.md
14,407 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Coordinate conventions — the inverse of OpenGL
- Opting in
- Camera traps
- Where an up vector earns its keep
- Turning a direction: `slerp`, not `lerp`
- Depth sorting
- Transparency
- Distance fog
- Meshes
- Normals are generated for you
- Colouring a mesh
- Moving a mesh in 3D
- The mesh pass is opaque
- Textures under a perspective camera
- Ground must outlast the props standing on it
- Sprite3d and billboards
- Lighting
- Collision in 3D
- glTF / GLB scenes
- Requires a GPU backend
- Symptom → cause
- Related skills
Files
SKILL.mdcore56,504 bytesSKILL.mdcore56,504 bytes
Read SKILL.md
# 3D and 2.5D in melonJS
> melonJS is a 2D engine that grew a real 3D tier: perspective cameras, meshes,
> instancing, glTF scenes and 3D lights. Most of what a model "knows" about 3D
> graphics comes from the OpenGL convention, and **melonJS's is the inverse**.
> Read the conventions section before writing any 3D code.
## Coordinate conventions — the inverse of OpenGL
This is the single most important thing on this page.
| | melonJS | OpenGL convention |
|---|---|---|
| vertical | **Y-down** — higher `y` is *lower* on screen | Y-up |View the complete source on GitHubmelonjs-3d-assets
When your agent uses it
Use this skill when loading 3D models into melonJS — glTF and GLB scenes, OBJ/MTL models, materials, imported lights, node animation, ground shadows and GPU instancing. Covers level.load options including the async flag, the rightHanded conversion, and exactly what the loader does and does not support. Triggers on: glTF, gltf, glb, OBJ, MTL, 3D model, getGLTF, getOBJ, getMTL, GLTFModel, GLTFScene, level.load glb, rightHanded, lightIntensityScale, castGroundShadow, shadowGroundY, EXT_mesh_gpu_instancing, KHR_lights_punctual, skinning, Blender export, 3D asset.
What it loads into context
Frontmatter
170 tokensAlways available to the agent
SKILL.md
6,798 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Loading a glTF/GLB scene
- `rightHanded` — and the default that differs between the two APIs
- Materials — what actually arrives
- Lights
- Animation
- Instancing
- Ground shadows
- OBJ/MTL
- Authoring assets for the engine
- Packaging
- Symptom → cause
- Related skills
Files
SKILL.mdcore26,460 bytesSKILL.mdcore26,460 bytesSKILL.mdcore26,460 bytesSKILL.mdcore26,460 bytesSKILL.mdcore26,460 bytesSKILL.mdcore26,460 bytesSKILL.mdcore26,460 bytesSKILL.mdcore26,460 bytesSKILL.mdcore26,460 bytesSKILL.mdcore26,460 bytesSKILL.mdcore26,460 bytesSKILL.mdcore26,460 bytesSKILL.mdcore26,460 bytesSKILL.mdcore26,460 bytesSKILL.mdcore26,460 bytes
Read SKILL.md
# Loading 3D assets
> glTF/GLB is the primary path for 3D content, and it goes through the **level
> director** rather than the world directly: `level.load("scene")`, the same call
> a Tiled map uses. OBJ/MTL is the simpler path for a single static model.
## Loading a glTF/GLB scene
```js
await loader.preload([
{ name: "diorama", type: "glb", src: "data/scenes/diorama.glb" },
]);
level.load("diorama", { scale: 50 });View the complete source on GitHubmelonjs-audio
When your agent uses it
Use this skill for sound and music in melonJS — loading audio, playing effects, background tracks, audio sprites, volume and muting, spatial audio, procedural tone/noise generation, and effects such as reverb or a compressor on the whole mix. Covers the mandatory audio.init format list, the directory-not-file src convention, playTrack versus play, the fixed listener and pixel-scale distances of positional sound, and browser autoplay unlocking. Triggers on: audio, sound, audio.init, audio.play, playTrack, stopTrack, audio.load, sfx, music, volume, mute, fade, rate, pitch, sprite audio, stereo, panner, position, listener, refDistance, reverb, echo, delay, compressor, distortion, filter, audio effect, audio.tone, audio.noise, getAudioContext, getMasterGain, hasAudio, hasFormat, autoplay, no sound, sound stopped working, context suspended, silent after idle, clips silent but tones play.
What it loads into context
Frontmatter
213 tokensAlways available to the agent
SKILL.md
6,745 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Two setup rules
- Effects versus music
- Audio sprites
- Clip state
- Volume and muting
- Spatial audio
- Procedural sound
- Effects on all game audio: reverb, echo, compressor
- Autoplay: sound is silent until the first gesture
- Load-time options
- Symptom → cause
- Related skills
Files
SKILL.mdcore26,478 bytesSKILL.mdcore26,478 bytesSKILL.mdcore26,478 bytesSKILL.mdcore26,478 bytesSKILL.mdcore26,478 bytesSKILL.mdcore26,478 bytes
Read SKILL.md
# Audio
## Two setup rules
```js
import { audio, loader } from "melonjs";
audio.init("mp3,ogg"); // 1. BEFORE preloading any audio
await loader.preload([
{ name: "cling", type: "audio", src: "data/sfx/" }, // 2. a PREFIX, not a file
]);
```
View the complete source on GitHubmelonjs-camera-and-drawing
When your agent uses it
Use this skill for camera control and immediate-mode drawing in melonJS — following a target, viewport bounds, shake and fade, secondary cameras and what each one draws, and drawing shapes, lines and gradients inside a custom draw(). Covers world versus screen coordinate conversion, clipping and masking, baking with CanvasRenderTarget, and reading pixels back. Triggers on: Camera2d, viewport, follow, offset, look ahead, setBounds, minimap, second camera, split screen, cullMask, visibilityLayer, hide from a camera, shake, fadeIn, fadeOut, worldToLocal, localToWorld, colorMatrix, renderer.fill, renderer.stroke, Rect, Ellipse, Polygon, Line, Gradient, clipRect, mask, CanvasRenderTarget, NoiseTexture2d, lookAt, setBasis, toImageData, getImageData, toBlob, toDataURL, screenshot, read pixels.
What it loads into context
Frontmatter
199 tokensAlways available to the agent
SKILL.md
5,232 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Following a target
- Bounds are the thing people forget
- Camera effects
- Coordinate conversion
- Pointing a 3D camera
- Secondary cameras
- Immediate-mode drawing
- Clipping and masking
- Bake once, draw many
- Reading pixels back
- Symptom → cause
- Related skills
Files
SKILL.mdcore20,373 bytes
Read SKILL.md
# Camera and immediate-mode drawing
## Following a target
```js
app.viewport.follow(player, app.viewport.AXIS.BOTH, 0.1);
```
**Pass the renderable, not `renderable.pos`.** `follow()` accepts a `Renderable`,
a `Vector2d` or a `Vector3d` and **throws** `invalid target for me.Camera2d.follow`
for anything else. A renderable's `pos` is an `ObservableVector3d`, which is not
a `Vector3d` subclass, so `follow(player.pos, …)` throws.
The third argument is a damping factor in `[0 .. 1]` — lower is smoother andView the complete source on GitHubmelonjs-deployment
When your agent uses it
Use this skill when packaging, shipping or scaffolding a melonJS game — starting a project with create-melonjs, building for the web, wrapping as a native app with Capacitor or Cordova, publishing to WeChat Mini Games or Facebook Instant Games, browser support and transpiling. Triggers on: create-melonjs, scaffold, new project, build, deploy, publish, Capacitor, Cordova, native app, iOS, Android, WeChat, Instant Games, browser support, transpile, ES2022, bundle size, tree-shaking.
What it loads into context
Frontmatter
128 tokensAlways available to the agent
SKILL.md
1,083 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Scaffolding
- Adding melonJS to an existing project
- Browser support and transpiling
- Native apps
- Mini-game platforms
- Size
- Symptom → cause
- Related skills
Files
SKILL.mdcore4,577 bytesSKILL.mdcore4,577 bytesSKILL.mdcore4,577 bytes
Read SKILL.md
# Starting and shipping a project
## Scaffolding
Start from the template rather than assembling a build by hand:
```bash
npm create melonjs@latest my-game
```
The project name is required — without it the command prints its usage and
exits. It downloads the melonJS TypeScript boilerplate (Vite, TypeScript and the
debug plugin already wired in), which saves you the top-level-await and
asset-path issues that a hand-rolled config usually hits first.View the complete source on GitHubmelonjs-display-and-scaling
When your agent uses it
Use this skill when a melonJS game looks blurry, soft, shimmering or cropped, or when choosing how the canvas fills its page. Covers the design resolution, scale and scaleMethod, scaleTarget, scaleRounding for pixel-perfect integer scaling, antiAlias, textureFilter and linear-mipmap for what is drawn small, subPixel, syncToDisplay for steady motion, devicePixelRatio, and which setting does which job. Triggers on: blurry, soft, fuzzy, shimmering, pixel art, pixel perfect, crisp, nearest, linear, scale, scaleMethod, scaleTarget, scaleRounding, integer scaling, antiAlias, textureFilter, linear-mipmap, mipmaps, minimap shimmer, zoomed out, subPixel, syncToDisplay, stutter, judder, uneven scrolling, devicePixelRatio, retina, hidpi, design resolution, canvas size, canvas cropped, letterbox, image-rendering, upscale, resolution.
What it loads into context
Frontmatter
205 tokensAlways available to the agent
SKILL.md
4,953 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- The four jobs
- Design resolution
- `scale` and `scaleMethod`
- `scaleTarget`: what gets measured
- `scaleRounding`: whole device pixels
- `antiAlias` does three things
- Drawn small: `textureFilter: "linear-mipmap"`
- `subPixel` is about position, not scale
- `syncToDisplay` is about steady motion
- Soft text next to crisp sprites
- A pixel-art setup
- A smooth 3D setup
- Symptoms
Files
SKILL.mdcore19,677 bytesSKILL.mdcore19,677 bytesSKILL.mdcore19,677 bytesSKILL.mdcore19,677 bytesSKILL.mdcore19,677 bytesSKILL.mdcore19,677 bytesSKILL.mdcore19,677 bytes
Read SKILL.md
# Display and scaling
Seven settings decide how a game looks on screen, and they are easy to get
individually right and collectively wrong. This is what each one actually
does, and which one to reach for.
## The four jobs
A pixel travels from your source art to a physical pixel through four
separate decisions. Knowing which setting owns which is most of the work.
| job | setting | what it decides |
|---|---|---|
| how big the frame is drawn | `width`/`height` on `Application` | the design resolution everything is authored against |View the complete source on GitHubmelonjs-effects-and-shaders
When your agent uses it
Use this skill for post-processing effects, custom shaders, blend modes and colour grading in melonJS. Covers the built-in ShaderEffect presets, addPostEffect on renderables and cameras, writing a custom dual-language GLSL/WGSL effect, the screen_texture builtins, and why effects silently do nothing on the Canvas fallback. Triggers on: Tween, easing, animate an effect, ShaderEffect, addPostEffect, removePostEffect, getPostEffect, postEffectNeedsCapture, VignetteEffect, GlowEffect, BlurEffect, PixelateEffect, ScanlineEffect, shader, GLSL, WGSL, uniform, setUniform, setTexture, setTime, blendMode, colorMatrix, screen_texture, toFrameTexture, post effect, filter.
What it loads into context
Frontmatter
169 tokensAlways available to the agent
SKILL.md
9,763 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Applying an effect
- A renderable that draws with PRIMITIVES has to ask to be captured
- Toggle with `enabled`, do not remove
- Built-in effects
- Custom effects are dual-language
- A ShaderEffect on a mesh is a colour hook, and drops some builtins
- Extra textures bind in setTexture order
- Blend modes
- The Canvas fallback
- Symptom → cause
- Related skills
Files
SKILL.mdcore39,462 bytesSKILL.mdcore39,462 bytesSKILL.mdcore39,462 bytesSKILL.mdcore39,462 bytesSKILL.mdcore39,462 bytes
Read SKILL.md
# Post effects and custom shaders
> melonJS ships a catalogue of post effects and a dual-language shader system.
> The recurring trap is that every shader path needs a GPU backend and
> **degrades to nothing** on Canvas rather than erroring. Blend modes are the
> exception — those work on all three renderers.
## Applying an effect
Effects attach to a renderable **or** to a camera (for full-screen grading):
```js
import { VignetteEffect, GlowEffect } from "melonjs";
View the complete source on GitHubmelonjs-events
When your agent uses it
Use this skill for the melonJS event bus and lifecycle hooks — subscribing to engine events, the per-frame and per-state event names, renderable lifecycle callbacks, and how to unsubscribe without leaking. Triggers on: event.on, event.off, event.once, event.emit, GAME_UPDATE, GAME_BEFORE_DRAW, LEVEL_LOADED, LOADER_COMPLETE, STATE_CHANGE, CANVAS_ONRESIZE, POINTERMOVE, WORLD_STEP, onActivateEvent, onDeactivateEvent, onDestroyEvent, lifecycle, subscribe, listener.
What it loads into context
Frontmatter
116 tokensAlways available to the agent
SKILL.md
1,733 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- The bus
- The events worth knowing
- Renderable lifecycle callbacks
- Guard callbacks that can fire during teardown
- Removing objects from a collision callback
- Symptom → cause
- Related skills
Files
SKILL.mdcore7,173 bytes
Read SKILL.md
# Events and lifecycle
## The bus
```js
import { event } from "melonjs";
const onUpdate = () => { /* … */ };
const unsubscribe = event.on(event.GAME_UPDATE, onUpdate); // on() returns its own off()
event.once(event.LEVEL_LOADED, () => { /* … */ });
// two ways to undo it — the same reference, or the returned function
event.off(event.GAME_UPDATE, onUpdate);
unsubscribe();View the complete source on GitHubmelonjs-getting-started
When your agent uses it
Use this skill when starting or bootstrapping a melonJS game, creating the Application, choosing a renderer, or setting up the first scene. Covers the mandatory async init, the world container, adding renderables, and the WebGPU/WebGL 2/Canvas fallback. Triggers on: melonjs, new Application, app.init, app.world, video.AUTO, video.WEBGL, video.CANVAS, Stage, state.change, getting started, bootstrap.
What it loads into context
Frontmatter
109 tokensAlways available to the agent
SKILL.md
1,716 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- The bootstrap
- Top-level await
- Choosing a renderer
- The scene graph
- Scenes
- Loading assets
- `anchorPoint` defaults to the centre
- Common mistakes
- Related skills
Files
SKILL.mdcore7,012 bytesSKILL.mdcore7,012 bytes
Read SKILL.md
# Getting started with melonJS
> Bootstrapping a melonJS 20.x game: the `Application` lifecycle, the mandatory
> `await app.init()`, the world container, and what the renderer fallback means
> for feature availability.
**Applies to:** melonJS 20.x. Older major versions differ — see the
`melonjs-20-migration` skill.
## The bootstrap
`Application` construction is synchronous but **initialisation is not**. `init()`
returns a promise and must be awaited before building any renderable, loading
assets, or entering a scene.View the complete source on GitHubmelonjs-input
When your agent uses it
Use this skill for keyboard, pointer, mouse, touch and gamepad input in melonJS. Covers the bindKey action indirection, registerPointerEvent on regions, the isKinematic requirement that silently blocks pointer events, which of several overlapping objects receives an event and how to consume it, world vs screen pointer coordinates, and gamepad mapping onto the same actions. Triggers on: input, bindKey, isKeyPressed, KEY, registerPointerEvent, releasePointerEvent, pointerdown, pointerup, pointermove, POINTERMOVE, gamepad, bindGamepad, triggerKeyEvent, virtual gamepad, touch controls, joystick, gamepad-plugin, floating stick, floating button, floating joystick, two thumbs, tap to fire, hideAtRest, mobile controls, KEYDOWN, KEYUP, press any key, splash screen, click, touch, drag, hit test, event propagation, stop propagating, overlapping, which object gets the click.
What it loads into context
Frontmatter
204 tokensAlways available to the agent
SKILL.md
4,470 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Keyboard goes through named actions
- Pointer events need `isKinematic = false`
- Which object gets the event
- World coordinates versus screen coordinates
- Pointer move and release outside a region
- Gamepad
- Virtual controls
- Symptom → cause
- Related skills
Files
SKILL.mdcore18,082 bytes
Read SKILL.md
# Input: keyboard, pointer and gamepad
## Keyboard goes through named actions
Do not poll key codes. Bind a key to an **action string**, then poll the action —
this is what lets gamepad and virtual controls map onto the same handling.
```js
import { input } from "melonjs";
input.bindKey(input.KEY.LEFT, "left");
input.bindKey(input.KEY.RIGHT, "right");
input.bindKey(input.KEY.X, "jump", true); // true = locked: one press per keydown
View the complete source on GitHubmelonjs-lighting
When your agent uses it
Use this skill for 2D dynamic lighting in melonJS — Light2d, ambient light on a Stage, multiple lights, and per-pixel normal-mapped sprites authored in SpriteIlluminator. Covers specular highlights via shininess, the ambient-cutout model, which parts need a GPU backend, and why Light2d does not survive a Camera3d. Triggers on: Light2d, specular, shininess, highlight, glint, lighting, ambientLight, ambientLightingColor, normalMap, SpriteIlluminator, per-pixel lighting, drawLight, torch, glow, darkness.
What it loads into context
Frontmatter
138 tokensAlways available to the agent
SKILL.md
2,733 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- The model: ambient darkness plus cutouts
- Soft edges: `softness`
- Multiple lights
- Per-pixel lighting with normal maps
- Specular highlights
- What needs a GPU backend, and what does not
- Do not combine with `Camera3d`
- Symptom → cause
- Related skills
Files
SKILL.mdcore10,771 bytes
Read SKILL.md
# 2D dynamic lighting
> `Light2d` is a world renderable that cuts through a stage's ambient darkness.
> The glow and the cutout work on every backend; only per-pixel normal-map
> shading needs a GPU one. It is 2D-only.
## The model: ambient darkness plus cutouts
The `Stage` holds an ambient colour — a dark sheet painted over the scene after
the world is drawn — and each active `Light2d` punches a hole in it at its
visible area. The lights themselves are drawn additively on top.
```js
class PlayScreen extends Stage {View the complete source on GitHubmelonjs-loading-assets
When your agent uses it
Use this skill for loading and managing game assets in melonJS — the resource descriptor format, the full asset type list, preload versus load, retrieving loaded assets, base URLs and cross-origin settings, and the loading screen. Triggers on: loader, loader.preload, loader.load, resources, getImage, getJSON, getTMX, getGLTF, getVideo, getFont, setBaseURL, setOptions, crossOrigin, withCredentials, credentials, cookies, authenticated assets, CORS, asset, preload, LOADER_COMPLETE, loading screen, unload, setParser, custom asset type, generated texture, procedural texture.
What it loads into context
Frontmatter
141 tokensAlways available to the agent
SKILL.md
5,478 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- The resource descriptor
- The type list
- What belongs in the manifest — and what cannot
- Two conventions that produce 404s
- Retrieving loaded assets
- Custom asset types
- Base URLs
- Progress and completion
- Unloading
- Loading between scenes
- Cross-origin and authenticated assets
- Symptom → cause
- Related skills
Files
SKILL.mdcore22,006 bytesSKILL.mdcore22,006 bytesSKILL.mdcore22,006 bytes
Read SKILL.md
# Loading assets
## The resource descriptor
Every asset is `{ name, type, src }` plus type-specific extras:
```js
import { loader } from "melonjs";
await loader.preload([
{ name: "tiles", type: "image", src: "data/img/tiles.png" },
{ name: "map1", type: "tmx", src: "data/map/map1.tmx" },
{ name: "tileset", type: "tsx", src: "data/map/tileset.tsx" },
{ name: "sfx", type: "audio", src: "data/sfx/" },View the complete source on GitHubmelonjs-math
When your agent uses it
Use this skill for vector and matrix maths in melonJS — Vector2d, Vector3d, their observable variants, Matrix2d, Matrix3d, and the math utility functions. Covers which methods mutate and which allocate, the vector pool and when clone() is the wrong tool, interpolation with lerp, slerp, damp and moveTowards, and the argument defaults that silently drop a component. Triggers on: Vector2d, Vector3d, ObservableVector2d, ObservableVector3d, Matrix2d, Matrix3d, vector, vector maths, dot, cross, normalize, length, distance, angle, lerp, slerp, damp, moveTowards, project, clamp, degToRad, radToDeg, clone, vector pool, vector3dPool, setMuted, setCallback, my vector is wrong, z is zero, scale ignores z., moveTowards ignores z, projectN, currentTransform, setTransform, matrix, transform matrix, column-major, val, Float32Array, basis matrix, orientation matrix, Noise, getNoise1d, flicker, wobble.
What it loads into context
Frontmatter
242 tokensAlways available to the agent
SKILL.md
3,854 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- The one rule that explains most surprises
- `clone()` comes from a pool, and only pays off if you give it back
- Argument defaults that drop a component
- `cross` is two different functions
- Interpolation: four of them, and they are not interchangeable
- `project` scales THIS, and `projectN` is the one without the divide
- `length()` is `sqrt(x*x + y*y + z*z)`
- Observable vectors
- Matrices
- Utilities
- Symptoms
- Related skills
Files
SKILL.mdcore13,549 bytesSKILL.mdcore13,549 bytes
Read SKILL.md
# Vectors, matrices and maths
## The one rule that explains most surprises
**Methods mutate `this` and return it. They do not return a new vector.**
```js
const a = new Vector3d(1, 0, 0);
const b = new Vector3d(0, 1, 0);
a.cross(b); // a IS NOW the cross product; the original a is gone
a.add(b).normalize().scale(3, 3, 3); // chains, all in place
```
View the complete source on GitHubmelonjs-particles-and-trails
When your agent uses it
Use this skill for particle effects and motion trails in melonJS — ParticleEmitter configuration, burst versus stream emission, the referenceSpace frame of reference introduced in 20.2, 3D particle motion through elevation and minSpread/maxSpread in 20.8, and the Trail renderable. Covers the emitter that silently does nothing until you call an emit method. Triggers on: Trail3d, ribbon, exhaust trail, speed streak, ski track, tyre mark, ribbonNormal, ParticleEmitter, particles, particle editor, tune particles, spawn depth, volume, burstParticles, streamParticles, referenceSpace, ParticleEmitterSettings, elevation, minSpread, maxSpread, spawn area, Trail, explosion, smoke, sparks, debris, ring, exhaust, emitter, tintOverLife, colour over life, color over life, flame, fire.
What it loads into context
Frontmatter
186 tokensAlways available to the agent
SKILL.md
5,286 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- An emitter does nothing until you tell it to emit
- Tuning an effect: the Particle Editor
- Sprite-sheet particles
- Colour over life: `tintOverLife`
- Where particles are born
- Particles in 3D
- `referenceSpace` — which frame particles live in
- Particle tuning changed in 20.2
- Trails
- Performance
- Symptom → cause
- Related skills
Files
SKILL.mdcore20,859 bytesSKILL.mdcore20,859 bytes
Read SKILL.md
# Particles and trails
## An emitter does nothing until you tell it to emit
Adding a `ParticleEmitter` to the world is not enough. Nothing appears, and
nothing warns you.
```js
const emitter = new ParticleEmitter(x, y, {
image: loader.getImage("spark"),
totalParticles: 60,
speed: 4,
minLife: 200, maxLife: 800,
});View the complete source on GitHubmelonjs-performance
When your agent uses it
Use this skill when a melonJS game drops frames, allocates heavily, or needs to scale to many objects. Covers object pooling, draw-call batching, atlases, baking with CanvasRenderTarget, instancing, culling and alwaysUpdate, the debug plugin, and where the real costs are. Triggers on: performance, slow, frame rate, fps, lag, pool, pool.register, pool.pull, batching, draw calls, InstancedMesh, culling, alwaysUpdate, inViewport, CanvasRenderTarget, optimise, profiling, debug plugin, memory, render targets, hdr.
What it loads into context
Frontmatter
131 tokensAlways available to the agent
SKILL.md
4,656 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Measure first
- Batching: the biggest lever
- Pooling
- `scale()` is multiplicative
- Culling and update cost
- Bake once, draw many
- Instancing in 3D
- Update loops
- Audio and assets
- The first frame of a scene is not like the others
- Render targets, and what `hdr` costs
- Where the costs actually are
- Symptom → cause
- Related skills
Files
SKILL.mdcore19,442 bytesSKILL.mdcore19,442 bytes
Read SKILL.md
# Performance
## Measure first
Register the debug plugin and read the numbers before changing anything:
```js
import { plugin } from "melonjs";
import { DebugPanelPlugin } from "@melonjs/debug-plugin";
await app.init();
plugin.register(DebugPanelPlugin, "debugPanel");
```
View the complete source on GitHubmelonjs-physics
When your agent uses it
Use this skill for collision, physics bodies, movement, and spatial queries in melonJS — the built-in SAT world and the planck/matter adapters. Covers bodyDef vs Body, collision types and masks, the collision callback family and their firing rules, raycast/queryAABB/querySphere, the behaviour differences between adapters, and which one to pick for a given game. Triggers on: which physics engine, choosing an adapter, rotation collision, rotating body, torque, joints, stacking, Body, bodyDef, collision, collisionType, collisionMask, onCollision, onCollisionStart, onCollisionActive, raycast, queryAABB, querySphere, PlanckAdapter, MatterAdapter, gravity, velocity, applyForce, isGrounded, SAT.
What it loads into context
Frontmatter
166 tokensAlways available to the agent
SKILL.md
10,622 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Choosing a world
- Two ways to declare a body
- Move with forces, not by assigning position
- Collision callbacks — which one to use
- Spatial queries
- 3D collision: `Box3d`, `Sphere` and the Z pushback
- Built-in world quirks
- Porting between adapters
- Symptom → cause
- Related skills
Files
SKILL.mdcore42,524 bytes
Read SKILL.md
# Physics and collision
> melonJS has a built-in SAT collision world and two optional rigid-body
> adapters. Movement, collision callbacks and spatial queries all behave
> differently depending on which is active — and several of the differences fail
> silently.
## Choosing a world
| | when |
|---|---|
| **built-in** (default) | Arcade-style: platformers, top-down games. Fast, position-based, not Newtonian. |
| **`@melonjs/planck-adapter`** | Full rigid-body dynamics — stacking, joints, realistic restitution. |
| **`@melonjs/matter-adapter`** | Same class of thing, backed by matter-js. |View the complete source on GitHubmelonjs-plugins
When your agent uses it
Use this skill when adding a melonJS plugin or adapter — the debug panel, Spine skeletal animation, compressed Tiled map support, on-screen touch controls, Capacitor packaging — or when writing your own plugin. Covers plugin.register and its version gate, plugin.cache, plugin.patch, and why physics adapters are not plugins. Triggers on: plugin, plugin.register, plugin.cache, plugin.get, plugin.patch, BasePlugin, debug-plugin, DebugPanelPlugin, SpinePlugin, TiledInflatePlugin, GamepadPlugin, gamepad-plugin, touch controls, virtual joystick, floating joystick, floating button, CapacitorPlugin, adapter, custom plugin, plugin version mismatch, already registered.
What it loads into context
Frontmatter
150 tokensAlways available to the agent
SKILL.md
2,257 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Two different mechanisms
- `register` in detail
- The official plugins
- Physics adapters
- Writing your own
- Symptom → cause
- Related skills
Files
SKILL.mdcore9,478 bytes
Read SKILL.md
# Plugins and adapters
## Two different mechanisms
This trips people up, so it is worth stating first:
| | how it is installed |
|---|---|
| **Plugins** | `plugin.register(Class, name?, ...args)` — after `await app.init()` |
| **Physics adapters** | an `Application` **setting** (`physic:`), before `init()` |
```js
// the adapter is chosen at construction …
const app = new Application(800, 600, {View the complete source on GitHubmelonjs-renderables
When your agent uses it
Use this skill when subclassing Renderable, writing a custom draw() method, handling pointer or click events on game objects, applying post effects and shaders, or controlling draw order. Covers the pos-relative draw contract, isKinematic and input, addPostEffect vs the deprecated shader property, and z-ordering. Triggers on: Tween, easing, animate, Renderable, extends Renderable, draw(, update(, isKinematic, pointerEvent, registerPointerEvent, onClick, addPostEffect, removePostEffect, ShaderEffect, addChild, z-order, anchorPoint, floating.
What it loads into context
Frontmatter
135 tokensAlways available to the agent
SKILL.md
3,917 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- 1. A custom `draw()` must position itself from `this.pos`
- 2. `isKinematic` must be `false` to receive input or collisions
- 3. Draw order: only `addChild(child, z)` works
- 4. `removePostEffect()` destroys the effect
- 5. Opacity cascades; `setChildsProperty` assigns
- 6. `Vector3d.set(x, y)` silently zeroes `z`
- 7. A settings key the class never reads is silently ignored
- 8. `isRenderable` does not hide anything
- A mask belongs to you, not to the renderable
- Update and draw
- Anchors and floating
- Prefer built-in features
- Symptom → cause
- Related skills
Files
SKILL.mdcore15,438 bytes
Read SKILL.md
# Renderables, input and effects
> Subclassing `Renderable`, custom drawing, receiving pointer events, and
> applying post effects — with the traps that produce silently wrong output
> rather than an error.
Everything here is a **silent failure**: the code runs, nothing throws, and the
result is wrong. Those are the cases worth memorising, because nothing in the
type signatures warns you.
## 1. A custom `draw()` must position itself from `this.pos`
The renderer is **not** pre-translated to the renderable's position when `draw()`
is called. `Container.draw` translates by the *container's* own `pos` and thenView the complete source on GitHubmelonjs-renderer-backends
When your agent uses it
Use this skill when a feature works on one machine and not another, when choosing or pinning a renderer, or when writing code that must degrade gracefully. Covers the WebGPU to WebGL 2 to Canvas fallback ladder, what each backend supports, capability detection, and the subsystems that warn once and then stop working on Canvas. Triggers on: video.AUTO, video.WEBGPU, video.WEBGL, video.CANVAS, renderer.type, supportsDepthBuffer, shaderLanguage, WebGPU, WebGL2, Canvas fallback, context loss, backend, works on my machine.
What it loads into context
Frontmatter
134 tokensAlways available to the agent
SKILL.md
2,404 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- The ladder
- What each backend can do
- Detecting what you have
- Writing code that degrades well
- Pinning a backend
- Context loss
- Test on the backend your users get, not the one your harness picks
- Practical differences
- Symptom → cause
- Related skills
Files
SKILL.mdcore9,678 bytesSKILL.mdcore9,678 bytesSKILL.mdcore9,678 bytesSKILL.mdcore9,678 bytes
Read SKILL.md
# Renderer backends and graceful degradation
> `video.AUTO` picks a backend at **runtime**. The same code runs on a different
> renderer depending on the machine, and several subsystems degrade to nothing
> rather than erroring. This is the root cause of most "works on my machine"
> reports.
## The ladder
`video.AUTO` (the default) tries **WebGPU → WebGL 2 → Canvas** and uses the first
that initialises.
```js
const app = new Application(800, 600, {View the complete source on GitHubmelonjs-scenes-and-state
When your agent uses it
Use this skill for scene structure and game flow in melonJS — Stage subclasses, the state manager, transitions, pausing, the update loop, timers and tweens. Covers onResetEvent versus the constructor, state.set before state.change, the camera and world lifecycle per stage, and pause-aware timing. Triggers on: Tween, easing, fade out, flash, pulse, punch, shrink back, ease in, ease out, animate over time, countdown in update, Stage, state, state.set, state.change, state.transition, state.pause, onResetEvent, onDestroyEvent, onActivateEvent, onDeactivateEvent, PLAY, MENU, LOADING, update loop, GAME_UPDATE, timer, setTimeout, setInterval, Tween, freeze.
What it loads into context
Frontmatter
166 tokensAlways available to the agent
SKILL.md
4,519 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Stages and the state manager
- Persistent objects across levels
- Transitions and pausing
- The update loop
- Timers: use the engine's, not the window's
- Tweens
- Guard teardown-adjacent callbacks
- Persistence
- Symptom → cause
- Related skills
Files
SKILL.mdcore17,964 bytes
Read SKILL.md
# Scenes, game state and timing
## Stages and the state manager
A `Stage` is a screen. Register it against a state id, then change to it:
```js
import { Stage, state } from "melonjs";
class PlayScreen extends Stage {
onResetEvent(app) { /* build the scene */ }
onDestroyEvent(app) { /* tear it down */ }
}
View the complete source on GitHubmelonjs-sprites-and-animation
When your agent uses it
Use this skill when creating sprites, playing frame animations, or working with texture atlases in melonJS. Covers Sprite construction from a plain image or an atlas region, addAnimation/setCurrentAnimation, TextureAtlas for TexturePacker/ShoeBox/Aseprite, tint, flip, NineSliceSprite, and the centred anchorPoint that offsets naive positioning. Triggers on: Sprite, new Sprite, addAnimation, setCurrentAnimation, isCurrentAnimation, TextureAtlas, TexturePacker, Aseprite, ShoeBox, atlas, region, framewidth, frameheight, tint, flipX, flipY, NineSliceSprite, animation.
What it loads into context
Frontmatter
143 tokensAlways available to the agent
SKILL.md
2,065 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- `pos` is the centre, not the top-left
- Constructing a sprite
- Animation
- Texture atlases
- Visual properties
- `NineSliceSprite`
- Pooling
- Symptom → cause
- Related skills
Files
SKILL.mdcore8,296 bytesSKILL.mdcore8,296 bytes
Read SKILL.md
# Sprites, animation and atlases
> Creating sprites from images or atlases, driving frame animation, and the
> positioning trap that catches almost everyone.
## `pos` is the centre, not the top-left
`Renderable.anchorPoint` defaults to **`(0.5, 0.5)`**, so a sprite's `pos` is its
**centre**. `Container` forces `(0, 0)` instead, which is why containers and
sprites appear to disagree.
```js
// a 64×64 sprite at (100, 100) covers 68..132, not 100..164
const s = new Sprite(100, 100, { image: "hero", framewidth: 64, frameheight: 64 });View the complete source on GitHubmelonjs-tilemaps
When your agent uses it
Use this skill for Tiled maps in melonJS — loading TMX/TSX levels, spawning entities from Tiled objects, collision shapes authored in Tiled, isometric and hexagonal maps, and image layers, and reading or changing tiles while the game runs. Covers registerTiledObjectClass and the pool.register name contract, camera bounds, compressed maps needing the inflate plugin, and the level director API. Triggers on: Tiled, TMX, TSX, tilemap, setTile, clearTile, cellAt, getTile, getTileById, change a tile, tile at run time, game board, grid, tile properties at run time, getTileProperties, map properties, level.load, level.load async, await level.load, tileset, ImageLayer, isometric, hexagonal, staggered, pool.register, Collectable, Trigger, object layer, collision layer, parallax, registerTiledObjectClass, registerTiledObjectFactory, TMXObject, resolvedProperty, resolvedProperties, tile class, tile properties.
What it loads into context
Frontmatter
228 tokensAlways available to the agent
SKILL.md
6,144 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Loading a level
- Spawning entities from Tiled objects
- Reading and changing tiles at run time
- Camera bounds
- Collision shapes
- Map orientations
- Image layers
- Compressed maps need a plugin
- Rendering
- Symptom → cause
- Related skills
Files
SKILL.mdcore24,480 bytes
Read SKILL.md
# Tiled maps
> melonJS's flagship content pipeline. Maps are authored in
> [Tiled](https://www.mapeditor.org/) and loaded through the `level` director —
> you rarely touch the `TMX*` classes directly.
## Loading a level
Preload the map **and** everything it references — the `.tmx`, any external
`.tsx` tilesets, and the tileset images:
```js
await loader.preload([
{ name: "map1", type: "tmx", src: "data/map/map1.tmx" },View the complete source on GitHubmelonjs-ui-and-text
When your agent uses it
Use this skill for HUDs, buttons, menus, options screens, dialogue panels, progress bars and on-screen text in melonJS. Covers UIBaseElement/UISpriteElement/UITextButton, UICheckbox, UISlider, ProgressBar, UIPanel (skins, layout, scrolling), Draggable and DropTarget, the floating screen-space container pattern, which of two overlapping panels gets the pointer, Text and BitmapText, web font loading, and NineSliceSprite panels. Triggers on: UI, HUD, button, checkbox, radio button, UICheckbox, slider, UISlider, volume slider, options menu, settings screen, scrolling list, scroll panel, layout, column, grid, UI skin, UIBaseElement, UISpriteElement, UITextButton, ProgressBar, progress bar, health bar, gauge, Draggable, DropTarget, menu, dialogue, overlapping panels, moveToTop, onOver, onClick, bindKey, keyboard shortcut, button keyboard, Tween, easing, animate a label, wavy text, per-glyph effect, glyphEffect, shake text, rainbow text, Text, BitmapText, fillStyle, fillGradient, gradient text, tint, font, fontface, wordWrapWidth, NineSliceSprite, score display, floating., fullscreen, full screen, requestFullscreen, exitFullscreen, isFullscreen, fullscreen button, fullscreen option
What it loads into context
Frontmatter
293 tokensAlways available to the agent
SKILL.md
14,419 tokensWhen the skill is activated
Reference documents
0 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Outlined text: behind the glyphs, or over them
- Gradient text
- BitmapText: `size` is a RATIO, not pixels
- The HUD pattern
- When the UI misbehaves
- Related skills
Files
SKILL.mdcore54,522 bytesSKILL.mdcore54,522 bytesSKILL.mdcore54,522 bytes
Read SKILL.md
# UI, HUD and text
## Outlined text: behind the glyphs, or over them
An outline is centred on the glyph's edge, so half of it lies inside the
glyph. `Text` paints it **behind** the glyphs by default (`paintOrder:
"stroke"`): the letters stay whole and the outline shows only around them, so
a thick outline works on any face. What shows is half of `lineWidth`: ask for
twice the width you want to see.
`paintOrder: "fill"` paints the glyphs first and the outline over them, as a
plain canvas does with `fillText` then `strokeText`, and as melonJS did before
20.13. Its inner half then covers the letters: on a small or thin face a
`lineWidth` of 3 already leaves them solid outline colour.View the complete source on GitHubSkills included
- melonjs
- melonjs-20-migration
- melonjs-3d
- melonjs-3d-assets
- melonjs-audio
- melonjs-camera-and-drawing
- melonjs-deployment
- melonjs-display-and-scaling
- melonjs-effects-and-shaders
- melonjs-events
- melonjs-getting-started
- melonjs-input
- melonjs-lighting
- melonjs-loading-assets
- melonjs-math
- melonjs-particles-and-trails
- melonjs-performance
- melonjs-physics
- melonjs-plugins
- melonjs-renderables
- melonjs-renderer-backends
- melonjs-scenes-and-state
- melonjs-sprites-and-animation
- melonjs-tilemaps
- melonjs-ui-and-text
Repository facts
- License
- MIT
- Created
- Apr 11, 2011
- Last pushed
- Nov 6, 2026
- Forks
- 668
- Open issues
- 14
- Project activity
- Active
Rank over the last 12 weeks
Now #225 · best #168 · down 25 in 30 days
- #221 on Oct 30
- #222 on Oct 31
- #223 from Nov 1 to Nov 2
- #225 on Nov 3
- #224 from Nov 4 to Nov 5
- #225 since Nov 6
51 earlier periods
- #162 on Aug 2
- #163 from Aug 7 to Aug 8
- #162 on Aug 9
- #167 on Aug 10
- #168 from Aug 13 to Aug 16
- #170 on Aug 17
- #173 on Aug 18
- #172 on Aug 21
- #168 on Aug 22
- #174 on Aug 23
- #173 from Aug 24 to Aug 25
- #174 on Aug 26
- #177 on Aug 27
- #183 on Sep 1
- #179 on Sep 2
- #185 on Sep 3
- #181 on Sep 4
- #182 on Sep 5
- #182 on Sep 7
- #185 on Sep 8
- #186 from Sep 10 to Sep 11
- #188 on Sep 12
- #189 on Sep 13
- #190 on Sep 14
- #189 on Sep 16
- #190 on Sep 17
- #192 on Sep 18
- #190 on Sep 19
- #193 on Sep 20
- #194 on Sep 22
- #195 on Sep 23
- #194 on Sep 24
- #193 on Sep 25
- #194 on Sep 26
- #197 on Oct 1
- #199 on Oct 2
- #196 on Oct 3
- #200 from Oct 7 to Oct 8
- #204 on Oct 9
- #201 on Oct 10
- #205 on Oct 12
- #208 on Oct 13
- #206 on Oct 15
- #204 on Oct 16
- #208 on Oct 18
- #209 on Oct 20
- #210 from Oct 21 to Oct 22
- #211 on Oct 24
- #214 on Oct 25
- #214 on Oct 28
- #218 on Oct 29
Before you install
Network or broad shellAutomated signals, not a guarantee
Checked Nov 5, 2026
Not fully analyzed: some files were too long, unreadable or missing. This never lowers the level.
Show 57 notes
.claude-plugin/marketplace.json:1Analysis incomplete: Referenced executable target unavailable; not analyzedpackages/melonjs/skills/melonjs/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedpackages/melonjs/skills/melonjs/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude-plugin/marketplace.json:1Plugin-wide analysis incomplete; see repository notespackages/melonjs/skills/melonjs-3d/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedpackages/melonjs/skills/melonjs-3d-assets/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedpackages/melonjs/skills/melonjs-3d-assets/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedpackages/melonjs/skills/melonjs-3d-assets/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedpackages/melonjs/skills/melonjs-3d-assets/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedpackages/melonjs/skills/melonjs-3d-assets/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedpackages/melonjs/skills/melonjs-3d-assets/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedpackages/melonjs/skills/melonjs-3d-assets/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedpackages/melonjs/skills/melonjs-3d-assets/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedpackages/melonjs/skills/melonjs-3d-assets/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedpackages/melonjs/skills/melonjs-3d-assets/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedpackages/melonjs/skills/melonjs-3d-assets/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedpackages/melonjs/skills/melonjs-3d-assets/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedpackages/melonjs/skills/melonjs-3d-assets/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedpackages/melonjs/skills/melonjs-3d-assets/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzedpackages/melonjs/skills/melonjs-audio/SKILL.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed
- No broad tool permissions
- No dangerous shell commands
- 50 network referencesin 8 files: packages/melonjs/skills/melonjs-deployment/SKILL.md:38 melonjs/SKILL.md:65 .claude-plugin/plugin.json:5 and 5 more
- No hidden or obfuscated text
- No instruction overrides
- No executable scripts
- 2 references to secretsin 1 file: packages/melonjs/skills/melonjs-loading-assets/SKILL.md:382
- No requests to vote in Hot
Show all 52 signals by file
.claude-plugin/marketplace.json
- Network accessline 2
"name": "melonjs", "description": "Skills for building games with melonJS, the open source 2D, 2.5D and 3D HTML5 game engine.", "owner": { "name": "melonJS", "url": "https://melonjs.org" }, - Network accessline 3
"description": "Skills for building games with melonJS, the open source 2D, 2.5D and 3D HTML5 game engine.", "owner": { "name": "melonJS", "url": "https://melonjs.org" }, "plugins": [ - Network accessline 4
"owner": { "name": "melonJS", "url": "https://melonjs.org" },
.claude-plugin/plugin.json
- Network accessline 5
"author": { "name": "melonJS", "url": "https://melonjs.org" - Network accessline 6
"name": "melonJS", "url": "https://melonjs.org" }, - Network accessline 7
"url": "https://melonjs.org" - Network accessline 8
}, "homepage": "https://melonjs.org", "repository": "https://github.com/melonjs/melonJS", - Network accessline 9
"homepage": "https://melonjs.org", - Network accessline 10
"repository": "https://github.com/melonjs/melonJS",
packages/melonjs/skills/melonjs-deployment/SKILL.md
- Network accessline 38
<script type="module"> import { Application } from "https://cdn.jsdelivr.net/npm/melonjs@20/+esm"; - Network accessline 38
<script type="module"> import { Application } from "https://cdn.jsdelivr.net/npm/melonjs@20/+esm"; - Network accessline 39
import { Application } from "https://cdn.jsdelivr.net/npm/melonjs@20/+esm"; - Network accessline 39
import { Application } from "https://cdn.jsdelivr.net/npm/melonjs@20/+esm"; - Network accessline 76
The thing that breaks first in both is asset loading: the app is served from `file://`, where `fetch()` cannot read local files. melonJS's loader falls back - Network accessline 76
The thing that breaks first in both is asset loading: the app is served from `file://`, where `fetch()` cannot read local files. melonJS's loader falls back - Network accessline 77
`file://`, where `fetch()` cannot read local files. melonJS's loader falls back - Network accessline 77
`file://`, where `fetch()` cannot read local files. melonJS's loader falls back - Network accessline 78
to XHR for that scheme, so engine-loaded assets work — but any `fetch()` in - Network accessline 78
to XHR for that scheme, so engine-loaded assets work — but any `fetch()` in - Network accessline 104
| blank page, syntax error in the console | browser older than the ES2022 target | | transpiling changes nothing | build config excludes `node_modules` | | assets 404 in a packaged native app | `fetch()` in game code — `file://` needs XHR | - Network accessline 104
| blank page, syntax error in the console | browser older than the ES2022 target | | transpiling changes nothing | build config excludes `node_modules` | | assets 404 in a packaged native app | `fetch()` in game code — `file://` needs XHR | - Network accessline 105
| transpiling changes nothing | build config excludes `node_modules` | | assets 404 in a packaged native app | `fetch()` in game code — `file://` needs XHR | | a built-in method is missing after transpiling | transpiling is syntax-only; pol - Network accessline 105
| transpiling changes nothing | build config excludes `node_modules` | | assets 404 in a packaged native app | `fetch()` in game code — `file://` needs XHR | | a built-in method is missing after transpiling | transpiling is syntax-only; pol - Network accessline 106
| assets 404 in a packaged native app | `fetch()` in game code — `file://` needs XHR | - Network accessline 106
| assets 404 in a packaged native app | `fetch()` in game code — `file://` needs XHR |
packages/melonjs/skills/melonjs-lighting/SKILL.md
packages/melonjs/skills/melonjs-loading-assets/SKILL.md
- Network accessline 325
loader.setBaseURL("image", "data/img/"); loader.setBaseURL("audio", "data/sfx/"); loader.setBaseURL("*", "https://cdn.example.com/"); // every 2D type at once - Network accessline 325
loader.setBaseURL("image", "data/img/"); loader.setBaseURL("audio", "data/sfx/"); loader.setBaseURL("*", "https://cdn.example.com/"); // every 2D type at once - Network accessline 327
loader.setBaseURL("*", "https://cdn.example.com/"); // every 2D type at once - Network accessline 327
loader.setBaseURL("*", "https://cdn.example.com/"); // every 2D type at once - Access to secretsline 382
[Credential-related source omitted] - Access to secretsline 382
[Credential-related source omitted]
packages/melonjs/skills/melonjs-particles-and-trails/SKILL.md
- Network accessline 38
Settings are easier to find by eye than by reasoning. The [Particle Editor](https://melonjs.github.io/melonJS/examples/#/particle-editor) - Network accessline 38
Settings are easier to find by eye than by reasoning. The [Particle Editor](https://melonjs.github.io/melonJS/examples/#/particle-editor) - Network accessline 39
[Particle Editor](https://melonjs.github.io/melonJS/examples/#/particle-editor) - Network accessline 39
[Particle Editor](https://melonjs.github.io/melonJS/examples/#/particle-editor)
packages/melonjs/skills/melonjs-tilemaps/SKILL.md
- Network accessline 9
> melonJS's flagship content pipeline. Maps are authored in > [Tiled](https://www.mapeditor.org/) and loaded through the `level` director — - Network accessline 9
> melonJS's flagship content pipeline. Maps are authored in > [Tiled](https://www.mapeditor.org/) and loaded through the `level` director — - Network accessline 10
> [Tiled](https://www.mapeditor.org/) and loaded through the `level` director — - Network accessline 10
> [Tiled](https://www.mapeditor.org/) and loaded through the `level` director —
packages/melonjs/skills/melonjs/SKILL.md
- Network accessline 65
<https://melonjs.github.io/melonJS/llms.txt> - Network accessline 108
| Package | Use when | |---|---| | [`@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` setti - Network accessline 109
|---|---| | [`@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 `rayca - Network accessline 110
| [`@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 `q - Network accessline 111
| [`@melonjs/matter-adapter`](https://www.npmjs.com/package/@melonjs/matter-adapter) | Same, backed by matter-js. Choose one adapter per game. | - Network accessline 112
| [`@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`. | - Network accessline 113
| [`@melonjs/spine-plugin`](https://www.npmjs.com/package/@melonjs/spine-plugin) | Skeletal animation authored in Spine, as a melonJS renderable. | - Network accessline 114
| [`@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()`. | - Network accessline 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; fixed or floati - Network accessline 116
| [`@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 scre - Network accessline 117
| [`create-melonjs`](https://www.npmjs.com/package/create-melonjs) | Scaffolding a new project — start here rather than assembling a build by hand. |
How the signals fit together
Facts from a static read of the files at the pinned commit. They describe what the code does, not why.
Some files could not be read; the facts below still hold.
Signal confidence: 43 facts
- Network access in code of the SKILL.mdpackages/melonjs/skills/melonjs-deployment/SKILL.md:38High confidence
- Network access in code of the SKILL.mdmelonjs-deployment/SKILL.md:38High confidence
- Network access in code of the SKILL.mdpackages/melonjs/skills/melonjs-deployment/SKILL.md:39High confidence
- Network access in code of the SKILL.mdmelonjs-deployment/SKILL.md:39High confidence
- Network access in prose of the SKILL.mdpackages/melonjs/skills/melonjs-deployment/SKILL.md:76Low confidence
- Network access in prose of the SKILL.mdmelonjs-deployment/SKILL.md:76Low confidence
- Network access in prose of the SKILL.mdpackages/melonjs/skills/melonjs-deployment/SKILL.md:77Low confidence
- Network access in prose of the SKILL.mdmelonjs-deployment/SKILL.md:77Low confidence
- Network access in prose of the SKILL.mdpackages/melonjs/skills/melonjs-deployment/SKILL.md:78Low confidence
- Network access in prose of the SKILL.mdmelonjs-deployment/SKILL.md:78Low confidence
- Network access in prose of the SKILL.mdpackages/melonjs/skills/melonjs-deployment/SKILL.md:104Low confidence
- Network access in prose of the SKILL.mdmelonjs-deployment/SKILL.md:104Low confidence
- Network access in prose of the SKILL.mdpackages/melonjs/skills/melonjs-deployment/SKILL.md:105Low confidence
- Network access in prose of the SKILL.mdmelonjs-deployment/SKILL.md:105Low confidence
- Network access in prose of the SKILL.mdpackages/melonjs/skills/melonjs-deployment/SKILL.md:106Low confidence
- Network access in prose of the SKILL.mdmelonjs-deployment/SKILL.md:106Low confidence
- Network access in prose of the SKILL.mdpackages/melonjs/skills/melonjs-lighting/SKILL.md:156Low confidence
- Network access in prose of the SKILL.mdmelonjs-lighting/SKILL.md:156Low confidence
- Network access in code of the SKILL.mdpackages/melonjs/skills/melonjs-loading-assets/SKILL.md:325High confidence
- Network access in code of the SKILL.mdmelonjs-loading-assets/SKILL.md:325High confidence
- Network access in code of the SKILL.mdpackages/melonjs/skills/melonjs-loading-assets/SKILL.md:327High confidence
- Network access in code of the SKILL.mdmelonjs-loading-assets/SKILL.md:327High confidence
- Access to secrets in prose of the SKILL.mdpackages/melonjs/skills/melonjs-loading-assets/SKILL.md:382Low confidence
- Access to secrets in prose of the SKILL.mdmelonjs-loading-assets/SKILL.md:382Low confidence
- Network access in prose of the SKILL.mdpackages/melonjs/skills/melonjs-particles-and-trails/SKILL.md:38Low confidence
- Network access in prose of the SKILL.mdmelonjs-particles-and-trails/SKILL.md:38Low confidence
- Network access in prose of the SKILL.mdpackages/melonjs/skills/melonjs-particles-and-trails/SKILL.md:39Low confidence
- Network access in prose of the SKILL.mdmelonjs-particles-and-trails/SKILL.md:39Low confidence
- Network access in prose of the SKILL.mdpackages/melonjs/skills/melonjs-tilemaps/SKILL.md:9Low confidence
- Network access in prose of the SKILL.mdmelonjs-tilemaps/SKILL.md:9Low confidence
- Network access in prose of the SKILL.mdpackages/melonjs/skills/melonjs-tilemaps/SKILL.md:10Low confidence
- Network access in prose of the SKILL.mdmelonjs-tilemaps/SKILL.md:10Low confidence
- Network access in prose of the SKILL.mdmelonjs/SKILL.md:65Low confidence
- Network access in prose of the SKILL.mdmelonjs/SKILL.md:108Low confidence
- Network access in prose of the SKILL.mdmelonjs/SKILL.md:109Low confidence
- Network access in prose of the SKILL.mdmelonjs/SKILL.md:110Low confidence
- Network access in prose of the SKILL.mdmelonjs/SKILL.md:111Low confidence
- Network access in prose of the SKILL.mdmelonjs/SKILL.md:112Low confidence
- Network access in prose of the SKILL.mdmelonjs/SKILL.md:113Low confidence
- Network access in prose of the SKILL.mdmelonjs/SKILL.md:114Low confidence
- Network access in prose of the SKILL.mdmelonjs/SKILL.md:115Low confidence
- Network access in prose of the SKILL.mdmelonjs/SKILL.md:116Low confidence
- Network access in prose of the SKILL.mdmelonjs/SKILL.md:117Low confidence
Works with
| Agent | Status | Evidence | Install to |
|---|---|---|---|
| Claude Code | Native | Manifest .claude-plugin/marketplace.json | .claude/skills/<skill-name>/ |
| Codex | Native | Manifest AGENTS.md | .agents/skills/<skill-name>/ |
| Cursor | Compatible | Standard SKILL.md packages/melonjs/skills/melonjs/SKILL.md | .cursor/skills/<skill-name>/ |
| Gemini CLI | Compatible | Standard SKILL.md packages/melonjs/skills/melonjs/SKILL.md | .gemini/skills/<skill-name>/ |
| GitHub Copilot | Compatible | Standard SKILL.md packages/melonjs/skills/melonjs/SKILL.md | .github/skills/<skill-name>/ |
| OpenCode | Compatible | Standard SKILL.md packages/melonjs/skills/melonjs/SKILL.md | .opencode/skills/<skill-name>/ |
- Native The repository ships a manifest, folder or frontmatter field for this agent.
- Compatible A standard SKILL.md that this agent can read.
- Unknown No evidence either way.
Derived automatically from paths, manifests and frontmatter. Not tested on each agent.
Add this badge to your README
It updates every night and links to this page.
[](https://hotskills.dev/skill/melonjs-melonjs/)