v19.2.0
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 aPromise<void>that resolves on unfreeze. Reentrant calls extend (don't stack); window blur cancels the freeze. Convenience proxies onApplicationfor the same.- Multi-pass post-effect chaining —
Renderable.postEffectsarray withaddPostEffect()/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
ShaderEffectto any camera'sshaderproperty for full-screen post-effects. Multi-camera independent (e.g. main + minimap with different effects). - Camera effects system — extensible
CameraEffectbase class with lifecycle. ExtractedShakeEffect, unifiedFadeEffect(in/out direction), and newMaskEffectfor shape-based level transitions (Ellipse / Polygon shrink/reveal). Camera2d.colorMatrix— built-inColorMatrixfor color grading (brightness / contrast / saturate / hueRotate / sepia / invertColors). Always applied as the final post-pass; zero overhead when identity.ColorMatrixclass +ColorMatrixEffect— chainable color adjustments.SepiaEffect,InvertEffect,DesaturateEffectnow share a single GLSL shader via the matrix.VignetteEffect— built-in shader effect to darken screen edges with configurable strength and size.RenderTargetabstract base (designed for future WebGPU support) with concreteWebGLRenderTarget(FBO) andCanvasRenderTarget(canvas) implementations. NewRenderTargetPoolreplaces the WebGL-specific FBO pool.ParticleEmitter.autoDestroyOnComplete(defaultfalse) — emitter removes itself from its parent once all particles have died. Solves the leak in fire-and-forgetburstParticles()use cases. CompaniononCompletecallback fires on completion.ParticleEmitter.accurateBounds(defaultfalse) — opt-in per-frame bounds refresh for debug visualization or collision. Default off saves significant matrix work at high particle counts.ParticleEmitterSettingsis now an exported TypeScript interface — constructor andreset()acceptPartial<ParticleEmitterSettings>for compile-time validation.Text.visibleCharacters/visibleRatio— progressive text reveal / typewriter effects onTextandBitmapText. AnimatevisibleRatiowith a Tween for character-by-character display.Tween.repeatDelay(ms)— adds a delay before each repeat cycle.- Renderer-agnostic state methods —
setViewport(),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; newcolorsetting replaces legacyfadeproperty (backward compatible).Matrix3d.transform()— accepts either 16 values (full 4x4) or 6 values (2D affine, promoted to 4x4). Mirrors theMatrix2d.transform()API.
Changed
Renderable.shaderis now a backward-compatible getter/setter forpostEffects[0](deprecated in favour ofaddPostEffect()/clearPostEffects()).Camera.shake() / fadeIn() / fadeOut()are now convenience wrappers that createShakeEffect/FadeEffectinstances — same signatures, fully backward compatible. Multiple shakes can coexist.Triggerinternally usesFadeEffect/MaskEffectinstead ofviewport.fadeIn()/viewport.fadeOut().ParticleEmitter.reset()now clamps reversed range pairs (minLife > maxLife,min/maxStartScale,min/maxEndScale,min/maxRotation) by loweringmintomax. Catches the common footgun of overriding only one half of a range.Particlehot-path performance — closed-form transform construction folded into a singlesetTransform()call,_halfW/_halfHcached on reset,_deltaInvcached on the emitter, frame-skip bookkeeping gated behindframesToSkip > 0. ~240k matrix ops/sec saved at 1000 particles, 60fps.
Bug Fixes
- WebGL1 stencil masking (
setMask/MaskEffect) now works correctly inpreferWebGL1: truemode.WebGLRenderTargetwas relying ongl.DEPTH_STENCIL/gl.DEPTH_STENCIL_ATTACHMENTbeing exposed on the WebGL1 context, which some browser/driver combinations leaveundefined. Now uses spec-defined numeric fallbacks (0x84F9 / 0x821A) and validates completeness viagl.checkFramebufferStatus()with a depth-only fallback path. ImageLayer.mask,shader/postEffects,flipX()/flipY()now apply correctly.ImageLayer.preDraw()was a stripped-down copy ofRenderable.preDraw()that handled only alpha / tint / blend mode. Coordinate-sensitive setup (flip, stencil mask) is now applied indraw()after the per-camera zoom transforms, so it stays correctly aligned at anyviewport.zoomand 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()orstate.stop()mid-freeze cancels the timer and resolves the freeze promise immediately - Window
BLURcancels the freeze (the visual "moment" is over by the time the user returns; regularpauseOnBlurstill keeps the game paused while away)
ParticleEmitterconstructor was using bitwise|instead of logical||for thewidth/heightfallback, silently rounding any provided value to the next odd number (e.g.width: 16 → 17,width: 32 → 33).Particlehitbox 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 usesevenoddclipping for proper inverted mask support (was usingdestination-atopcomposite which didn't clip subsequent draws). - Ellipse
clone()now uses the ellipse pool — consistent withPolygon.clone(). - WebGL
WebGLRenderTargetconstructor andresize()now explicitly useTEXTURE0to 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