[p5.js 2.0 Bug Report]: Tessellation of beginShape/endShape with multiple contours sometimes produces weird results
@avinxshKD is already working on this.
Since Oct 24, 2025.
- Dominant language
- JavaScript
- Stars
- 24k
- Forks
- 3.8k
- Avg merge
- 3d 16h
- Merged PRs (30d)
- 25
Description
Most appropriate sub-area of p5.js?
- Accessibility
- Color
- Core/Environment/Rendering
- Data
- DOM
- Events
- Image
- IO
- Math
- Typography
- Utilities
- WebGL
- Build process
- Unit testing
- Internationalization
- Friendly errors
- Other (specify if possible)
p5.js version
2.0.5, 1.11.10
Web browser and version
Firefox, Chrome
Operating system
MacOS
Steps to reproduce this
Steps:
- Use WebGL mode
- Draw a shape with two intersecting contours
- In one of the contours, make a vertex have one coordinate aaalmost equal to that coordinate of the previous, e.g. have x=1 and then x=1.00000001
The output of libtess is glitchy in this case:
| Without a similar coordinate | With a similar coordinate |
|---|---|
|
|
|
I debugged this and our vertices all look right going into libtess, and our GLU_TESS_COMBINE callback is working properly, so this is actually a bug within libtess. But libtess is a JS port of SGI C code from the 90s, I doubt they're actually going to fix this bug, and it's pretty subtle, so this feels like something we'll have to work around ourselves if we want to work around it at all.
Workaround for users
Basically if they're drawing a bunch of points, they have to add a check like this before drawing the points:
for (let i = 1; i < points.length; i++) {
const prev = points[i-1]
const next = points[i]
if (Math.abs(prev.x - next.x) < 1e-6) next.x = prev.x
if (Math.abs(prev.y - next.y) < 1e-6) next.y = prev.y
}
A fix for this probably would involve us doing that loop ourselves before tessellating a shape.
Should we fix this at all?
It's unlikely that a user would manually create problematic coordinates like this, but it's a lot more likely to happen when drawing contours automatically sampled from a font with font.textToContours() (which is how I ran into this just now!) So if we do a fix, we can maybe consider it a fix for textToContours usage.
Snippet:
function setup() {
createCanvas(400, 400, WEBGL);
}
function draw() {
const contours = [
[
[-3.8642425537109375,-6.120738636363637,0],
[3.2025188099254267,-6.120738636363637,0],
[3.2025188099254267,-4.345170454545455,0],
[-3.8642425537109375,-4.345170454545455,0],
[-3.8642425537109375,-6.120738636363637,0],
],
[
[-1.8045834628018462,4.177556818181818,0],
[-1.8045834628018462,-9.387784090909093,0],
[0.29058699174360836,-9.387784090909093,0],
...(
frameCount % 120 < 60
? [[0.2905869917436083,3.609374411367136,0]] // doesnt work
// ? [[0.29058699174360836,3.609374411367136,0]] // works
: []
),
[0.31044303036623855,4.068235883781435,0],
[0.38522861430307975,4.522728865422799,0],
[0.548044378107245,4.941051136363637,0],
[0.8364672032828204,5.2932224887960775,0],
[1.2227602871981542,5.526988636363637,0],
[1.6572258237923885,5.634502949876295,0],
[2.101666537198154,5.669034090909091,0],
[2.6695604948237173,5.633568761673102,0],
[3.0249619917436084,5.5625,0],
[3.4510983553799726,7.4446022727272725,0],
[2.8568950819856695,7.613138889205699,0],
[2.3751340936529037,7.676962586830456,0],
[1.8892600236717598,7.693181792704519,0],
[1.2922705720786674,7.649533731133848,0],
[0.7080836288276859,7.519788939617751,0],
[0.14854153719815422,7.311434659090909,0],
[-0.38643934048179873,7.00959666478984,0],
[-0.858113258144025,6.61653855366859,0],
[-1.25415732643821,6.1484375,0],
[-1.5108595282965422,5.697682732328092,0],
[-1.6824918355513252,5.207533878495854,0],
[-1.7762971052870198,4.695933154267308,0],
[-1.8045834628018462,4.177556818181818,0],
]
]
background('red')
push()
stroke(0)
fill('#EEE')
scale(15)
beginShape()
for (const contour of contours) {
beginContour()
for (const v of contour) {
vertex(...v)
}
endContour()
}
endShape()
stroke(0, 255, 0)
strokeWeight(5)
beginShape(POINTS)
for (const contour of contours) {
for (const v of contour) {
vertex(...v)
}
}
endShape()
pop()
}
Live: https://editor.p5js.org/davepagurek/sketches/mvVHjXVjM
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.