Firefox has excellent support for Canvas 2D and WebGL. This guide covers the practical API, performance tips, and how to debug graphics with Firefox DevTools.
Canvas 2D Basics
<canvas id="myCanvas" width="800" height="600"></canvas>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// Shapes
ctx.fillStyle = '#3B82F6';
ctx.fillRect(10, 10, 100, 80);
ctx.strokeStyle = '#1E40AF';
ctx.lineWidth = 2;
ctx.strokeRect(10, 10, 100, 80);
// Paths
ctx.beginPath();
ctx.moveTo(200, 50);
ctx.lineTo(300, 150);
ctx.lineTo(100, 150);
ctx.closePath();
ctx.fillStyle = '#10B981';
ctx.fill();
ctx.stroke();
// Circles
ctx.beginPath();
ctx.arc(400, 100, 50, 0, Math.PI * 2);
ctx.fillStyle = '#F59E0B';
ctx.fill();
Text Rendering
ctx.font = '24px "Inter", sans-serif';
ctx.fillStyle = '#1F2937';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('Hello Canvas', canvas.width / 2, canvas.height / 2);
// Measure text
const metrics = ctx.measureText('Hello');
console.log(metrics.width); // pixel width
console.log(metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent); // height
Images and Sprites
const img = new Image();
img.src = '/sprites/player.png';
img.onload = () => {
// Draw full image
ctx.drawImage(img, 0, 0);
// Draw scaled
ctx.drawImage(img, 0, 0, 200, 200);
// Draw sprite (source x, y, w, h → dest x, y, w, h)
ctx.drawImage(img, 64, 0, 32, 32, 100, 100, 64, 64);
};
Canvas Performance Tips
// 1. Clear only what changed, not the whole canvas
function clearRegion(x, y, w, h) {
ctx.clearRect(x, y, w, h);
}
// 2. Use requestAnimationFrame, not setInterval
function gameLoop(timestamp) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
update(timestamp);
draw(ctx);
requestAnimationFrame(gameLoop);
}
requestAnimationFrame(gameLoop);
// 3. Use an offscreen canvas for complex static content
const offscreen = new OffscreenCanvas(800, 600);
const offCtx = offscreen.getContext('2d');
// Draw complex background once
drawBackground(offCtx);
// In game loop, blit the offscreen canvas
function draw(ctx) {
ctx.drawImage(offscreen, 0, 0); // Fast copy
// Draw dynamic content on top
drawPlayer(ctx);
}
// 4. Batch operations — avoid switching fill/stroke colors repeatedly
// Bad:
items.forEach(item => {
ctx.fillStyle = item.color;
ctx.fillRect(item.x, item.y, item.w, item.h);
});
// Better: group by color
const grouped = Map.groupBy(items, i => i.color);
grouped.forEach((items, color) => {
ctx.fillStyle = color;
ctx.beginPath();
items.forEach(item => ctx.rect(item.x, item.y, item.w, item.h));
ctx.fill();
});
WebGL Basics
For 3D or high-performance 2D, use WebGL:
const gl = canvas.getContext('webgl2'); // Firefox supports WebGL 2
// Vertex shader
const vertexShaderSrc = `#version 300 es
in vec2 aPosition;
void main() {
gl_Position = vec4(aPosition, 0.0, 1.0);
}`;
// Fragment shader
const fragmentShaderSrc = `#version 300 es
precision highp float;
out vec4 fragColor;
void main() {
fragColor = vec4(0.231, 0.510, 0.965, 1.0); // #3B82F6
}`;
function createShader(type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
throw new Error(gl.getShaderInfoLog(shader));
}
return shader;
}
const vertShader = createShader(gl.VERTEX_SHADER, vertexShaderSrc);
const fragShader = createShader(gl.FRAGMENT_SHADER, fragmentShaderSrc);
const program = gl.createProgram();
gl.attachShader(program, vertShader);
gl.attachShader(program, fragShader);
gl.linkProgram(program);
// Draw a triangle
const vertices = new Float32Array([
0, 0.5, // top
-0.5, -0.5, // bottom-left
0.5, -0.5, // bottom-right
]);
const vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.useProgram(program);
const posLoc = gl.getAttribLocation(program, 'aPosition');
gl.enableVertexAttribArray(posLoc);
gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);
gl.clearColor(0.1, 0.1, 0.1, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);
Debugging Canvas with Firefox DevTools
Firefox has dedicated canvas debugging tools:
- Memory Snapshot: DevTools → Memory → Take snapshot to see canvas contexts and GPU memory usage
- Performance: Record a timeline to see frame rendering time, GPU raster time
-
Canvas Inspector (via WebExtension): Firefox has
getContexthooks — you can log all draw calls for debugging
// Manual draw call logging for debugging
const origFillRect = CanvasRenderingContext2D.prototype.fillRect;
CanvasRenderingContext2D.prototype.fillRect = function(x, y, w, h) {
console.trace('fillRect', { x, y, w, h });
return origFillRect.apply(this, arguments);
};
Saving Canvas as Image
// PNG download
canvas.toBlob(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'canvas-export.png';
a.click();
URL.revokeObjectURL(url);
}, 'image/png');
// JPEG with quality
canvas.toBlob(blob => { /* ... */ }, 'image/jpeg', 0.9);
// Synchronous (avoid for large canvases — can block UI)
const dataUrl = canvas.toDataURL('image/png');
Three.js with Firefox
For complex 3D, Three.js builds on WebGL and works great in Firefox:
import * as THREE from 'three';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshPhongMaterial({ color: 0x3B82F6 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 5, 5);
scene.add(light);
camera.position.z = 5;
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
Firefox's WebGL implementation follows the spec closely — code that works in Firefox generally works everywhere.
Top comments (0)