melonJS

melonjsMIT活跃维护 有专家点评

面向 JavaScript/TypeScript 的现代 HTML5 游戏引擎,支持 2D/3D、WebGL/WebGPU 渲染,内置物理、Tiled 地图、glTF 与 WebAudio,省去自己搭底层。

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.

20.13.0发布于 2026-11-06 10:24 UTC6,498star +58 / 7 天676fork同步于 2026-11-11 05:32 UTC

专家点评

上手难度:进阶更新于 2026-11-11

一个 API 仿 Canvas2D 的 HTML5 引擎,用一套代码同时覆盖 WebGPU、WebGL2 和 Canvas 三条渲染路径

适用场景

  • 2D 小游戏或原型:渲染接口就是 save/translate/fillRect 那套,从 Canvas 手写代码迁过来几乎不用重学,换 Phaser 得重新适应 Scene/GameObject 体系
  • 需要同时出 2D 和 3D 场景的项目:Tiled 地图和 glTF/GLB 走同一个 level.load(),不用为了一个 3D 关卡再引入 three.js 并自己接物理
  • 目标设备跨度大的发布:AUTO 模式在 WebGPU 不可用时降级到 WebGL2,再不行退到 Canvas,老设备至少能跑起来而不是白屏
  • 不想管音频素材的 jam 项目:内置 WebAudio 空间音频和程序化音效,省掉采样资源这一环

踩坑

  • 只支持 WebGL1 的设备:20.0 起 WebGL1 路径已移除,这类设备在 AUTO 下会掉到 Canvas 渲染,2D 还能看,3D 场景基本没法用,发布前得确认目标机型分布
  • 模块化/工程化接入:issue 里 ES6 class 定义与 module 支持、npm 依赖管理这两类被反复提出且讨论量大,说明把它塞进现代打包流程不是开箱即用的事,动手前先读构建相关文档
  • Tiled 工作流:Infinite Map 支持是仍在被提的 feature request,如果你的关卡设计依赖无限地图,得先确认当前版本行为再决定是否换关卡格式

同类对比

2D 且要成熟生态和大量教程时选 Phaser;3D 为主、需要完整 PBR 与编辑器时选 three.js 或 Babylon.js,melonJS 的 3D 是够用而非深入

怎么上手

由 README 提炼,执行前请确认
npm install melonjs
硬件要求按 README 说明

README 未说明具体显存或 GPU 型号要求;引擎运行在支持 WebGPU、WebGL 2 或 Canvas2D 的浏览器上,WebGL 1 设备在 AUTO 模式下回退到 Canvas 渲染器。

下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

面向独立开发者的开源 HTML5 2D/3D 游戏引擎,一次编写即可在 WebGPU、WebGL 2 或 Canvas 上运行

面向 JavaScript/TypeScript 的现代 HTML5 游戏引擎,支持 2D/3D、WebGL/WebGPU 渲染,内置物理、Tiled 地图、glTF 与 WebAudio,省去自己搭底层。

核心能力

  • 渲染 API 仿 Canvas2D,提供 save、translate、fillRect 等熟悉接口
  • AUTO 模式启动时优先使用 WebGPU,不可用时回退到 WebGL 2 或 Canvas
  • 用 level.load(name) 一行加载 Tiled 2D 地图或 glTF/GLB 3D 场景
  • 内置 SAT 多边形物理,2D 用 QuadTree、3D 用 Octree 做宽相检测
  • 内置 WebAudio 3D 空间音频与程序化音效,无需采样素材

容易踩的坑

