Skip to content

[p5.js 2.0+ Bug Report]: point() is not drawn when x >= 256 in Chrome 153 (2D mode, since 2.3.1) #9206

Description

@frank890417

Most appropriate sub-area of p5.js?

  • Accessibility
  • Color
  • Core/Environment/Rendering
  • Data
  • DOM
  • Events
  • Image
  • IO
  • Math
  • Typography
  • Utilities
  • WebGL
  • WebGPU
  • p5.strands
  • Build process
  • Unit testing
  • Internationalization
  • Friendly errors
  • Other (specify if possible)

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:

  1. Run the snippet below with p5.js 2.3.3 in Chrome 153.
  2. The points at x = 254 and 255 are drawn. The point at x = 256 is not.
  3. 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

  1. 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).
  2. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions