From 020f9f9348f7cff50ea7725396d67b406f5335c3 Mon Sep 17 00:00:00 2001 From: Olivier Biot Date: Mon, 12 Oct 2026 08:32:43 +0800 Subject: [PATCH] Skills: stop showing the global `game` in code a reader copies `game` is not deprecated, but it is whichever `Application` finished `init()` last, so a skill that writes it is teaching a reader to depend on that. An audit of all 23 skills found three places. The effects skill was the real one. It wrote game.viewport.addPostEffect(new BloomEffect(app.renderer)); four times, reaching for the global for the viewport while holding `app` on the same line. Now `app.viewport`. The glTF options table listed `onLoaded` as defaulting to `app.onLevelLoaded`. There is no global `app`, and the engine's default is `game.onLevelLoaded` (`level.js:275`). Corrected. The glTF and tilemap skills both document `container` as defaulting to `game.world`, which is accurate: `level.load` really does assign `game.world`, `game.onLevelLoaded` and `game.mergeGroup` as its defaults. The fact stays, with the half that was missing. A reader who sees "default: `game.world`" reasonably concludes relying on it is the intended path, so both now say what that default actually resolves to and show passing `container: this.app.world` from a `Stage`. No skill shows the global in a code block any more, and none imports it. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01NGvtaUNATVCVxD2qcbiY4t --- packages/melonjs/skills/melonjs-3d-assets/SKILL.md | 10 +++++++++- .../skills/melonjs-effects-and-shaders/SKILL.md | 8 ++++---- packages/melonjs/skills/melonjs-tilemaps/SKILL.md | 4 ++++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/melonjs/skills/melonjs-3d-assets/SKILL.md b/packages/melonjs/skills/melonjs-3d-assets/SKILL.md index 554dcbdaf..2dbbad810 100644 --- a/packages/melonjs/skills/melonjs-3d-assets/SKILL.md +++ b/packages/melonjs/skills/melonjs-3d-assets/SKILL.md @@ -33,11 +33,19 @@ or it renders flat. See `melonjs-3d` for the camera. |---|---|---| | `scale` | `1` | pixels per glTF unit, applied to the whole scene. Blender's metre-scale export usually needs 20–100. | | `container` | `game.world` | where the nodes are added | -| `onLoaded` | `app.onLevelLoaded` | called with the **level id**, not the scene | +| `onLoaded` | `game.onLevelLoaded` | called with the **level id**, not the scene | | `async` | `false` | return a promise that settles once the scene is in the world, instead of a boolean | | `rightHanded` | `true` | see below | | `lights` | `true` | instantiate authored `KHR_lights_punctual` lights as `Light3d` world children | | `lightIntensityScale` | — | keep authored intensity ratios instead of normalising every light to 1 | + +Those `game.` defaults are the engine's, not a recommendation. `game` is +whichever `Application` finished `init()` last, so **pass `container` +explicitly** from a `Stage`, where the right one is in your hand: + +```js +level.load("sceneId", { container: this.app.world, scale: 40 }); +``` | `castGroundShadow` | inherits the app setting (**on**) | blob shadows for this scene's meshes | | `shadowGroundY` | each object's own base | world Y of the floor the blobs land on | | `shadowOpacity` | `0.45` | how dark the blobs are | diff --git a/packages/melonjs/skills/melonjs-effects-and-shaders/SKILL.md b/packages/melonjs/skills/melonjs-effects-and-shaders/SKILL.md index 1773ae27c..87f013e80 100644 --- a/packages/melonjs/skills/melonjs-effects-and-shaders/SKILL.md +++ b/packages/melonjs/skills/melonjs-effects-and-shaders/SKILL.md @@ -136,9 +136,9 @@ bright pixels bleed into their neighbours — and it is the one to put on the camera: ```js -game.viewport.addPostEffect(new BloomEffect(app.renderer)); +app.viewport.addPostEffect(new BloomEffect(app.renderer)); // only the brightest highlights, with a wider halo -game.viewport.addPostEffect( +app.viewport.addPostEffect( new BloomEffect(app.renderer, { threshold: 0.85, radius: 4 }), ); ``` @@ -154,8 +154,8 @@ reads as a white sticker. `exposure` lifts the image into the curve, and the curve (`aces`, `reinhard` or `exponential`) is baked at construction: ```js -game.viewport.addPostEffect(new BloomEffect(app.renderer)); -game.viewport.addPostEffect( +app.viewport.addPostEffect(new BloomEffect(app.renderer)); +app.viewport.addPostEffect( new ToneMappingEffect(app.renderer, { exposure: 1.6 }), ); ``` diff --git a/packages/melonjs/skills/melonjs-tilemaps/SKILL.md b/packages/melonjs/skills/melonjs-tilemaps/SKILL.md index 184d51ed8..a9031b7ed 100644 --- a/packages/melonjs/skills/melonjs-tilemaps/SKILL.md +++ b/packages/melonjs/skills/melonjs-tilemaps/SKILL.md @@ -38,6 +38,10 @@ also skip `src` and pass the map inline via `data` (with `format: "json"` or `level not found` for an unknown id — synchronously, in both forms, because that is a typo rather than a load failure. +Those `game.` defaults are the engine's own, and `game` is whichever +`Application` finished `init()` last. **Pass `container` explicitly** from a +`Stage`, which has the right one: `level.load("map", { container: this.app.world })`. + **`level.load` is deferred while the game loop is running.** It calls `state.stop()` and finishes the load on a timer, after the current frame, so by default it returns `true` before anything is in the world. Two ways to sequence