Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "melonjs",
"version": "20.4.0",
"version": "20.5.0",
"description": "Build games with melonJS — 23 guides to the 2D, 2.5D and 3D HTML5 game engine, its conventions and idioms, so generated code runs the first time.",
"author": {
"name": "melonJS",
Expand Down
5 changes: 1 addition & 4 deletions packages/melonjs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
# Changelog

## [20.5.0] (melonJS 2) - _unreleased_
## [20.5.0] (melonJS 2) - _2026-09-15_

### Added
- Mesh: a `ShaderEffect` can be hosted on a mesh — `addPostEffect` shades it on both backends as a colour hook, so the mesh keeps its own placement, alpha cutout, lighting and fog. `screen_uv`, `noise_uv`, `screen_texture`, a body's own samplers, WGSL `vColor` and `InstancedMesh` are unsupported and warn once ([#1658](https://github.com/melonjs/melonJS/issues/1658))
- `GLTFModel` can be placed and moved: `pos`, `depth`, `rotate` and `scale` drive the whole rig as on any other renderable, composing with the animated pose rather than replacing it. Every root node used to hang from the identity, so a loaded model posed at the world origin and stayed there
- Text: `fillStyle` takes a `Gradient` as well as a colour, built with `createLinearGradient`/`addColorStop`. Coordinates are the label's own bake and the ramp colours the fill only, since the stroke is a separate pass. A multi-line label restarts the ramp on every line; `gradientPerLine: false` spans one ramp across the block instead
- `save`: registered keys are reachable from TypeScript without a cast. The namespace was typed `Record<string, unknown>`, and that index signature swallowed its own members, so under `strict` `save.add()` was `unknown` and could not be called at all. `add()` now returns the namespace typed with the keys just registered, and chained calls accumulate
- `audio.tone()` and `audio.noise()` take a `delay` in seconds, scheduled on the audio clock, so a multi-part sound — a stinger's second note, an explosion's double-tap — sequences without a `setTimeout`. A timer fires on the main thread and a busy frame slips the note; this is scheduled up front and is sample-accurate. Omitting it is unchanged

- `Gradient#toCanvasGradient(ctx)` is public: a `Gradient` could be built and handed to `Text.fillStyle`, but there was no supported way to rasterise one into your own canvas. It returns a native `CanvasGradient` and holds no shared state
- Camera: `roll` completes the `pitch` / `yaw` trio. On a `Camera3d` it banks the view and the frustum planes follow, so culling stays correct under a bank; on a `Camera2d` it is the screen-plane rotation, and picking compensates for it. Assigning it rebuilds the camera transform, so a camera banked every frame cannot drift

- `Light3d`: `direction` and `position` accept a `Vector3d` as well as an `[x, y, z]` array, so a value the game already holds goes straight in — `color` already took a `Color`, a string or an array. The vector is read, not retained. Passing one used to be read by index and silently produce a `NaN` direction, so the light contributed nothing ([#1661](https://github.com/melonjs/melonJS/issues/1661))

- Typings: a parsed glTF node's geometry is readable from TypeScript. `GLTFData.nodes` was `object[]` with its fields listed in prose, so `node.vertices` did not compile — the array is `GLTFNode[]` now. `Mesh`'s `texture` accepts a `Texture2d` and its `indices` a `Uint32Array`, both of which it already handled; a shader `Asset` may carry the `{glsl, wgsl}` pair the loader has always parsed

### Fixed
Expand Down
Loading