自 20.0 起 WebGL 1 路径已移除,仅支持 WebGL 1 的设备会回退到 Canvas 渲染;音频后端为内置定制版 howler.js 衍生代码,不是运行时依赖,无需另行安装;README 未说明默认端口等其他配置项。

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本20.13.0
  1. 20.13.0v20.13.0最新正式版2026-11-06 · 2026-11-06 10:24 UTC

    Added

    • Particles: a depth setting, so particles under a Camera3d spawn through a volume instead of on a flat sheet
    • Text: paintOrder, to draw the outline behind the glyphs ("stroke", the default) or over them ("fill")
    • Text: lineJoin and miterLimit, the shape of the outline's corners ("round" by default, "bevel" or "miter")
    • UI: UICheckbox, a checkbox with its label, that becomes a radio button with a group (#1722)
    • UI: UISlider, a horizontal or vertical slider with min, max and step, moved by dragging, clicking the track or the mouse wheel
    • UI: UIPanel lays out its children ("column", "row" or "grid"), scrolls them, and takes a nine-slice skin, a title and draggable
    • UI: UITextButton takes onClick, a skin and pressedColor, and the size, font and color settings the other widgets use; label is its text object
    • UI: every UIBaseElement has enabled, cancelPress() / onCancel(), and a hover and press bounce (hoverScale, pressScale)
    • UI: keyboard and gamepad navigation between widgets, once one takes the focus with focus()
    • UI: drop shadows on UIPanel and ProgressBar (shadowColor, shadowOffsetX, shadowOffsetY, shadowBlur)
    • UI: UISpriteElement is a UIBaseElement holding a Sprite, so it has everything the other widgets have; Sprite members other than its region and animation methods are on element.sprite
    • UI: the widgets' settings and skin types are exported, ProgressBar's onChange also gets the bar, and Container#clipContains(x, y) tells whether a container shows its children at a point

    Deprecated

    • UI: UITextButton#bitmapText, for label

    Fixed

    • Rendering: a translucent setColor() no longer fades what is drawn after it, nor changes getGlobalAlpha()
    • Rendering: on WebGL and WebGPU, a clip inside a clip is their overlap, as on Canvas (#1816)
    • WebGL: fillArc() handles an end angle before the start, and save() / restore() keep lineWidth and lineJoin, as on Canvas
    • Camera: post effects on a camera no longer wipe out the cameras drawn before it; a minimap with effects shows the view behind where it draws nothing
    • Camera: worldToLocal() / localToWorld() are right on a minimap or zoomed camera when the level is centred
    • Camera: fadeIn() and fadeOut() always call onComplete (#1810)
    • Container: reset(), and so level.load, keeps the pending sort of the persistent children it keeps
    • Container: onDeactivateEvent is called once per child of a removed container, not twice or more
    • Container: enableChildBoundsUpdate follows moving children, so the camera no longer culls the group
    • Container: physics bodies of nested children are added and removed at any depth; moving a group with bodies to another container no longer throws
    • World: a persistent container's children keep their physics bodies through a state change or level.load
    • Sprite: redefining the playing animation no longer crashes the next update when it is shorter
    • Sprite: a flicker() callback gets the sprite as this, after the flicker has ended
    • Particles: particles follow their emitter's visibilityLayer
    • Particles: an emitter without an image no longer leaks a texture per emitter or reset(); all share the renderer's white pixel (#1807)
    • Text: an outline no longer hides thin letters or gets cut off at the edges. Its corners are round by default and only its outer half shows: double lineWidth to keep its weight, or use paintOrder: "fill" and lineJoin: "miter" for the old look
    • Text: word wrap keeps \n line breaks, and no longer adds a blank first line for a long first word (Text and BitmapText)
    • Text: multi-line text is placed by textBaseline as one block, as BitmapText is, so it stays inside its bounds
  2. 20.12.0v20.12.02026-10-30 · 2026-10-30 03:00 UTC
    查看更新说明

    Added

    • State: a "pixelate" transition, state.transition("pixelate", color, duration, size): the screen breaks into growing blocks and comes back sharp. Skipped on Canvas

    Fixed

    • Rendering: with subPixel off, each draw snaps to whole pixels once, where it lands, the same on Canvas, WebGL and WebGPU (#1765). Something at a fractional position can draw one pixel over
    • Camera: with subPixel off, worldView, localToWorld and worldToLocal use the view position rounded to a whole pixel, where the world is drawn from
    • Geometry: the methods taking a point (translate, shift, contains) take any object with x and y, such as a renderable's pos, instead of returning NaN
    • Physics: a body with several shapes has the union of its shapes as its bounds; each shape added shifted them
    • Physics: Body#setVertices on one of several shapes keeps the body's bounds and pseudoInertia right (set it again if you set it by hand), and throws a RangeError past the last shape
    • Physics: a body that drops its last Box3d or Sphere no longer resolves along z
    • Loader: the default loading screen shows its progress bar and logo in the same frame
    • ImageLayer: a repeating layer keeps covering the screen however far the camera moves, instead of sliding off
    • Animation: a one-frame animation played once completes, so onComplete fires and next is followed
    • Audio: audio.setListener(app.viewport) hears from the center of the camera's view, not its top-left corner
    • Input: input.bindPointer keeps its bindings once the mouse enters the canvas
    • Audio: a clip with preload: false is fetched and streamed when first played; it never played (#1784)
    • State: the first frame of a new stage or level shows its world, not the background alone
    • State: a state.change() asked for during a transition is made by that transition, instead of leaving the screen black (#1787)
    • Effects: the built-in effects that place a pattern (sway, wave, vignette, gradient, scanline, shine) place it on the sprite, also cut from an atlas or with other effects after it (#1407)
    • Effects: a renderable drawn through two or more effects keeps its opacity on WebGL and WebGPU (#1791)
    • Effects: through two or more effects, widths, offsets and sizes are in the renderable's own pixels at any scale or zoom, as with one effect. Check widths tuned on a scaled renderable
    • Effects: a renderable drawn through two or more effects stays inside its clip, such as a minimap camera's view, instead of spilling over the canvas
    • Effects: on WebGPU, effects read their capture at the game's texture filter, as on WebGL, so pixel-art games stay crisp
    • Input: a gamepad unplugged while a button or the stick is held lets go of the keys bound to them, instead of leaving them pressed
    • Input: a stick with only one side bound lets go of its key when it returns to the centre or rests just past it, instead of holding it until pushed that way again
    • Lighting: a Light2d's glow and the darkness around it compile when the light is added to the world, not inside the first frame that draws it
    • Typings: TextureAtlas#createAnimationFromName declares both of its arguments optional, as they are at runtime, and is documented again

    Full Changelog: https://github.com/melonjs/melonJS/compare/20.11.0...20.12.0

  3. 20.11.0v20.11.02026-10-27 · 2026-10-27 10:13 UTC
    查看更新说明

    Added

    • Effects: colors take an alpha. Every color option and setColor takes [r, g, b] or [r, g, b, a], the alpha being the color's opacity ([r, g, b] stays opaque), RadialGradientEffect honours the alpha of its Color, and DropShadowEffect gains the setColor the others have. Four values used to break an effect (WebGL rejected them, and on WebGPU the fourth overwrote the next setting, such as an outline's width); a color of any other length now throws a TypeError saying so
    • Effects: SwayEffect leans a sprite or a layer from side to side, as if in a breeze, its top swaying most and everything from its anchor row down staying put. It is a WaveEffect, which now takes an anchor for the row its wave fades out at, and it wraps its own time so it never stutters on a phone's medium-precision floats
    • Rendering: Renderable#sortOffset lines a renderable up as if it stood that many pixels lower (or higher) when its container sorts on "y" or "x", without moving it: a torch drawn over the wall it hangs on, dust sorted with the door it rises from, or art of different heights sorted by its base
    • Lighting: Light2d#softness (0 to 1) fades the edge of a light's hole in the stage's ambient darkness, from a hard rim (0, the default, as before) to a darkness that thins straight from the center (1), along the same falloff as the glow. Hard and soft lights mix in one scene, overlapping lights multiply, and it works on every renderer
    • Particles: tintOverLife gives the tints a particle takes over its life, evenly spaced and blended from the first at birth to the last at the end, such as a flame turning from white hot to deep red. It sets the color only (the fade still sets the opacity), and the blend is taken in 32 steps, which keeps the Canvas renderer to 32 tinted copies of the texture
    • Animation: setCurrentAnimation(name, { onFrame }) calls back with each frame index as playback reaches it, from frame 0 when the animation starts, so a footstep or a hit can land on its frame. It applies to the frame animations of a Sprite or a Sprite3d
    • Audio: playTrack(name, { volume, sprite }) plays one region of a clip as the track and loops on it. A region of a loop's exact length keeps an MP3 loop gapless in Safari, which plays the padding an MP3 encoder adds to the end of the file
    • Tiled: a tile object with no class of its own is built by the class registered under its tile's class, as Tiled shows it, so a class set once on a tile in the tileset applies to every object placed from it, and TMXTileset#getTileClass() returns that class. The object's own class or registered name still comes first, and a tile classed like a built-in (Sprite, Trigger, shape...) stays a plain tile
    • Tiled: TMXObject#resolvedProperty() and resolvedProperties() return an object's custom properties together with those it inherits from its tile, the object's own winning, as the methods of the same names in Tiled's scripting API do. Only the object's own properties are set on it by name, as before
    • Tiled: a tileset, a tile of an image collection or an image layer whose image has a transparent color (trans in TMX, transparentcolor in JSON) is drawn with that color transparent, as Tiled shows it. The color is cleared once when the map loads, on a copy of the image
    • Typings: TMXObject, the settings a class registered with registerTiledObjectClass (or a factory registered with registerTiledObjectFactory) receives, is exported as a type, and both functions are typed with it. A class or factory typed with its own settings still compiles
    • Rendering: textureFilter: "linear-mipmap" samples a texture's mipmaps wherever it is drawn smaller than its size, so a zoomed-out camera, a minimap or a scaled-down sprite no longer shimmers as it moves; it covers sprites, text and tile layers on WebGL and WebGPU. A sprite cut from an atlas or a tileset keeps its samples inside its own frame, so its neighbours no longer streak along i
  4. 20.10.1v20.10.12026-10-21 · 2026-10-21 09:53 UTC
    查看更新说明

    Fixed

    • Rendering: entering a state no longer stalls its first frame compiling the shaders its stage had only started preparing. That frame now waits until they are ready, for at most 1.5s, and STATE_CHANGE and a transition's reveal come with it, so the reveal plays in full instead of running its course behind the stall
    • Rendering: the first frame of a scene whose camera uses fog no longer stalls compiling its meshes. The warm-up read the fog of whichever camera drew last, which after a state change is the previous screen's, so it prepared the variant without fog and the first frame then built the fogged one on the spot
    • Rendering: a camera's colorMatrix, and on WebGPU an InstancedMesh and its ground shadow, are now prepared when the stage is built, like every other renderable since 20.10, instead of compiling in the first frame that draws them
    • WebGL: an ImageLayer with a single post effect now draws through it. The layer's repeated image was drawn with the default shader, so the effect did nothing on WebGL while WebGPU applied it

    Full Changelog: https://github.com/melonjs/melonJS/compare/20.10.0...20.10.1

  5. 20.10.0v20.10.02026-10-20 · 2026-10-20 01:27 UTC
    查看更新说明

    Highlights: a game no longer stutters the first time an effect, a blend mode or a new kind of object appears. Shaders, pipelines and render targets are now prepared when the object is added, or during loader.preload(), rather than in the frame that first draws it, where a single first draw was measured at up to 140ms. Dropping a batch of meshes no longer stalls the frame either.

    Added

    • Effects: SquishEffect bulges a sprite's middle out, or pinches it in, while its top and bottom rows stay where they are. Paired with a change of height it gives squash and stretch that keeps the sprite's volume, and it draws past the sprite's own frame, so the art needs no transparent margin

    Fixed

    • WebGL: releasing retained geometry no longer stalls the frame, a stutter whenever a scene dropped a batch of meshes. Teardown asked a blocking is* query about every buffer and vertex array before deleting it, a round trip per object, and now only asks once the context has been lost, the only case where the answer can be no
    • WebGL: a ShaderEffect hosted on a Mesh is compiled during loader.preload(), on every call including a later one that brings a level's own effects, rather than on the frame it first draws. Preloading the shader built its standalone program, but a mesh host splices the body into the mesh shader, which is a different program again, so a game that declared every effect in its manifest still stuttered the first time each one appeared
    • WebGPU: a post effect's pipelines are compiled when the effect is attached (addPostEffect, assigning shader, or the tone curve setToneMapping builds), off the frame, rather than in the frame that first draws it, a stutter measured at up to 140ms per effect on desktop. Attaching effects when a pool or a stage is built, rather than when the object is shown, gives the compile time to finish
    • WebGL: a ShaderEffect hosted on a Mesh is also linked when it is attached, so an effect built inline and never preloaded no longer stalls its first draw either. The links are spread over the following frames, so a stage building a pool of effect-carrying meshes does not pay for all of them in one
    • Effects: switching a disabled effect on no longer creates a render target in that frame. A chain gets its targets for every effect attached to it, enabled or not, when the effect is attached
    • Rendering: adding a renderable to the world starts preparing its draw, so one added before it is first shown no longer pays for it on that frame. On WebGPU that is the pipeline for its blend mode, culling and transparency, compiled off the frame, and on both GPU backends an advanced blend mode (overlay, difference and the rest) gets its blend shader and offscreen target, a first draw measured at up to 136ms
    • WebGL and WebGPU: the shader warm-up runs again after a lost context or device is restored. It never did, so every shader went back to compiling on the frame it next drew
    • WebGPU: the mip-chain generator is built during loader.preload() when textures are filtered (textureFilter resolving to "linear"), instead of on the frame the first mipmapped texture is uploaded
    • Sprite: a video the browser refuses to start, as it does before the user has interacted with the page, no longer logs an uncaught error on every frame. The refusal is handled once, and playback starts on the next click, touch or key press
    • WebGL: ETC1 compressed textures no longer draw black. They were uploaded with a call ETC1 does not accept, which left the texture empty; they now upload as ETC2, which reads the same data, or level by level when the browser only supports ETC1
    • WebGPU: the smallest mip levels of a compressed texture (the 2×2 and 1×1 levels of a 4×4-block format) are no longer rejected and left empty. Each upload now covers whole blocks, as WebGPU requires
    • Tween: a tween stopped while the game updates (replaced by a new one, say) no longer takes one more step and fires its onComplete in that same f

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    melonJS 2

    melonJS: fast & light 2D & 3D games for the web, running on WebGPU, WebGL 2 or Canvas

    Build Status NPM Package NPM Downloads Build Size jsDelivr License: MIT Discord Contributor Covenant

    A modern & fully featured HTML5 game engine

    melonJS is an open-source 2D & 3D game engine designed for indie developers — perspective and orthogonal cameras, GPU-accelerated tilemap rendering, post-processing effects, custom shaders, 3D mesh support, polygon-accurate physics, modern Tiled workflows, and high performance. Runs on WebGPU, WebGL 2 or Canvas2D with automatic fallback. The whole engine is ~250 KB minzipped of vanilla JS/TS, with no dependencies and no toolchain lock-in. Built with modern class syntax and bundled with esbuild.

    melonJS is licensed under the MIT License and actively maintained by the team at AltByte in Singapore.

    Why melonJS

    melonJS is designed so you can focus on making games, not on graphics plumbing.

    • Canvas2D-inspired rendering API — If you've used the HTML5 Canvas, you already know melonJS. The rendering API (save, restore, translate, rotate, setColor, fillRect, ...) follows the same familiar patterns — no render graphs, no shader pipelines, no instruction sets to learn.

    • True renderer abstraction — Write your game once, run it on WebGPU, WebGL 2 or Canvas2D with zero code changes. The engine handles all GPU complexity behind a unified API: the default AUTO mode tries WebGPU first at startup, falls back to WebGL 2 if that is unavailable, and ultimately to Canvas, and the entire feature set renders identically on both GPU backends.

    • Complete engine, minimal footprint — Physics, tilemaps, audio, input, cameras, tweens, particles, UI — a full game stack in a single tree-shakeable ES module. No dependency sprawl, no library stitching.

    • Scenes, loaded in one call — level.load(name) brings an authored scene straight into your world. Tiled is a first-class citizen for 2D — orthogonal, isometric, hexagonal & staggered maps, animated tilesets, collision shapes, object properties, compressed formats, with GPU-accelerated tile rendering on the GPU backends — and glTF / GLB is the equivalent for 3D scenes: author in Blender (or any DCC tool), export a .glb, and the whole scene — meshes, materials, cameras, lights, and node animation — loads under a Camera3d, no per-mesh wiring. Animated models play back through the same animation API as a 2D Sprite.

    • Batteries included, hackable by design — Get started in minutes with minimal setup. When you need to go deeper: modern class-based architecture, a plugin system for engine extensions, and a clean architecture that's easy to extend without fighting the framework.

    About melonJS

    melonJS is a fully featured game engine :

    Compatibility

    • Standalone library (does not rely on anything else, except a HTML5 capable browser)
    • Compatible with all major browsers (Chrome, Safari, Firefox, Opera, Edge) and mobile devices

    Graphics

    • Fast GPU renderers (WebGPU and WebGL 2) for desktop and mobile devices, with fallback to Canvas rendering
    • Since 20.0 the aging WebGL 1 path is retired and WebGL 2 is the baseline; devices offering only WebGL 1 fall back to the Canvas renderer under AUTO
    • Extensible batcher system for custom rendering pipelines, with backend-neutral vertex formats and draw topologies (declare a layout once, describe it to either GPU backend)
    • High DPI resolution & Canvas advanced auto scaling
    • Sprite with 9-slice scaling option and frame animation
    • Built-in effects such as tinting, masking, and the full set of CSS-style blend modes (normal, none, additive, multiply, screen, exclusion, darken, lighten, overlay, hard-light, color-dodge, color-burn, soft-light, difference) — all of them supported identically on WebGPU, WebGL 2 and Canvas since 20.2
    • Standard spritesheet, single and multiple Packed Textures support
    • Compressed texture support (DDS, KTX, KTX2, PVR, PKM) with automatic format detection and fallback
    • Hardware antialiasing (antiAlias: true) on both GPU backends — and it survives post-processing, since the offscreen targets a post-effect chain renders into are multisampled to match
    • Procedural noise textures: Noise (simplex/perlin/value/cellular, fBm / ridged / ping-pong fractal, domain warp; renderer-free and CPU-samplable for heightmaps, terrain, and spawn jitter) and NoiseTexture2d — bake a noise field into a sprite image, a Gradient color ramp, or a live-animated tangent-space normal map for lit water and surfaces; unified under a new Texture2d base alongside TextureAtlas
    • 3D mesh rendering with OBJ/MTL model loading, multi-material support, hardware depth testing, and perspective projection via Camera3d — retained-mode geometry, uploaded to the GPU once and re-drawn from there, so moving, rotating, scaling or re-tinting a mesh costs no vertex upload and no per-vertex CPU work at all
    • Mipmapped and anisotropically-filtered mesh textures on both GPU backends, so distant and grazing-angle geometry stops shimmering (opt out per mesh with textureFilter: "nearest" for crisp pixel-art models)
    • Lighting, in 2D and 3D:
      • 2D — Light2d as a first-class Renderable (multiple dynamic lights, radial-gradient falloff, illumination-only mode, procedural rendering via drawLight), plus optional per-pixel normal-map shading on sprites for 3D-looking dynamic lights
      • 3D — Light3d directional, point, spot and ambient lights, added to the world like Light2d (half-Lambert diffuse + ambient fill, quadratic falloff and cone angles on the punctual types, runtime-manipulable for day/night), auto-loaded from a glTF scene's authored suns and lamps
      • up to 32 simultaneous lights on either path, with light data travelling in a uniform buffer — a static light rig costs zero GPU state changes per frame
    • Ground ("blob") shadows for 3D objects — on by default — so characters and props read as standing on the floor instead of hovering. An ellipse matching the caster's own footprint and rotation, shrinking and fading with height above the ground; one extra draw per object, and one for an entire InstancedMesh scatter regardless of instance count. Shaped by the light rather than always straight down: shadowLight points a blob at a Light3d and is re-read every draw, so a day/night cycle carries every shadow with it, while shadowOffset slides it out from the caster's feet, shadowStretch lengthens it for a low sun, shadowScale sizes it independently of the object, and shadowGroundNormal lays it on a floor that is not level. All of them work on an InstancedMesh too, as one value for the whole set. Controllable per object, per glTF scene (level.load(name, { castGroundShadow, shadowLight, … })) or application-wide. Deliberately not shadow mapping: it answers "where is this standing", which is what a 2.5D scene needs
    • Built-in shader effects (Flash, Outline, Glow, Bloom, ToneMapping, Dissolve, CRT, Hologram, etc.) with multi-pass chaining via addPostEffect(), plus custom shader support on both GPU backends: ShaderEffect for per-sprite fragment effects (GLSL and/or WGSL bodies) and complete custom mesh shader programs via mesh.shader (a dual-language GLShader: GLSL pair and/or WGSL module)
    • Optional HDR rendering (hdr: true) — the camera's render targets become half-float, so additive light stops saturating on every write and BloomEffect thresholds on genuinely over-bright pixels instead of merely bright ones, with ToneMappingEffect and a toneMapping setting to compress the result back into display range when your art calls for it. Off by default and additive: nothing is inserted into your effect chain, so turning it on does not restyle a game whose look is built on clipped whites. On WebGPU it goes one step further — hdrOutput: true presents the frame in the display's own dynamic range rather than clamping it to SDR at the last step
    • Trail renderable for fading, tapering ribbons behind moving objects (speed lines, sword slashes, magic trails)
    • System & Bitmap Text with built-in typewriter effect
    • Video sprite playback

    Sound

    • Web Audio support with 3D spatial audio and stereo panning, plus a procedural tone/noise API. The playback backend began as howler.js and is now a customized derivative vendored into the engine, so this is not a runtime dependency (see src/audio/backend/LICENSE)
    • Built-in procedural audio primitives (envelope-shaped oscillators, white/pink/brown noise) for SFX without sample assets
    • Direct AudioContext / master-gain accessors for custom WebAudio graphs that mix with the engine's master volume / mute

    Physics

    • Polygon (SAT) based collision algorithm for accurate detection and response
    • Fast broad-phase collision detection using spatial partitioning (QuadTree in 2D, Octree in 3D, swapped automatically)
    • Raycast, AABB and sphere region queries with precise entry geometry, including 3D raycasts (raycast3d)
    • Collision lifecycle hooks on every Renderable
    • Collision filtering for optimized automatic collision detection
    • Multiple shapes per body for complex hitboxes
    • Pluggable PhysicsAdapter interface for custom physics via official adapters

    Input

    • Mouse and Touch device support (with mouse emulation)
    • Gamepad support with button and axes binding
    • Keyboard event handling with key binding system
    • Device motion & accelerometer support

    Camera

    • Multi-camera support (split-screen, minimaps, multiple viewports)
    • Optional perspective camera (Camera3d) with frustum culling for 2.5D / 3D-projected scenes — drop-in subclass of the default 2D camera
    • Camera follow with configurable deadzone and frame-rate-independent damping
    • Built-in shake, fade, flash, and mask-based transition effects
    • Per-camera post-processing pipeline with stackable shader effects and color grading (ColorMatrix)

    UI

    • UIBaseElement / UISpriteElement containers for clickable, hoverable and holdable elements with full pointer-event wiring
    • Draggable / DropTarget for drag-and-drop with configurable overlap or contains-check
    • UITextButton text button with hover, press, and key-bind support — built on BitmapText

    Scenes

    • Load a scene in one call with level.load(name) — 2D Tiled maps and 3D glTF scenes alike, auto-registered on preload
    • Tiled map format up to 1.12 built-in support for easy level design
      • GPU-accelerated tile rendering for orthogonal maps on the GPU backends (WebGL 2 and WebGPU) — each layer draws as a single quad with no per-tile loop, ~5–8× faster than the legacy CPU renderer on dense maps. Honors animated tiles, flip bits, per-layer opacity/tint/blend, and oversized bottom-aligned tiles; falls back transparently to the CPU renderer on isometric/staggered/hexagonal layers or under the Canvas renderer
      • Uncompressed and compressed Plain, Base64, CSV and JSON encoded XML tilemap loading
      • Orthogonal, Isometric, Hexagonal (both normal and staggered) and Oblique maps
      • Multiple layers with per-layer alpha, tinting and blend modes (multiple background/foreground, collision and Image layers)
      • Parallax scrolling via Image layers, with parallax origin support
      • Animated and multiple Tileset support, tile sub-rectangles, embedded base64 images
      • Native .aseprite / .ase tileset images (Tiled 1.11+ qaseprite plugin workflow), with frame tags auto-mapped to per-tile animations — no PNG export step required
      • Tileset transparency settings
      • Rectangle, Ellipse, Polygon, Polyline and Capsule (round-rect) object shapes
      • Tiled Objects with custom properties (string, number, boolean, color, file, object, list/array and class-typed)
      • Per-object opacity and visibility
      • Concave collision polygons auto-decomposed via earcut triangulation
      • Flipped & rotated Tiles
      • Dynamic Layer and Object/Group ordering
      • Dynamic Entity loading via an extensible object factory registry — register custom handlers for any Tiled class name without modifying engine code
      • Shape based Tile collision support
    • glTF / GLB 3D scenes — load an authored 3D scene with level.load(...), the same one call as a Tiled map
      • The whole scene loads at once — meshes, materials, cameras and lights — viewed under a Camera3d
      • Automatically lit by the scene's authored lights — the sun plus any point/spot lamps set up in the authoring tool, each keeping its authored name so getChildByName("Sun") finds it for runtime tuning
      • Textured, solid-colored, and vertex-colored materials
      • Node animation — walk/idle/sprint characters, spinning pickups, doors, lifts — played through the same setCurrentAnimation / play / pause / stop API as a 2D Sprite
      • .glb and .gltf files, with embedded or external buffers & textures
      • Works with any glTF authoring tool (Blender, Maya, 3ds Max, Cinema 4D, …)

    Assets

    • Asynchronous asset loading with progress tracking
    • A fully customizable preloader
    • Support for images, JSON, TMX/TSX, glTF / GLB 3D scenes, .aseprite / .ase binary, audio, video, binary and fonts

    Core

    • Application class as the modern entry point — construct it, then await app.init() (asynchronous since 20.0, so the WebGPU device can be acquired) — with built-in pause, resume, and freeze() (hit-stop) primitives
    • A state manager (to easily manage loading, menu, options, in-game state)
    • Tween effects with multiple easing functions (Quadratic, Cubic, Elastic, Bounce, etc.) and Bezier/Catmull-Rom interpolation
    • Transition effects
    • Pooling support for object recycling
    • Particle system with ParticleEmitter (emission rate, lifetime, velocity, gravity, blend modes), and a reference space so particles can be measured from the emitter, from the world, or from any container — a moving emitter leaves a trail instead of dragging its cloud along, and a Particle Editor to tune effects live and copy the code
    • EventEmitter based event system
    • Persistent data storage (save/load via localStorage)
    • Plugin system for extending engine capabilities

    Tools integration

    melonJS is supporting the below tools and frameworks natively or through our official plugin(s) :

    Free Texture Packer TexturePacker SpriteIlluminator PhysicsEditor ShoeBox Tiled Cordova Capacitor Spine aseprite

    Tools integration and usage with melonJS is documented in our Wiki.

    Getting Started

    The fastest way to create a new game:

    npm create melonjs my-game
    cd my-game
    npm install
    npm run dev
    

    This scaffolds a ready-to-run project with TypeScript, Vite, and the debug plugin. It also works with plain JavaScript — just rename .ts files to .js.

    You can also start from the boilerplate directly, or follow the step-by-step Platformer Tutorial.

    For more details, check the wiki Details & Usage guide.

    Examples

    Browse all examples here


    Basic Hello World Example

    import { Application, Text } from "https://cdn.jsdelivr.net/npm/melonjs/+esm";
    
    // create a new melonJS application
    const app = new Application(1218, 562, {
        parent: "screen",
        scale: "auto",
        backgroundColor: "#202020",
    });
    
    // initialize it (builds the renderer and appends the canvas)
    await app.init();
    
    // set a gray background color
    app.world.backgroundColor.parseCSS("#202020");
    
    // add a font text display object
    app.world.addChild(new Text(609, 281, {
        font: "Arial",
        size: 160,
        fillStyle: "#FFFFFF",
        textBaseline: "middle",
        textAlign: "center",
        text: "Hello World !",
    }));
    

    Simple hello world using melonJS

    Note: since version 20.0, await app.init() is required after constructing the Application. The WebGPU backend, which AUTO tries first on browsers that support it, acquires its GPU device asynchronously, so initialization had to become an async step; it resolves without suspending on the WebGL and Canvas backends. On 19.x the call is optional and this example works without it.

    Documentation

    Plugins

    melonJS provides a plugin system allowing to extend the engine capabilities.

    Here is the list of official plugins maintained by the melonJS team:

    • debug-plugin - a debug panel for inspecting game objects
    • tiled-inflate-plugin - enable loading and parsing of zlib, gzip and zstd compressed Tiled maps
    • spine-plugin - Spine runtime integration to render Spine skeletal animations, with a dedicated batcher on each renderer (WebGPU, WebGL and Canvas)
    • gamepad-plugin - on-screen touch controls (sticks and buttons) reported as a gamepad, so the same bindings cover a real pad and a touch screen
    • capacitor-plugin - bridges Capacitor's native lifecycle (pause/resume, hardware back-button, orientation lock, splash) for melonJS games wrapped as iOS / Android apps

    If you wish to develop your own plugin, we also provide a plugin template to help you get started.

    Physics Adapters

    Since 19.5, melonJS exposes a PhysicsAdapter interface so the same game code can run on either the built-in SAT physics (default) or a third-party rigid-body engine, selected via the physic option on Application. Two official adapter packages, maintained by the melonJS team:

    See the Migrating to the Physics Adapter API, Switching Physics Adapters, and BuiltinAdapter Quirks wiki pages for migration guides and the per-adapter behaviour table.

    Installation

    melonJS is distributed as a tree-shakeable ES module with TypeScript declarations included. The published bundle targets ES2022 — transpile it if you need to support older browsers.

    Install via npm :

    npm install melonjs
    

    Then import what you need in your project :

    import { Application, Sprite, loader } from 'melonjs';
    

    Or use it directly via jsDelivr CDN :

    <!-- load the ES module bundle of melonJS v20.x -->
    <script type="module" src="https://cdn.jsdelivr.net/npm/melonjs@20/+esm"></script>
    <!-- omit the version completely to get the latest one -->
    <!-- you should NOT use this in production -->
    <script type="module" src="https://cdn.jsdelivr.net/npm/melonjs/+esm"></script>
    

    Note: the debug plugin is available separately as @melonjs/debug-plugin

    Supporting older browsers

    The published bundle targets ES2022, so it uses private class members and other modern syntax. A browser that predates those cannot parse the file at all — this fails at load, not at the point a feature is used.

    To support older browsers, transpile melonJS together with your own code. The usual trap is that build setups skip node_modules by default, which leaves melonJS untouched no matter how low you set your target.

    With Vite :

    // vite.config.js
    export default {
        build: {
            // esbuild downlevels dependencies too, melonjs included
            target: "es2020",
        },
    };
    

    With Babel, make sure melonJS is not excluded :

    // webpack.config.js
    {
        test: /\.js$/,
        // the default `exclude: /node_modules/` would skip melonjs
        exclude: /node_modules\/(?!melonjs)/,
        use: "babel-loader",
    }
    

    Transpiling costs some size and speed: private class members become WeakMap lookups, which are on hot paths in the renderer. Only reach for it if you have users on browsers that need it.

    Building with AI agents

    melonJS ships skills — guidance files that teach AI coding assistants the engine's conventions and, more usefully, the mistakes that fail silently rather than raising an error.

    They are versioned with the engine and ship inside the package, at node_modules/melonjs/skills/ — so a copy matching the exact release you are running is always on disk.

    Install them into whatever assistant you use, with one command :

    npx skills add https://github.com/melonjs/melonJS/tree/master/packages/melonjs/skills
    

    It detects the assistants in your project and installs one copy of each skill under .agents/skills/<skill-name>, then symlinks that copy into every assistant's own directory, so .claude/skills/melonjs points back at .agents/skills/melonjs and there is nothing to place by hand. It reports the assistants it covers as it runs (77 of them at the time of writing). Add -a claude-code -a cursor to target specific ones.

    The set includes an AGENTS.md for anything following that convention (Codex, Cursor, Gemini CLI); GitHub Copilot reads the same content from .github/copilot-instructions.md. It names the three rules that produce code which runs and is wrong, and links the API index below — if you already keep an AGENTS.md, paste its sections into yours.

    The command installs from master. To pin to the release you are running, point it at that tag instead of master in the URL above.

    The skills are plain markdown and can be read by any agent, or by a human.

    For anything the skills do not cover, the complete API is indexed for agents at llms.txt — every exported class, function and type with a one-line summary and a link to its reference page, regenerated on every docs build.

    Community

    Join us and get help or share your projects :

    Contributing

    We welcome contributions! Please read our Contributing Guide before submitting changes or new features.

    Sponsors

    Support the development of melonJS by becoming a sponsor. Get your logo in our README with a link to your site or become a backer and get your name in the BACKERS list. Any level of support is really appreciated and goes a long way !

    Melon Gaming

    Altbyte Pte Ltd