Most appropriate sub-area of p5.js?
p5.js version
2.3.1, 2.3.2, 2.3.3 (2.3.0 works)
Web browser and version
Chrome 153.0.8010.53
Operating system
Windows 11 (where a student of mine first saw it), also reproduced on macOS 26.6
Steps to reproduce this
Steps:
- Run the snippet below with p5.js 2.3.3 in Chrome 153.
- The points at x = 254 and 255 are drawn. The point at x = 256 is not.
- Switch to p5.js 2.3.0 and all three points are drawn.
Snippet:
function setup() {
createCanvas(400, 400);
}
function draw() {
background(0);
stroke('white');
strokeWeight(100);
point(254, 100);
point(255, 200);
point(256, 300); // not drawn in 2.3.1+ on Chrome 153
}
What seems to be happening
PrimitiveToPath2DConverter.visitPoint in src/shape/custom_shapes.js draws a point as moveTo(x, y) plus lineTo(x + 0.00001, y) and relies on the line caps to make the dot. Canvas paths keep coordinates as 32-bit floats, and once |x| >= 256, x + 0.00001 rounds back to x (Math.fround(256 + 0.00001) === 256). The segment ends up with zero length.
Chrome 153 does not draw zero-length segments at all, which matches the canvas spec ("Prune all zero-length line segments from path" in the trace-a-path steps). A plain moveTo(50, 30); lineTo(50, 30) with round caps draws nothing in Chrome 153, while Chromium 152 (Electron) still draws a dot for it, so this may not show up on older Chrome.
Before 2.3.1 only beginShape(POINTS) used this path. #8899 moved point() onto the shape system too, which is why plain point() broke in 2.3.1.
It is the coordinate passed to point() that matters, not where the point lands on screen: translate(-300, 0); point(400, 60); also disappears.
A related case: with strokeCap(SQUARE) (butt caps), a 0.00001 px line has no visible area, so point() draws nothing at any position, in both Chrome 152 and 153. In 2.3.0 it drew a circle.
Each check below draws one point on a freshly cleared canvas and reads the pixel under it:
| Chrome 153.0.8010.53 |
2.3.0 |
2.3.3 |
point(255, y) |
drawn |
drawn |
point(256, y) |
drawn |
missing |
point(1000, y) |
drawn |
missing |
translate(-300, 0); point(400, y) |
drawn |
missing |
strokeCap(SQUARE); point(100, y) |
drawn |
missing |
beginShape(POINTS); vertex(300, y); endShape() |
missing |
missing |
2.3.1 and 2.3.2 give the same results as 2.3.3. In Chromium 152 every row above is drawn, except strokeCap(SQUARE) on 2.3.3.
Possible directions
- Keep the line-cap approach, but make the offset large enough to survive float32 rounding, for example by scaling it with
|x|. This is a small change, but it does not help strokeCap(SQUARE).
- Draw the point shape itself (a circle, or a square for the square caps) and fill it with the stroke color, which is closer to what 2.3.0 did for
point().
I'm happy to work on a PR once there is a preferred approach.
Most appropriate sub-area of p5.js?
p5.js version
2.3.1, 2.3.2, 2.3.3 (2.3.0 works)
Web browser and version
Chrome 153.0.8010.53
Operating system
Windows 11 (where a student of mine first saw it), also reproduced on macOS 26.6
Steps to reproduce this
Steps:
Snippet:
What seems to be happening
PrimitiveToPath2DConverter.visitPointinsrc/shape/custom_shapes.jsdraws a point asmoveTo(x, y)pluslineTo(x + 0.00001, y)and relies on the line caps to make the dot. Canvas paths keep coordinates as 32-bit floats, and once|x| >= 256,x + 0.00001rounds back tox(Math.fround(256 + 0.00001) === 256). The segment ends up with zero length.Chrome 153 does not draw zero-length segments at all, which matches the canvas spec ("Prune all zero-length line segments from path" in the trace-a-path steps). A plain
moveTo(50, 30); lineTo(50, 30)with round caps draws nothing in Chrome 153, while Chromium 152 (Electron) still draws a dot for it, so this may not show up on older Chrome.Before 2.3.1 only
beginShape(POINTS)used this path. #8899 movedpoint()onto the shape system too, which is why plainpoint()broke in 2.3.1.It is the coordinate passed to
point()that matters, not where the point lands on screen:translate(-300, 0); point(400, 60);also disappears.A related case: with
strokeCap(SQUARE)(butt caps), a 0.00001 px line has no visible area, sopoint()draws nothing at any position, in both Chrome 152 and 153. In 2.3.0 it drew a circle.Each check below draws one point on a freshly cleared canvas and reads the pixel under it:
point(255, y)point(256, y)point(1000, y)translate(-300, 0); point(400, y)strokeCap(SQUARE); point(100, y)beginShape(POINTS); vertex(300, y); endShape()2.3.1 and 2.3.2 give the same results as 2.3.3. In Chromium 152 every row above is drawn, except
strokeCap(SQUARE)on 2.3.3.Possible directions
|x|. This is a small change, but it does not helpstrokeCap(SQUARE).point().I'm happy to work on a PR once there is a preferred approach.