Skip to content

Releases: melonjs/melonJS

v19.2.0

29 Apr 11:13
9493187

Choose a tag to compare

What's New in melonJS 19.2.0

New Features

  • state.freeze(duration, music?) + Application.pause/resume/freeze — hit-stop / hit-pause primitive that pauses the stage for a fixed duration then auto-resumes. Returns a Promise<void> that resolves on unfreeze. Reentrant calls extend (don't stack); window blur cancels the freeze. Convenience proxies on Application for the same.
  • Multi-pass post-effect chainingRenderable.postEffects array with addPostEffect() / getPostEffect() / removePostEffect() / clearPostEffects(). Effects run in sequence via FBO ping-pong; single-effect renderables use a zero-overhead fast path.
  • FBO-based camera post-processing pipeline — assign a ShaderEffect to any camera's shader property for full-screen post-effects. Multi-camera independent (e.g. main + minimap with different effects).
  • Camera effects system — extensible CameraEffect base class with lifecycle. Extracted ShakeEffect, unified FadeEffect (in/out direction), and new MaskEffect for shape-based level transitions (Ellipse / Polygon shrink/reveal).
  • Camera2d.colorMatrix — built-in ColorMatrix for color grading (brightness / contrast / saturate / hueRotate / sepia / invertColors). Always applied as the final post-pass; zero overhead when identity.
  • ColorMatrix class + ColorMatrixEffect — chainable color adjustments. SepiaEffect, InvertEffect, DesaturateEffect now share a single GLSL shader via the matrix.
  • VignetteEffect — built-in shader effect to darken screen edges with configurable strength and size.
  • RenderTarget abstract base (designed for future WebGPU support) with concrete WebGLRenderTarget (FBO) and CanvasRenderTarget (canvas) implementations. New RenderTargetPool replaces the WebGL-specific FBO pool.
  • ParticleEmitter.autoDestroyOnComplete (default false) — emitter removes itself from its parent once all particles have died. Solves the leak in fire-and-forget burstParticles() use cases. Companion onComplete callback fires on completion.
  • ParticleEmitter.accurateBounds (default false) — opt-in per-frame bounds refresh for debug visualization or collision. Default off saves significant matrix work at high particle counts.
  • ParticleEmitterSettings is now an exported TypeScript interface — constructor and reset() accept Partial<ParticleEmitterSettings> for compile-time validation.
  • Text.visibleCharacters / visibleRatio — progressive text reveal / typewriter effects on Text and BitmapText. Animate visibleRatio with a Tween for character-by-character display.
  • Tween.repeatDelay(ms) — adds a delay before each repeat cycle.
  • Renderer-agnostic state methodssetViewport(), clearRenderTarget(), enableScissor(), disableScissor(), setBlendEnabled() (no-ops on Canvas, real on WebGL). Eliminates direct GL calls from the post-effect pipeline.
  • Trigger.transition — accepts "fade" (default) or "mask" for shape-based level transitions; new color setting replaces legacy fade property (backward compatible).
  • Matrix3d.transform() — accepts either 16 values (full 4x4) or 6 values (2D affine, promoted to 4x4). Mirrors the Matrix2d.transform() API.

Changed

  • Renderable.shader is now a backward-compatible getter/setter for postEffects[0] (deprecated in favour of addPostEffect() / clearPostEffects()).
  • Camera.shake() / fadeIn() / fadeOut() are now convenience wrappers that create ShakeEffect / FadeEffect instances — same signatures, fully backward compatible. Multiple shakes can coexist.
  • Trigger internally uses FadeEffect / MaskEffect instead of viewport.fadeIn() / viewport.fadeOut().
  • ParticleEmitter.reset() now clamps reversed range pairs (minLife > maxLife, min/maxStartScale, min/maxEndScale, min/maxRotation) by lowering min to max. Catches the common footgun of overriding only one half of a range.
  • Particle hot-path performance — closed-form transform construction folded into a single setTransform() call, _halfW / _halfH cached on reset, _deltaInv cached on the emitter, frame-skip bookkeeping gated behind framesToSkip > 0. ~240k matrix ops/sec saved at 1000 particles, 60fps.

Bug Fixes

  • WebGL1 stencil masking (setMask / MaskEffect) now works correctly in preferWebGL1: true mode. WebGLRenderTarget was relying on gl.DEPTH_STENCIL / gl.DEPTH_STENCIL_ATTACHMENT being exposed on the WebGL1 context, which some browser/driver combinations leave undefined. Now uses spec-defined numeric fallbacks (0x84F9 / 0x821A) and validates completeness via gl.checkFramebufferStatus() with a depth-only fallback path.
  • ImageLayer.mask, shader / postEffects, flipX() / flipY() now apply correctly. ImageLayer.preDraw() was a stripped-down copy of Renderable.preDraw() that handled only alpha / tint / blend mode. Coordinate-sensitive setup (flip, stencil mask) is now applied in draw() after the per-camera zoom transforms, so it stays correctly aligned at any viewport.zoom and across multi-camera setups.
  • state.freeze() no longer leaves the game in inconsistent states when interacting with manual pause/resume or window blur:
    • The freeze timer's auto-resume now respects whether the game was already paused when freeze started — won't unpause a manually-paused game on expiry
    • Calling state.resume() or state.stop() mid-freeze cancels the timer and resolves the freeze promise immediately
    • Window BLUR cancels the freeze (the visual "moment" is over by the time the user returns; regular pauseOnBlur still keeps the game paused while away)
  • ParticleEmitter constructor was using bitwise | instead of logical || for the width/height fallback, silently rounding any provided value to the next odd number (e.g. width: 16 → 17, width: 32 → 33).
  • Particle hitbox now tracks the visual — anchor + transform + bounds are kept consistent (rotation pivots on the visual center, bounds match the visual extent). Previously the hitbox was offset by (w/2, h/2) and lagged one frame behind the visual.
  • Canvas setMask(shape, true) now uses evenodd clipping for proper inverted mask support (was using destination-atop composite which didn't clip subsequent draws).
  • Ellipse clone() now uses the ellipse pool — consistent with Polygon.clone().
  • WebGL WebGLRenderTarget constructor and resize() now explicitly use TEXTURE0 to avoid corrupting the multi-texture batcher's texture unit bindings.
  • WebGL post-effect pipeline now explicitly sets viewport on every FBO bind and saves/restores the projection matrix, fixing rendering issues after canvas resize.

Install

npm install melonjs@19.2.0

v19.1.0

16 Apr 09:30
df65218

Choose a tag to compare

What's New in melonJS 19.1.0

New Features

  • Multi-texture batching — up to 16 textures drawn in a single batch/draw call, eliminating GPU flushes on texture changes. Automatically falls back to single-texture mode when a custom ShaderEffect is active. ~80% fewer draw calls on the platformer example (14 vs ~70 flushes/frame), with an estimated 30-50% FPS improvement on low-end mobile devices.
  • highPrecisionShader application setting — when false, caps shader precision at mediump for better performance on mobile GPUs that support highp but run faster at mediump. Default true (auto-detect highest precision).

Bug Fixes

  • getSupportedCompressedTextureFormats() no longer crashes when the GL context is unavailable
  • Examples updated for 19.0 API changes (Text standalone draw removal, Application pattern)

Install

npm install melonjs@19.1.0

v19.0.0

14 Apr 10:00
a36a29f

Choose a tag to compare

What's New in melonJS 19.0.0

New Features

  • 3D mesh renderingMesh class for textured 3D triangle meshes with OBJ/MTL model loading, drawMesh() on both WebGL and Canvas renderers, Matrix3d.perspective() for perspective projection, mesh-to-canvas/ImageBitmap export and convex hull collision shapes
  • 15 built-in ShaderEffect presetsFlashEffect, OutlineEffect, GlowEffect, DesaturateEffect, PixelateEffect, BlurEffect, ChromaticAberrationEffect, DissolveEffect, DropShadowEffect, ScanlineEffect (with CRT curvature/vignette), TintPulseEffect, WaveEffect, InvertEffect, SepiaEffect, HologramEffect. All extend ShaderEffect with configurable uniforms.
  • Trail renderable — fading, tapering ribbons behind moving objects with auto-follow or manual point mode, color gradient, width curve, opacity, and blend mode support. Works on both WebGL and Canvas.
  • Gradient color samplingGradient.getColorAt(position, out) interpolates colors at any position along a gradient with float-space interpolation and lazy-parsed Color cache
  • Math utilitieslerpArray(values, position) for interpolating across evenly-spaced value arrays; computeVertexNormal(points, index, out) for perpendicular normals at polyline vertices
  • Vertex utilitiesnormalizeVertices(), projectVertices(), convexHull() for 3D vertex operations

Changed

  • BREAKING: Renderable.currentTransform is now a Matrix3d (was Matrix2d) — code accessing currentTransform.val indices must update: translation at [12],[13] (was [6],[7])
  • BREAKING: Matrix3d.scale(x, y, z) default z changed from 0 to 1 — prevents accidental Z-axis flattening
  • BREAKING: Text.draw() and BitmapText.draw() no longer accept text, x, y parameters — standalone draw removed (deprecated since 10.6.0)
  • BREAKING: Tween uses event-based lifecycle instead of adding to game.world. Public API unchanged.
  • BREAKING: depthTest application setting removed — GPU depth sorting is incompatible with 2D alpha blending. Depth testing remains available for 3D mesh rendering only.
  • BREAKING: UITextButton settings backgroundColor/hoverColor removed — use hoverOffColor/hoverOnColor
  • Container sortOn getter/setter with cached comparator function
  • customShader property moved to base Renderer class
  • exactOptionalPropertyTypes re-enabled for stricter TypeScript checking

Performance

  • Color hex conversion — pre-computed 256-entry lookup table replaces per-call nibble extraction + string concat
  • Color.toHex/toHex8 — read glArray directly, bypassing getter overhead
  • Gradient.getColorAt — float-space interpolation via toArray()/setFloat(), avoids int↔float round trips
  • Trail rendering — zero-allocation draw loop with pre-allocated normals, hoisted divisions, single-splice point expiry

Bug Fixes

  • Rect.setSize() now calls updateBounds() — fixes pointer event regression from July 2024 TS conversion
  • WebGL depth buffer correctly used for 3D mesh rendering
  • Canvas backface culling corrected for Y-flipped screen space
  • Canvas triangle seam expansion (0.5px) for anti-aliasing gaps

Dependencies

  • vite 8.0.3 → 8.0.8
  • esbuild 0.27.4 → 0.28.0
  • typescript-eslint 8.58.1 → 8.58.2
  • react 19.2.4 → 19.2.5, react-dom 19.2.4 → 19.2.5
  • typedoc 0.28.18 → 0.28.19
  • vite-plugin-glsl 1.5.6 → 1.6.0

v18.3.0

06 Apr 23:48
2f42bbb

Choose a tag to compare

What's New in melonJS 18.3.0

New Features

  • Bezier curve drawingbezierCurveTo(), quadraticCurveTo(), and arcTo() path methods, matching the Canvas 2D API. WebGL renderer tessellates via Path2D.
  • Gradient fillscreateLinearGradient() and createRadialGradient() methods for both Canvas and WebGL renderers, usable with all fill methods
  • Dashed linessetLineDash() and getLineDash() for stroke operations on both renderers
  • Tiled object factory registry — extensible registerTiledObjectFactory() and registerTiledObjectClass() APIs for plugins to register custom Tiled object handlers without modifying engine code

Changed

  • Application as entry pointnew Application(width, height, options) auto-calls boot(), making it a standalone entry point. video.init() is deprecated.
  • Game singleton decoupled — internal modules no longer import from the barrel index.js; game singleton uses setDefaultGame pattern
  • Stage lifecycleonResetEvent(app, ...args) and onDestroyEvent(app) now receive the Application instance as first parameter
  • Container defaults — dimensions default to Infinity (no intrinsic size, no clipping), removing dependency on game.viewport
  • EventEmitter — native context parameter support on on()/once(), eliminating .bind() closure overhead

Bug Fixes

  • BitmapText bounding box — width uses last glyph visual extent; height uses actual glyph extents instead of capHeight; baseline shifts use real glyph metrics for all baselines; y offset starts at first visible pixel
  • BitmapText multiline baseline — shift applied once for entire text block instead of per-line (which caused accumulating offsets)
  • Camera2d — floating containers with Infinity bounds (e.g., HUD) are now always visible, fixing a regression where HUD elements stopped rendering
  • Sprite flicker — time-based flickering (~15 flashes/sec) replaces per-draw-call toggle that broke with multi-camera setups
  • Path2D — fix quadraticCurveTo/bezierCurveTo startPoint reference bug and adaptive segment count
  • Application — fix settings mutation, white flash on load, pool cleanup errors
  • WebGLRenderer — fix setBlendMode premultipliedAlpha tracking
  • Text — fix multiline textBaseline y offset, power-of-two texture sizes

Performance

  • BitmapText — precompute glyphMinTop/glyphMaxBottom once in font parsing; cache measureText results in setText/resize

v18.2.2

29 Mar 13:41
a9147da

Choose a tag to compare

What's Changed

melonJS Team

  • Chore: fix missing README on the npm release (58a534d)
  • Copy root README into melonjs package during dist (6ef58cd)
  • Bump spine-plugin to 2.0.1 (501de1f)

Full Changelog: 18.2.1...18.2.2

v18.2.1

29 Mar 13:21
b4d6a68

Choose a tag to compare

What's Changed

melonJS Team

  • Fix loading screen logo persisting after preload completes (3f0be6f)

Full Changelog: 18.2.0...18.2.1

v18.2.0

29 Mar 10:26
37eaf7f

Choose a tag to compare

What's New in melonJS 18.2.0

New Features

  • Multi-camera support — stages can now have multiple cameras for split-screen, minimaps, and multi-viewport layouts
  • Extensible batcher system — custom Batcher subclasses with configurable maxVertices, indexed drawing (settings.indexed), and custom projection uniform names (settings.projectionUniform)
  • Tiled 1.8–1.12 full support — oblique maps, capsule shapes, list properties, embedded base64 images, tile sub-rectangles, tilerendersize/fillmode, layer blend modes, per-object opacity/visibility, repeatx/repeaty, parallaxoriginx/parallaxoriginy, class-type properties, isCollection flag
  • RoundRect as collision shape — can now be used for SAT collision via polygon-approximated rounded corners
  • Expanded blend modes — Canvas: overlay, darken, lighten, color-dodge, color-burn, hard-light, soft-light, difference, exclusion; WebGL2: darken, lighten via gl.MIN/gl.MAX

Changed

  • TypeScript — converted plugin, camera, particles emitter, state, audio, application, input, UI, and pointer modules to TypeScript
  • CDN URLs — README now uses cdn.jsdelivr.net instead of esm.run (which is still in beta)

Bug Fixes

  • WebGLRenderersetBatcher() now rebinds the shared vertex buffer when switching batchers, allowing custom batchers with their own GL buffers
  • WebGLRenderersetBlendMode() now accepts a premultipliedAlpha parameter for correct blending with non-premultiplied textures
  • Renderer — add base setBlendMode() and GPURenderer property to fix TypeScript casts
  • Pluginplugin.register() now uses pluginClass.name for reliable name derivation
  • TMXTileset — fix animation key using first frame tile ID instead of the tile's own ID
  • CanvasRenderer — replace bezier ellipse approximation with native context.ellipse() (with polyfill)
  • Plugin — fix plugin.get() throwing TypeError when searching by name with no match
  • Events — fix duplicate BLUR entry (was missing FOCUS)
  • UIBaseElement — fix isDraggable JSDoc and released default
  • Application — fix constructor options not being optional, fix getUriFragment() unsafe cast
  • CanvasRenderersetProjection() now properly applies the projection matrix as a canvas 2D transform

Spine Plugin

  • @melonjs/spine-plugin migrated into the monorepo — custom SpineBatcher with two-color tinting, indexed drawing, expanded example with 17 official Spine characters

v18.1.0

23 Mar 04:19
b444554

Choose a tag to compare

What's New in melonJS 18.1.0

New Features

  • ShaderEffect class — simplified custom shader API that only requires a fragment apply(color, uv) function. Vertex shader, uniforms, and texture sampling boilerplate are handled automatically. Silently disabled in Canvas mode.
  • create-melonjs CLI — scaffold a new game project in seconds with npm create melonjs my-game
  • Inline source code viewer — examples now have a "Show Code" button to view syntax-highlighted source alongside the running game
  • API docs landing page — new home page with quick start, feature overview, and common tasks
  • API docs categories — sidebar organized into 14 categories (Rendering, Physics, Input, etc.)

Changed

  • Physics — collision response is now mass-proportional; overlap and velocity correction are split based on relative mass
  • Entity — deprecated in favor of Sprite/Renderable + Body (#1008)
  • Loader — modernized with Promise-based asset loading for improved parallel performance; onload/onProgress/onError deprecated in favor of events
  • TMX — refactored TMXUtils into reusable decode.ts and xml.ts modules
  • Compositor → BatcherCompositor, QuadCompositor, PrimitiveCompositor renamed to Batcher, QuadBatcher, PrimitiveBatcher (old names still work with deprecation warnings)

Bug Fixes

  • Texture cache overflow — flush and rebatch when GPU texture units are exhausted instead of throwing (#1280)
  • setAntiAlias — now controls GL texture filtering (GL_NEAREST vs GL_LINEAR) on all bound textures (#1279)
  • createPattern leak — clean up previous GPU texture when repeat mode changes (#1278)
  • Custom shader support — properly flush and restore default shader per draw call, fix setUniform using wrong GL program, reset sampler uniform on shader switch
  • TMX — fix hexagonal pixelToTileCoords mutation, canvas memory leak, collision shape dimensions, XML parsing crash, GC pressure from vector allocations
  • Sprite — fix body-renderable misalignment with trimmed atlas frames, visual vibration on flip, jumping on rotated frames (#1201, #1214)
  • Path2D — fix SVG arc parsing and ellipse rotation (#1198)
  • WebGLRenderer — fix polygon corruption from vertex mutation, scissor restore, drawVertices vertex count, resize setAntiAlias corruption
  • Z-ordering — fix reset during collision response

Performance

  • TMX loading — ~20-40% faster via tileset caching, pre-allocated decode buffers, and fast path for base64 data
  • WebGL renderingfillRect, fillEllipse, fillArc, fillRoundRect, fillPolygon now generate geometry directly, bypassing path2D and earcut
  • WebGL batching — quad rendering uses gl.drawElements with index buffer (33% less vertex data), redundant sampler calls eliminated, zero-allocation save/restore stacks
  • Collision — index-based pool access instead of array push/pop in SAT detection
  • Container — O(n) accumulator pattern in getChildByProp/getChildByType instead of O(n²)

Developer Experience

  • 74 JSDoc typo and grammar fixes across 32 files
  • Coin glow shader example in the platformer demo
  • Updated typescript-boilerplate and plugin-template for melonJS 18
  • Archived es6-boilerplate with redirect notice

Full Changelog: 18.0.0...18.1.0

v18.0.0

10 Mar 07:46

Choose a tag to compare

What's New in melonJS 18.0.0

New Features

  • Color constructor — now also accepts another Color object as parameter
  • Renderer — new backgroundColor property for clearing background between frames
  • Pool system — new type-safe createPool() API with improved performance; destroy renamed to release

Changed

  • Build system — replaced rollup with esbuild (@hornta)
  • Documentation — replaced webdoc with typedoc (@hornta)
  • Test framework — replaced mocha and puppeteer with vitest in browser mode (@hornta)
  • TypeScript — extensive conversion across the codebase: color, math, geometry, platform, DOM, keyboard, timer, application settings, pool, and more (@hornta)
  • Monorepo — migrated to pnpm workspaces with turbo (@hornta)
  • RenderableanchorPoint now uses the lighter ObservablePoint class instead of ObservableVector2d
  • Math — namespace Math is now deprecated and renamed to math for consistency
  • Deprecated API removal — all classes and methods deprecated since version 15 and lower have been removed (see Upgrade Guide)

Bug Fixes

  • Body — fix setCollisionType() not accepting numeric values; fix setVertices() fallback creating Point instead of Polygon
  • Camera — fix moveTo() upper bound clamping; fix focusOn() double-counting position
  • Container — fix addChildAt() rejecting valid index; fix getNextChild() returning wrong child; fix removeChildNow() crash when not attached to root
  • Physics — fix collision response velocity projection; fix shapes tunneling through polyline junctions; fix persistence for child bodies during reset (@Vareniel); fix step() crash with undefined ancestor
  • Renderable — fix Light2D color blending in Canvas mode (@Vareniel)
  • CanvasRenderTarget — fix arguments passed to convertToBlob() (@hornta)
  • TypeScript — fix missing OffscreenCanvas type for TextureAtlas constructor
  • Video — fix implicit global reference to HTMLVideoElement
  • Docs — fix floating default shown for UI elements (@SergioChan)

Performance

  • Collision — pre-built SAT function dispatch lookup table; reduced hot path overhead
  • Container — cache camera references outside per-child update loop
  • Physics — reduced iteration overhead in world.step()
  • QuadTree — reduced array allocations in retrieve() and insert()
  • Observable vectors — rewritten for better performance
  • Color — faster clone() method
  • Pool — optimized implementation

New Contributors

Full Changelog: 17.4.0...18.0.0

v17.4.0

22 Jun 00:57

Choose a tag to compare

Added

  • Renderer: new lineJoin property to set the line join style (only support "round" for now in WebGL mode)
  • Renderer: add support for line thickness for strokePolygon and strokeRect operations in WebGL

Changed

  • Chore: Update to TypeScript 5.5

Fixed

  • Renderer: fix fillEllipse() method in WebGL mode (that was stroking the ellipse instead)
  • TypeScript: fix most (if not all) missing declarations