-
-
Notifications
You must be signed in to change notification settings - Fork 657
Rendering API
The melonJS rendering API is designed to feel familiar to anyone who has used the HTML5 Canvas 2D API (CanvasRenderingContext2D). Whether you choose the Canvas or WebGL renderer, the API remains the same — write your game once, and it runs on both backends with zero code changes.
// This code works identically on Canvas and WebGL
renderer.save();
renderer.translate(100, 50);
renderer.rotate(Math.PI / 4);
renderer.setColor("#FF0000");
renderer.fillRect(0, 0, 64, 64);
renderer.restore();If you've used ctx.save(), ctx.translate(), ctx.fillRect() on a Canvas 2D context, you already know the melonJS rendering API.
See these features in action:
- Graphics — shapes, paths, bezier curves, dashed lines, masks, transforms
- Gradients — linear/radial gradients on rects, ellipses, polygons, rounded rects
- Blend Modes — all supported composite operations
The table below maps every melonJS renderer method to its Canvas 2D equivalent.
| melonJS | Canvas 2D Equivalent | Description |
|---|---|---|
save() |
ctx.save() |
Push the current renderer state onto a stack |
restore() |
ctx.restore() |
Pop and restore the most recently saved state |
reset() |
— | Reset the entire renderer context to its default state |
clear() |
— | Prepare the framebuffer for a new frame |
flush() |
— | Flush the render pipeline (WebGL batches; no-op on Canvas) |
| melonJS | Canvas 2D Equivalent | Description |
|---|---|---|
translate(x, y) |
ctx.translate(x, y) |
Add a translation transformation |
rotate(angle) |
ctx.rotate(angle) |
Add a rotation (radians) to the transformation matrix |
scale(x, y) |
ctx.scale(x, y) |
Add a scaling transformation |
transform(a, b, c, d, e, f) |
ctx.transform(a, b, c, d, e, f) |
Multiply the current matrix by the given one |
setTransform(a, b, c, d, e, f) |
ctx.setTransform(a, b, c, d, e, f) |
Reset the matrix then apply the given one |
resetTransform() |
ctx.setTransform(1,0,0,1,0,0) |
Reset the transformation matrix to identity |
setProjection(matrix) |
— | Set the projection matrix (orthographic) |
| melonJS | Canvas 2D Equivalent | Description |
|---|---|---|
setColor(color) |
ctx.fillStyle / ctx.strokeStyle
|
Set the current fill and stroke color (accepts Color, string, or Gradient) |
getColor() |
— | Get the current fill and stroke color |
createLinearGradient(x0, y0, x1, y1) |
ctx.createLinearGradient(x0, y0, x1, y1) |
Create a linear gradient fill |
createRadialGradient(x0, y0, r0, x1, y1, r1) |
ctx.createRadialGradient(x0, y0, r0, x1, y1, r1) |
Create a radial gradient fill |
gradient.addColorStop(offset, color) |
gradient.addColorStop(offset, color) |
Add a color stop to a gradient |
setGlobalAlpha(alpha) |
ctx.globalAlpha = alpha |
Set the global alpha (opacity) |
getGlobalAlpha() |
ctx.globalAlpha |
Get the current global alpha |
setTint(tint, alpha) |
— | Set a coloring tint for sprite rendering |
clearTint() |
— | Clear the current rendering tint |
setBlendMode(mode) |
ctx.globalCompositeOperation |
Set the blend/composite mode |
getBlendMode() |
ctx.globalCompositeOperation |
Get the current blend mode |
Gradient example:
const gradient = renderer.createLinearGradient(0, 0, 200, 0);
gradient.addColorStop(0, "#00FF00");
gradient.addColorStop(0.5, "#FFFF00");
gradient.addColorStop(1, "#FF0000");
renderer.setColor(gradient);
renderer.fillRect(10, 10, 200, 24);| melonJS | Canvas 2D Equivalent | Description |
|---|---|---|
fillRect(x, y, w, h) |
ctx.fillRect(x, y, w, h) |
Fill a rectangle |
strokeRect(x, y, w, h) |
ctx.strokeRect(x, y, w, h) |
Stroke a rectangle outline |
clearRect(x, y, w, h) |
ctx.clearRect(x, y, w, h) |
Erase pixels in a rectangular area |
clearColor(color, opaque) |
— | Clear the framebuffer with a solid color |
fillRoundRect(x, y, w, h, r) |
ctx.roundRect() + ctx.fill()
|
Fill a rounded rectangle |
strokeRoundRect(x, y, w, h, r) |
ctx.roundRect() + ctx.stroke()
|
Stroke a rounded rectangle outline |
| melonJS | Canvas 2D Equivalent | Description |
|---|---|---|
beginPath() |
ctx.beginPath() |
Start a new path |
closePath() |
ctx.closePath() |
Close the current sub-path |
moveTo(x, y) |
ctx.moveTo(x, y) |
Move to a point without drawing |
lineTo(x, y) |
ctx.lineTo(x, y) |
Draw a straight line to a point |
quadraticCurveTo(cpx, cpy, x, y) |
ctx.quadraticCurveTo(cpx, cpy, x, y) |
Add a quadratic Bezier curve to the path |
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) |
ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) |
Add a cubic Bezier curve to the path |
arcTo(x1, y1, x2, y2, radius) |
ctx.arcTo(x1, y1, x2, y2, radius) |
Add a circular arc using control points and radius |
rect(x, y, w, h) |
ctx.rect(x, y, w, h) |
Add a rectangle to the current path |
roundRect(x, y, w, h, radii) |
ctx.roundRect(x, y, w, h, radii) |
Add a rounded rectangle to the current path |
stroke(shape) |
ctx.stroke() |
Stroke the current path or a given shape |
fill(shape) |
ctx.fill() |
Fill the current path or a given shape |
Bezier curve example:
renderer.beginPath();
renderer.setColor("#10b981");
renderer.moveTo(0, 100);
renderer.bezierCurveTo(100, 0, 200, 200, 300, 100);
renderer.stroke();| melonJS | Canvas 2D Equivalent | Description |
|---|---|---|
strokeArc(x, y, r, start, end) |
ctx.arc() + ctx.stroke()
|
Stroke an arc |
fillArc(x, y, r, start, end) |
ctx.arc() + ctx.fill()
|
Fill an arc |
strokeEllipse(x, y, w, h) |
ctx.ellipse() + ctx.stroke()
|
Stroke an ellipse |
fillEllipse(x, y, w, h) |
ctx.ellipse() + ctx.fill()
|
Fill an ellipse |
strokeLine(x1, y1, x2, y2) |
ctx.moveTo() + ctx.lineTo() + ctx.stroke()
|
Stroke a line between two points |
fillLine(x1, y1, x2, y2) |
ctx.moveTo() + ctx.lineTo() + ctx.fill()
|
Fill a line between two points |
strokePolygon(poly) |
ctx.lineTo() loop + ctx.stroke()
|
Stroke a polygon |
fillPolygon(poly) |
ctx.lineTo() loop + ctx.fill()
|
Fill a polygon |
strokePoint(x, y) |
— | Stroke a single point |
fillPoint(x, y) |
— | Fill a single point |
| melonJS | Canvas 2D Equivalent | Description |
|---|---|---|
drawImage(image, ...) |
ctx.drawImage(image, ...) |
Draw an image (supports all 3/5/9 argument forms) |
createPattern(image, repeat) |
ctx.createPattern(image, repeat) |
Create a repeating image pattern |
drawPattern(pattern, x, y, w, h) |
ctx.fillStyle = pattern + ctx.fillRect()
|
Draw a pattern within a rectangle |
| melonJS | Canvas 2D Equivalent | Description |
|---|---|---|
clipRect(x, y, w, h) |
ctx.rect() + ctx.clip()
|
Clip rendering to a rectangular region |
setMask(mask, invert) |
ctx.clip() / gl.stencilFunc()
|
Apply an arbitrary shape as a rendering mask |
clearMask() |
— | Remove the current rendering mask |
| melonJS | Canvas 2D Equivalent | Description |
|---|---|---|
setLineDash(segments) |
ctx.setLineDash(segments) |
Set the dash pattern for stroke operations |
getLineDash() |
ctx.getLineDash() |
Get the current dash pattern |
lineWidth |
ctx.lineWidth |
Line thickness (property, not a method) |
Dashed line example:
renderer.setLineDash([10, 5]);
renderer.strokeLine(0, 50, 300, 50);
renderer.setLineDash([]); // back to solid| melonJS | Canvas 2D Equivalent | Description |
|---|---|---|
setAntiAlias(enable) |
ctx.imageSmoothingEnabled |
Enable or disable image smoothing/anti-aliasing |
| melonJS | Canvas 2D Equivalent | Description |
|---|---|---|
getCanvas() |
canvas |
Return the underlying canvas element |
getContext() |
canvas.getContext('2d') |
Return the underlying rendering context |
resize(w, h) |
Setting canvas.width / canvas.height
|
Resize the rendering canvas |
overlaps(bounds) |
— | Check if a bounding box overlaps the visible area |
toBlob(type, quality) |
canvas.toBlob() |
Export the current frame as a Blob |
toDataURL(type, quality) |
canvas.toDataURL() |
Export the current frame as a data URL |
toImageBitmap(type, quality) |
createImageBitmap(canvas) |
Export the current frame as an ImageBitmap |
These methods are available on both renderers but only return meaningful results on WebGL. On Canvas they are safe to call but have no effect or return empty/default values:
| melonJS | Description |
|---|---|
addBatcher(batcher, name) |
Add a custom batcher for specialized rendering (WebGL only) |
setBatcher(name, shader) |
Switch the active rendering batcher (WebGL only) |
setViewport(x, y, w, h) |
Set the WebGL viewport rectangle (WebGL only) |
WebGLVersion |
Returns the WebGL version in use (1 or 2), undefined on Canvas |
getSupportedCompressedTextureFormats() |
List supported GPU compressed texture formats (returns empty on Canvas) |
While the API mirrors Canvas 2D closely, there are a few design differences:
-
Unified color setter — melonJS uses
setColor(color)to set bothfillStyleandstrokeStyleat once, rather than having two separate properties. -
Convenience shape methods — Instead of building paths manually, melonJS provides direct
strokeRect,fillEllipse,strokePolygon, etc. methods that accept melonJS shape objects (Rect, Ellipse, Polygon). -
Tinting —
setTint()/clearTint()provide sprite-level color tinting with no Canvas 2D equivalent. -
Automatic batching — The WebGL renderer automatically batches draw calls. Call
flush()explicitly only when you need to force a batch submission (e.g. before reading pixels). -
Blend modes — Both renderers support the same blend mode names (
normal,multiply,screen,additive, etc.), abstracting away the difference betweenglobalCompositeOperation(Canvas) and GL blend functions (WebGL).
import { Application, video } from "melonjs";
// Auto-detect (WebGL with Canvas fallback)
const app = new Application(800, 600, { renderer: video.AUTO });
// Force Canvas
const app = new Application(800, 600, { renderer: video.CANVAS });
// Force WebGL
const app = new Application(800, 600, { renderer: video.WEBGL });The renderer is accessed via app.renderer and provides the full API listed above regardless of which backend is active.
melonJS uses an internal Path2D class to build and tessellate 2D paths for the WebGL renderer. On Canvas, path methods (moveTo, lineTo, bezierCurveTo, etc.) are direct pass-throughs to the native context. On WebGL, they are routed through Path2D which tessellates curves into line segments for the primitive batcher.
Path2D also supports SVG path strings for defining shapes:
import Path2D from "melonjs";
// a heart shape using arcs and quadratic curves
const heart = new Path2D(
"M 10 30 A 20 20 0 0 1 50 30 A 20 20 0 0 1 90 30 Q 90 60 50 90 Q 10 60 10 30 Z"
);Supported SVG commands: M (moveTo), L (lineTo), H (horizontal line), V (vertical line), Q (quadratic Bezier), C (cubic Bezier), A (arc), Z (close path).
To draw custom graphics, override the draw method of a Renderable:
import { Renderable } from "melonjs";
class MyGraphics extends Renderable {
constructor() {
super(0, 0, 200, 200);
this.anchorPoint.set(0, 0);
}
draw(renderer) {
// sky gradient
const sky = renderer.createLinearGradient(0, 0, 0, 100);
sky.addColorStop(0, "#1a1a6e");
sky.addColorStop(1, "#FF6B35");
renderer.setColor(sky);
renderer.fillRect(0, 0, 200, 100);
// dashed horizon line
renderer.setLineDash([8, 4]);
renderer.setColor("#FFFFFF");
renderer.strokeLine(0, 100, 200, 100);
renderer.setLineDash([]);
// bezier curve hill
renderer.beginPath();
renderer.setColor("#2d5016");
renderer.moveTo(0, 150);
renderer.bezierCurveTo(50, 80, 150, 80, 200, 150);
renderer.lineTo(200, 200);
renderer.lineTo(0, 200);
renderer.fill();
}
}