We are releasing p5.js 2.0 to the community for testing and development! Here’s what you need to know.
- For reference: p5.js 1.x reference will stay on https://p5js.org/, and p5.js 2.x documentation will be on https://beta.p5js.org/
- In the p5.js Editor: the default will continue to be 1.x until at least August 2026 - more information and discussion on timeline can be found on this Discourse thread or this GitHub thread
- For updating sketches and add-on libraries: check out the compatibility add-on libraries and guides
- For contribution:
npm latest
will default to 2.x, but the git branches are still separated withmain
on 1.x anddev-2.0
on 2.x. We will switch the branches when we have updated all automations (including deploying updated documentation to the website). Want to contribute ideas or implementation? Check the 2.x project board for an overview of what still needs discussion, and what’s ready for work!
Start exploring 🌱
- Typography: textToContours(), textToModel() in
WEBGL
, and textWeight() for variable fonts! - New color modes with colorMode()!
- Authoring shaders with JavaScript using p5.strands!
- Add-on Library Authoring Guide
More details of the changes 🌳
You can also checkout Dave Pagurek's reflections on p5.js 2.0 and an open source philosophy!
Typography
- A refactor of the typography system to be smaller, support variable fonts, and have more precise text measurement by Daniel Howe @dhowe
- Support for loading fonts via CSS (thanks to @dhowe)
- More ways to draw and manipulate text (thanks to @davepagurek)
- An approximately 350% performance improvement to textToPoints and 3D text extrusion support (thanks to @davepagurek)
Support for more color spaces in p5.Color
(thanks to @limzykenneth and @dianamgalindo)
p5.js 2.0 now supports more color modes in addition to the existing RGB, HSB, and HSL color modes. Here are the list of new supported color mode and brief description of them:
RGBHDR
- High Dynamic Range RGB color defined within the Display P3 color space. You will need to use the HDR canvas described below to draw this color on the canvas accurately.HWB
- Hue, Whiteness, Blackness. This is similar toHSL
andHSB
in that you will define a hue angle however instead of saturation and lightness, you will define the percentage of whiteness and blackness. It is the color model of the GUI color picker used by Chrome.
LAB
- Also called CIE Lab, defines color with Lightness, Alpha, and Beta. The color space is often used in professional color measuring context.LCH
- An easier to use representation of a CIE Lab color with definition of Lightness, Chroma, and Hue instead.OKLAB
- OkLab is a slight adjustment to CIE Lab color space mainly to fix a non-uniformity issue that exist in CIE Lab. This difference is more visible in the example below.OKLCH
- An easier to use representation of an OkLab color with definition of Lightness, Chroma, and Hue instead.
Comparing HSL
, LCH
, and OKLCH
in a sketch below:
From left to right are color wheels of HSL
, LCH
, and OKLCH
respectively. Notice the evenness of color distribution between each wheel with OkLCH having the most even distribution. It can be noted that the LCH wheel has a large blue section that is fixed by OkLCH.
To use these new color spaces in p5.js 2.0, the respective constants have been added and the colorMode()
function can be used with these constants in the same way as RGB
, HSL
, and HSB
.
function setup(){
createCanvas(200, 200);
}
function draw(){
colorMode(OKLCH);
background(220); // Should show a teal colored canvas
}
Support for wide-gamut colors with the display-p3
mode (thanks to @limzykenneth)
You can now create a 2D canvas that supports HDR colors that will give you a more vibrant sketch and also HDR images. To use a HDR canvas you will need to create it using the P2DHDR
constant like below:
function setup(){
createCanvas(400, 400, P2DHDR);
}
When a P2DHDR
canvas is created, the default color mode will be switched to the new RGBHDR
color mode instead of RGB
. In practice you can continue to use the same RGB color definition you have always used.
function setup(){
createCanvas(400, 400, P2DHDR);
}
function draw(){
background(255, 0, 0);
fill(100, 255, 0);
circle(100, 100, 50);
}
This example sketch shows a direct comparison between HDR and non-HDR colors, you should see three bands of red, green, and blue colors with a slightly dimmer red, green, and blue circles within. However, both your browser and your screen will need to support HDR to see the difference. Currently Firefox on desktop does not support HDR canvas so if you do not see a difference, try a different browser such as Safari or Chrome.
You can also now load HDR images and have them be displayed in full HDR in a HDR canvas. If you see a dark image on the linked sketch, your browser or screen does not support HDR and you should try a different browser/device.
A new simple lines mode for WebGL (thanks to contributions from @perminder-17)
If you are drawing lots of shapes, and don't need stroke caps or joins, you can use a simple lines mode for increased performance in WebGL. You can activate this mode by calling linesMode(SIMPLE)
in your sketch.
Custom shaders for fills, strokes, images (thanks to @Garima3110 and @perminder-17)
You can now create your own shaders for fills, strokes, and images, and have them all applied at once! Use shader()
to set a fill shader, strokeShader()
to set a stroke shader, and imageShader()
to set an image shader. Try using baseMaterialShader().modify(...)
and baseStrokeShader().modify(...)
to create custom shaders.
let myFillShader = baseMaterialShader.modify({
'vec4 getFinalColor': `(vec4 color) {
return vec4(1., 1., 0., 1.);
}`
});
let myStrokeShader = baseStrokeShader.modify({
'vec4 getFinalColor': `(vec4 color) {
return vec4(1., 0., 1., 1.);
}`
});
let myImageShader = baseMaterialShader.modify({
'vec4 getFinalColor': `(vec4 color) {
return vec4(0., 1., 1., 1.);
}`
});
shader(myFillShader);
strokeShader(myStrokeShader);
imageShader(myImageShader);
sphere(); // Draws with the custom stroke and image shaders
image(myImg, 0, 0); // Draws with the custom image shader
Updated bezier and curve drawing functions (thanks to @GregStanton)
First off: you can combine multiple types of curves in one begin/endShape()
block now!
Long cubic and quadratic bezier vertex calls are now split up into their individual control points. Both cubic and quadratic curves are done with bezierVertex
now, and you can set bezierOrder()
to change from cubic (order 3) to quadratic (order 2). For WebGL mode, this also means you can also specify texture coordinates per control point, or change the fill, stroke, normal, and more between control points.
1.x | 2.0 |
---|---|
beginShape();
vertex(10, 10);
vertex(30, 10);
bezierVertex(35, 10, 40, 15, 40, 20);
vertex(40, 30);
quadraticVertex(40, 40, 30, 40);
vertex(10, 40);
endShape(CLOSE); |
beginShape();
vertex(10, 10);
vertex(30, 10);
// Default cubic
bezierVertex(35, 10);
bezierVertex(40, 15);
bezierVertex(40, 20);
vertex(40, 30);
bezierOrder(2);
bezierVertex(40, 40);
bezierVertex(30, 40);
vertex(10, 40);
endShape(p5.CLOSE); |
We've renamed curveVertex
to splineVertex
and have given it more options. By default, it will now go through every splineVertex
, so you no longer have to double up the first/last point to get it to go through it:
1.x | 2.0 |
---|---|
beginShape();
curveVertex(10, 10);
curveVertex(10, 10);
curveVertex(15, 40);
curveVertex(40, 35);
curveVertex(25, 15);
curveVertex(15, 25);
curveVertex(15, 25);
endShape(); |
beginShape();
splineVertex(10, 10);
splineVertex(15, 40);
splineVertex(40, 35);
splineVertex(25, 15);
splineVertex(15, 25);
endShape(); |
Similarly, endShape(CLOSE)
(or endContour(CLOSE)
if you're in a contour) will cause a spline to smoothly loop back on itself so you no longer need to double up any points:
1.x | 2.0 |
---|---|
beginShape();
curveVertex(15, 25);
curveVertex(10, 10);
curveVertex(15, 40);
curveVertex(40, 35);
curveVertex(25, 15);
curveVertex(15, 25);
curveVertex(10, 10);
curveVertex(15, 40);
endShape(); |
beginShape();
splineVertex(10, 10);
splineVertex(15, 40);
splineVertex(40, 35);
splineVertex(25, 15);
splineVertex(15, 25);
endShape(CLOSE); |
Async loading (thanks to @limzykenneth)
Rather than having a preload
function, p5 2.0 has async setup
!
1.x | 2.0 |
---|---|
let img;
function preload() {
img = loadImage('cat.jpg');
}
function setup() {
createCanvas(200, 200);
} |
let img;
async function setup() {
createCanvas(200, 200);
img = await loadImage('cat.jpg');
} |
🚧 Since this is a breaking change from 1.x to 2.0, you can weight in on the compatibility discussion here
Support for loading fonts via CSS (thanks to @dhowe)
In 2D mode, try loading fonts via a a path to a CSS font file, such as a Google Fonts link!
loadFont("https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,[email protected],200..800&display=swap")
loadFont(`@font-face { font-family: "Bricolage Grotesque", serif; font-optical-sizing: auto; font-weight: <weight> font-style: normal; font-variation-settings: "wdth" 100; }`);
loadFont({
fontFamily: '"Bricolage Grotesque", serif',
fontOpticalSizing: 'auto',
fontWeight: '<weight>',
fontStyle: 'normal',
fontVariationSettings: '"wdth" 100',
});
loadFont("https://fonts.gstatic.com/s/inter/v18/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfMZhrib2Bg-4.ttf");
loadFont("path/to/localFont.ttf");
loadFont("system-font-name");
Support for variable font weight (thanks to contributions by @dhowe)
In 2D mode, if you've loaded a variable font, try changing its weight!
var font;
async function setup() {
createCanvas(100, 100);
font = await loadFont(
'https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100..900;1,100..900&display=swap'
);
}
function draw() {
background(255);
textFont(font);
textAlign(LEFT, TOP);
textSize(35);
textWeight(sin(millis() * 0.002) * 200 + 400);
text('p5*js', 0, 10);
}
More ways to draw and manipulate text (thanks to @davepagurek)
Like how textToPoints()
gives you points on text, the new textToContours()
function lets you edit the points on text and then draw them with fills!
createCanvas(100, 100);
const font = await loadFont('myFont.ttf');
background(200);
strokeWeight(2);
textSize(50);
const contours = font.textToContours('p5*js', 0, 50, { sampleFactor: 0.5 });
beginShape();
for (const pts of contours) {
beginContour();
for (const pt of pts) {
vertex(pt.x + 20*sin(pt.y*0.01), pt.y + 20*sin(pt.x*0.01));
}
endContour(CLOSE);
}
endShape();
In WebGL, you can use textToModel
to extrude a 3D model out of your text:
createCanvas(100, 100, WEBGL);
const font = await loadFont('myFont.ttf');
background(200);
textSize(50);
const geom = font.textToModel('p5*js', 0, 50, { sampleFactor: 2, extrude: 20 });
orbitControl();
model(geom);
A new pointer event handling system (thanks to @diyaayay)
Instead of having separate methods for mouse and touch, we now use the browser's pointer API to handle both simultaneously. Try defining mouse functions as usual and accessing the global touches
array to see what pointers are active for multitouch support!
Custom shader attributes (thanks to @lukeplowden)
If you are using a shader and want custom per-vertex properties in addition to uniform
s, which are the same across the whole shape, you can now call vertexProperty(name, value)
before vertices.
const vertSrc = `#version 300 es
precision mediump float;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
in vec3 aPosition;
in vec2 aOffset;
void main(){
vec4 positionVec4 = vec4(aPosition.xyz, 1.0);
positionVec4.xy += aOffset;
gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;
}
`;
const fragSrc = `#version 300 es
precision mediump float;
out vec4 outColor;
void main(){
outColor = vec4(0.0, 1.0, 1.0, 1.0);
}
`;
function setup(){
createCanvas(100, 100, WEBGL);
// Create and use the custom shader.
const myShader = createShader(vertSrc, fragSrc);
shader(myShader);
describe('A wobbly, cyan circle on a gray background.');
}
function draw(){
// Set the styles
background(125);
noStroke();
// Draw the circle.
beginShape();
for (let i = 0; i < 30; i++){
const x = 40 * cos(i/30 * TWO_PI);
const y = 40 * sin(i/30 * TWO_PI);
// Apply some noise to the coordinates.
const xOff = 10 * noise(x + millis()/1000) - 5;
const yOff = 10 * noise(y + millis()/1000) - 5;
// Apply these noise values to the following vertex.
vertexProperty('aOffset', [xOff, yOff]);
vertex(x, y);
}
endShape(CLOSE);
}
What's Changed
What's Changed 🎊
- Addresses issue #7077 by @Garima3110 in #7102
- Add initial conversion script from Documentation.js to old format by @davepagurek in #6777
- Standardize all parameter types by @sproutleaf in #7179
- Modify convert.js and finish standardizing parameters by @sproutleaf in #7183
- Start developing a new param validator using Zod by @sproutleaf in #7186
- Update to param validator + test file by @sproutleaf in #7194
- [p5.js 2.0] Refactor and modular build by @limzykenneth in #7203
- Fix most WebGL tests by @davepagurek in #7210
- Get visual tests running in 2.0 by @davepagurek in #7251
- Small fixes to help get dev-2.0 branch running for other contributors by @lukeplowden in #7215
- Module syntax conversion by @limzykenneth in #7257
- More test fixes by @davepagurek in #7266
- Update param validator and test file by @sproutleaf in #7268
- Shader hooks for dev-2.0 by @davepagurek in #7267
- Final changes for parameter validation by @sproutleaf in #7291
- setAttribute() function for defining custom shader attributes by @lukeplowden in #7276
- Initial modules refactor by @davepagurek in #7295
- [p5.js 2.0] WebGL module syntax by @limzykenneth in #7296
- Add new sketch verifier to FES by @sproutleaf in #7293
- Make shaders define what they get used for. by @Garima3110 in #7256
- Shape tests by @davepagurek in #7323
- Split contents of dom.js among four(4) files by @SilasVM in #7316
- Solves issue #7059 by @Garima3110 in #7113
- Add more shape visual tests by @davepagurek in #7350
- [p5.js 2.0] State machines and renderer refactoring by @limzykenneth in #7270
- WebGL mode refactor by @davepagurek in #7355
- 2.0 modules clean up by @limzykenneth in #7361
- Add custom_shapes.js, which will eventually replace vertex.js by @GregStanton in #7368
- Fix issues with stroke depth ordering by @davepagurek in #7369
- [p5.js 2.0] IO refactoring by @limzykenneth in #7365
- Fix issues with retained mode rendering and image light by @davepagurek in #7384
- [p5.js 2.0] Fix CSV parsing by @limzykenneth in #7391
- Adding strokeMode() to access SIMPLE lines. by @perminder-17 in #7390
- Event Ordering for touch and mouse events by @diyaayay in #7378
- [p5.js 2.0] Unit tests fix/conversion by @limzykenneth in #7393
- Type 2.0 by @dhowe in #7356
- Refactor 2.0 Typography code to work with WebGL by @davepagurek in #7417
- Overhaul custom shapes for p5.js 2.0 by @GregStanton in #7373
- Add tests for font weight + fix Google Font loading by @davepagurek in #7426
- Add visual tests for textToPoints, addTextToContours by @davepagurek in #7427
- textToPoints perf improvement by @davepagurek in #7428
- FilterRenderer2D for a 2d-Build by @perminder-17 in #7409
- [p5.js 2.0] Color module rewrite by @limzykenneth in #7406
- [p5.js 2.0] Vector n-dimentional and Matrix Interface by @holomorfo in #7405
- [dev-2.0] Benchmark setup and sample report for render and batch by @holomorfo in #7421
- Changed mouse button to object by @diyaayay in #7404
- Updates to shader hooks for 2.0 by @davepagurek in #7432
- More typography updates by @davepagurek in #7434
- Type: implement #7147 and minor refactors by @dhowe in #7440
- Fix MTL color loading when vertices are shared across different faces by @davepagurek in #7441
- Fix noErase() breaking in WebGL by @davepagurek in #7443
- added loadFilterShader function by @Rishab87 in #7445
- [dev-2.0] WOFF font support by @dhowe in #7449
- Add 0 check before dividing color by alpha by @davepagurek in #7478
- Fix usage of model() in buildGeometry() by @davepagurek in #7479
- Fix WebGL text alignment + add tests by @davepagurek in #7481
- Implement splineProperty by @davepagurek in #7471
- Update sketch verifier to check for redefinitions and print friendly messages by @sproutleaf in #7326
- Fix buildGeometry absorbing the ambient fill color by @davepagurek in #7489
- Fix closed curves having extra loops by @davepagurek in #7495
- Fix FES errors, parameter data omitting classes by @davepagurek in #7497
- Merge main into dev-2.0 by @davepagurek in #7509
- Minor refactors, cleanup, comments by @dhowe in #7521
- Text adjustments by @dhowe in #7523
- Remove wrong rendererGL textWidth function by @seyko1 in #7524
- Replaced deprecated keyCode functionality and docs with KeyboardEvent.code & KeyboardEvent.key also updates the keyIsDown function to accept alphanumerics as parameters by @Vaivaswat2244 in #7472
- Clean up modifier key constants by @davepagurek in #7526
- Interleave example between other docs by @davepagurek in #7466
- Add splineProperties by @davepagurek in #7528
- 2.0 perf updates by @davepagurek in #7543
- fixed vertex property to take single digits by @Vaivaswat2244 in #7547
- Add warning when using preload function by @aferriss in #7542
- Two fixes for #7486 by @dhowe in #7555
- [p5.js 2.0] Documentation updates by @limzykenneth in #7558
- Stop future errors when encountering an async error by @davepagurek in #7563
- Add screenToWorld function mirroring worldToScreen by @bojidar-bg in #7561
- [p5.js 2.0] Attach p5.Element methods to WebGL canvas by @limzykenneth in #7567
- [p5.js 2.0] Expose global drawingContext by @limzykenneth in #7572
- Fix saveCanvas for framebuffers by @davepagurek in #7576
- Fix: Preserve canvas position when calling noSmooth() in WEBGL by @ImRAJAS-SAMSE in #7568
- Add back WebGL matrices via getters by @davepagurek in #7588
- Add filter shader hooks by @davepagurek in #7582
- [p5.js 2.0] Loading functions fixes by @limzykenneth in #7594
- Remove old overloads for bezierVertex() and quadraticVertex() by @davepagurek in #7600
- Fix endShape() to Properly Close Paths and Prevent Shape Merging by @Forchapeatl in #7601
- Replace p5.Element mouse/touch events with pointer events by @davepagurek in #7608
- Updated Stencil Test Case to prevent it from disable after every draw by @Vaivaswat2244 in #7578
- Tried an approch for text case in pixelmatch by @Vaivaswat2244 in #7552
- Add deprecation info for p5.Table and splitTokens by @davepagurek in #7624
- Fixes to get the website to build the 2.0 branch by @davepagurek in #7625
- [p5.js 2.0] Remove typed dict and array functions by @limzykenneth in #7616
- Typescript declaration files script by @diyaayay in #7465
- loadFilterShader fixes by @perminder-17 in #7636
- [p5.js 2.0] Fix p5.Table.getColumn does not work with named columns by @limzykenneth in #7643
- Convert docs and types scripts to .mjs to fix node errors on some platforms by @davepagurek in #7644
- fixing getString(), getNum() and get() by @perminder-17 in #7647
- fixing get() in p5.Table by @perminder-17 in #7646
- p5.js Shader generation API by @lukeplowden in #7622
- Minor 2.0 shape changes by @davepagurek in #7656
- Fix binding of texture() by @davepagurek in #7668
- [dev-2.0] fix bug in textAscent/Descent by @dhowe in #7657
- Remove debug logs from the Shader Generator file by @lukeplowden in #7663
- Rename uv in vertex shader hooks to texCoord for consistency by @davepagurek in #7669
- Fix debug mode for 2.0 by @davepagurek in #7672
- Fix default fill color blowing out lighting in WebGL mode by @davepagurek in #7673
- Updating the docs for
colorMode()
. by @perminder-17 in #7654 - Added Docs for the new visual tests by @Vaivaswat2244 in #7640
- fixing-strokeShader() and some minor fixes in shaderHooks-docs by @perminder-17 in #7649
- Update examples that use createCamera() to explicitly call setCamera() by @webermayank in #7607
- Added fontAscent Docs by @perminder-17 in #7606
- Adding documentation for all text functions by @perminder-17 in #7658
- Add back docs for existing font methods by @davepagurek in #7683
- Make sure some new APIs have param types for FES by @davepagurek in #7684
- Fix a few camera bugs by @davepagurek in #7688
- [p5.js 2.0] Restore single color value define grayscale color by @limzykenneth in #7676
- Rename curvePoint/curveTangent to splinePoint/splineTangent by @davepagurek in #7703
- Text to model docs by @perminder-17 in #7595
- Updating loadModel function by @perminder-17 in #7691
- Updating docs for new text functions by @perminder-17 in #7692
- Adding loadBlob() docs by @perminder-17 in #7694
- Bug fixes for Shader API by @lukeplowden in #7675
- Glsl types by @davepagurek in #7706
- Add support for woff2 via an addon by @davepagurek in #7693
- Updating Gray-scale in colorMode() by @perminder-17 in #7690
- fixing-keyboard.js docs by @perminder-17 in #7689
- Update bezier() to use new bezierVetext by @ksen0 in #7701
- loadbytes, loadTable and some minor fixes with other modified functions. by @perminder-17 in #7638
- [dev-2.0] p5.Matrix and p5.Vector docs update by @holomorfo in #7637
- Update phrasing in dev2 branch for trigonometric f functions by @VANSH3104 in #7666
- 2.0 beta 6 bug fixes by @davepagurek in #7709
- 2.0 bug fixes by @davepagurek in #7713
- Clamp color() to maxes by @davepagurek in #7715
- Make deprecation in data.json match 1.x by @davepagurek in #7719
- Start to add pako support by @davepagurek in #7716
- Fix division by 0 in textToPoints by @davepagurek in #7723
- [p5.js 2.0] Refactor out reference to fn in p5.Image class by @limzykenneth in #7720
- Support variable fonts in textToPoints + WebGL rendering by @davepagurek in #7724
- Set FontFace weight ranges based on Typr info by @davepagurek in #7727
- Fix incorrect text weight for variable fonts in Safari by @davepagurek in #7738
- Merge attribution and contributor docs from main to 2.0 by @ksen0 in #7731
- reorder npm run commands to make p5.js-website update the correct ver… by @lirenjie95 in #7748
- Fix spline() with z values + initial beginShape colors not updating by @davepagurek in #7750
- Minimal shape docs by @ksen0 in #7749
New Contributors
- @sproutleaf made their first contribution in #7179
- @lukeplowden made their first contribution in #7215
- @holomorfo made their first contribution in #7405
- @seyko1 made their first contribution in #7524
- @Vaivaswat2244 made their first contribution in #7472
- @bojidar-bg made their first contribution in #7561
- @webermayank made their first contribution in #7607
Full Changelog: v1.11.5...v2.0.0