Skip to content

q5 WebGPU renderer

Quinton Ashley edited this page Feb 7, 2025 · 9 revisions

The WebGPU graphics API is the successor to WebGL.

As of February 2025, WebGPU is fully supported in Google Chrome and Edge. 🎉

Why use q5 WebGPU?

q5 WebGPU is many times faster than p5.js, in common use cases.

Comprehensive test results comparing q5.js to other graphics libraries is coming soon.

When you intend for a q5.js sketch to use WebGPU, but WebGPU is not supported on a viewer's browser, q5 will put a warning in the console, apply a compatibility layer, and display the sketch with the fallback Canvas2D renderer.

Basic Usage

To use q5's WebGPU renderer, run Q5.webgpu() after the creation of any file level variables.

let message = "Hello world!";

Q5.webgpu();

function setup() {
  createCanvas(200, 100);
  text(message, 0, 0);
}

Note that with this method of using q5 WebGPU, you can only use q5 functions and variables inside q5 functions like setup and draw, similar to p5's limited global mode. You'll need to use the preload function if you want to preload assets.

Try it out with the OpenProcessing online code editor!

https://openprocessing.org/sketch/2471587

q5 WebGPU differences

  • The origin of the canvas (0, 0) is in the center, not the top left.
  • The default color mode is RGB in 0-1 "float" format: colorMode(RGB, 1).
  • Unlike in p5's WebGL mode, mouse and touch coordinates align with canvas pixel values.
  • Fonts must be loaded in MSDF format.

Module Usage

Note that Q5.webgpu is an async function, so top level global mode can only be achieved inside a JS module.

Set the type of your sketch to "module" in your html.

<script type="module" src="sketch.js">

Await for Q5.webgpu() to return a Q5 instance (q), which you can then use to set q5 functions such as draw. This is necessary because q5 can not "see" functions created in a module's scope.

let q = await Q5.webgpu();

createCanvas(200, 200);
noStroke();

q.draw = () => {
  clear();
  rect(50, 50, 100, 100);
};

If you'd like to know the technical reasons why Q5.webgpu had to be an async function, it's because GPU.requestAdapter and GPUAdapter.requestDevice are async functions. A GPUDevice is needed before anything can be drawn to a WebGPU canvas.

Text Rendering

The q5 WebGPU text renderer uses multi-channel signed distance fields (MSDF) for high performance and high quality text rendering. Text can be rapidly recolored, rotated, and scaled without any loss in quality or performance.

MSDF, introduced by Chlumsky Viktor in his master's thesis "Shape Decomposition for Multi-channel Distance Fields" (2015), improves upon the signed distance field (SDF) technique, popularized by Chris Green and Valve Software in "Improved Alpha-Tested Magnification for Vector Textures and Special Effects" (2007).

SDF MSDF
demo-sdf16 demo-msdf16

For convenience, if no font is loaded before text is run, then q5's default "sans-serif" MSDF font is loaded: https://q5js.org/fonts/sans-serif-msdf.json

"sans-serif" msdf texture

This 512x512 msdf texture (207kb) was made with the Microsoft YaHei font and stores every character visible on a standard English keyboard, letters with diacritics (accents) used in European languages, and mathematical symbols.

!"#$%&'()\*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^\_`abcdefghijklmnopqrstuvwxyz{|}~�¡¢£¥©®°²³´·¹º¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ‘’“”ΑαΒβΓγΔδΕεΛλΠπΣσΩω∴∵─│┌┐└┘├┤┬┴┼▀▄█▌▐▓▒░←↑→↓↔↕↖↗↘↙«»µτΦΘ∞≡±≈∙√ⁿ

Do you think any other characters ought to be included in the default set? Let us know! /~https://github.com/q5js/q5.js/issues

Create a MSDF Font

You can choose a custom set of characters and convert fonts to MSDF format by using the msdf-bmfont-xml website, created by Don McCurdy.

Optionally, you can use q5's msdf-minifier node.js script to reduce the size of the MSDF json file.

Load a MSDF font

Fonts must be in MSDF format with the file ending "-msdf.json".

Q5.webgpu();

function preload() {
  loadFont('arial-msdf.json');
}

function setup() {
  createCanvas(200, 200);
}

function draw() {
  fill(0.71, 0.92, 1);
  text('Hello, World!', mouseX, mouseY);
}

Displaying Emojis

Full color emoji characters can't be rendered using the MSDF technique, so draw them using textImage.