Skip to content

[p5.js 2.0+ Bug Report]: bezierOrder() accepts values outside its documented range, and 2D and WebGL then fail differently and silently #9079

Description

@harshiltewari2004

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.2 (p5.js Web Editor)

Web browser and version

151.0.7922.138 (Official Build) (arm64)

Operating system

macOS Tahoe 26.6.1

Steps to reproduce this

Steps to reproduce this

bezierOrder() is documented as taking 2 or 3, but the value is stored without validation. Values not in range reach the renderers intact, and the 2D and WebGL converters then handle them differently — none of the two reporting anything to the user.

The sketches below use console.log('bezierOrder() reports:', bezierOrder()) to show that the out-of-range value is stored rather than rejected or clamped.

Control: bezierOrder(3) renders the same curve in both renderers

function setup() {
  createCanvas(200, 200);
  background(220);
  noFill();
  stroke(0);
  strokeWeight(2);

bezierOrder(3);
beginShape();
vertex(20, 100);
bezierVertex(60, 20);
bezierVertex(100, 180);
bezierVertex(140, 20);
endShape();
}

Image

The same sketch with createCanvas(200, 200, WEBGL) and translate(-100, -100) after background():

Image

The translate(-100, -100) only aligns the WEBGL origin with the 2D one so the coordinates match. The two render identically, so anything that differs below is down to the order value and not the setup.

1. bezierOrder(4) in 2D — draws nothing

function setup() {
  createCanvas(200, 200);
  background(220);
  noFill();
  stroke(0);
  strokeWeight(2);

bezierOrder(4);
console.log('bezierOrder() reports:', bezierOrder());
beginShape();
vertex(20, 100);
bezierVertex(60, 20);
bezierVertex(100, 180);
bezierVertex(140, 20);
bezierVertex(180, 100);
endShape();
}

Result: blank canvas. No error, no warning. bezierOrder() reports 4.

Image

2. The same sketch in WEBGL — draws a different curve

function setup() {
  createCanvas(200, 200, WEBGL);
  background(220);
  translate(-100, -100);
  noFill();
  stroke(0);
  strokeWeight(2);

bezierOrder(4);
console.log('bezierOrder() reports:', bezierOrder());
beginShape();
vertex(20, 100);
bezierVertex(60, 20);
bezierVertex(100, 180);
bezierVertex(140, 20);
bezierVertex(180, 100);
endShape();
}

Result: a curve is drawn, but it ends near (100, 180) — the third of the five points. The last two control points are silently discarded. Again no error or warning.

Image

3. bezierOrder(1) — silent in 2D, throws in WEBGL

Both sketches again with bezierOrder(1).

In 2D: blank canvas, nothing logged beyond the order value.

Image

In WEBGL:

TypeError: Cannot read properties of undefined (reading 'map')
  at Shape.arrayScale
  at Shape.evaluateQuadraticBezier
  at PrimitiveToVerticesConverter.visitBezierSegment

Image

The friendly error that follows points at a line inside the bundled p5.js and suggests checking a variable the user never wrote. Nothing in the message mentions bezierOrder.

Summary of observed behaviour

  2D WebGL
bezierOrder(4) draws nothing, silently draws a quadratic through the first 3 points, silently
bezierOrder(1) draws nothing, silently TypeError from p5 internals

The difference between the two renderers comes from the shape of the code rather than any choice of it. The 2D switch has a natural do-nothing path when no case matches, therefore the segment is skipped. The ternary has no third branch, so anything that isn't 3 is actively evaluated as a quadratic — with the extra control points dropped by the destructure at order 4, and with a missing one at order 1 causing the TypeError.

Notes

There look to be a few possible directions here — validating in bezierOrder(), emitting a friendly error, or adding a default: to both converters — and they differ quite a bit in scope, so I haven't assumed one.

I also noticed custom_shapes.js carries a // TODO shapes refactor comment; if this is already covered by work in progress, happy to close this.

Happy to fix this myself once an approach is agreed on.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions