Repository navigation
Add arcVertex() for creating arcs with beginShape()/endShape() #6459
Description
Increasing Access
This feature increases access in two main ways:
- It addresses an inconsistency that may be an obstacle for beginners.
- It allows the user to perform common tasks with less mathematical knowledge.
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
- Internalization
- Friendly Errors
- Other (specify if possible)
Feature request details
Proposal
Add arcVertex() to the set of vertex functions in p5, to address a limitation of beginShape()/endShape().
The problem
Two of p5’s curve-vertex pairs are incomplete. In the table below, asterisks indicate missing items.
| p5 curve | p5 vertex | |
|---|---|---|
| line/polyline | line() |
vertex() |
| quadratic Bézier | quadratic()* |
quadraticVertex() |
| cubic Bézier | bezier() |
bezierVertex() |
| Catmull-Rom spline | curve() |
curveVertex() |
| circular/elliptical arc | arc() |
arcVertex()* |
Of the missing items, arcVertex() is the most important. Arcs are the only type of SVG subpaths not supported by p5’s beginShape()/endShape(). Without them, p5's most powerful shape-making feature cannot make some of the most basic shapes (e.g. lines and Bézier curves can only approximate circles). This leads to complications for both users and developers.
The solution
Provide a new function called arcVertex() based on SVG’s arc command. Applications include the following:
- Rounded corners: Allow users to round corners of polygons (not just rectangles) without approximations.
- Shape objects: Retain exact data for built-in and custom shapes in a common format usable by
beginShape()/endShape(). - SVG paths: Work with SVG paths by translating SVG path commands directly to p5 vertex commands.
Specification of arcVertex()
The following may serve as a draft reference page and usage tutorial.
Description
Used to draw an arc along a circle or ellipse (oval), from one vertex (point) to another. The arc may be drawn along any ellipse, even one that’s been rotated. (If the ellipse is too small to connect the two vertices, its size is automatically adjusted.)
The first vertex is specified with vertex(). The second vertex is specified with arcVertex(). Both are specified within beginShape() and endShape(), with no parameter passed to beginShape().
The arc itself is specified by indicating the shape and rotation of the ellipse (w, h, and angle), together with its type (MINOR or MAJOR) and its direction (COUNTERCLOCKWISE or CLOCKWISE).
If DEGREES is passed to angleMode(), angle may be specified in degrees; otherwise, angle should be specified in radians. If RADIUS is passed to ellipseMode(), the shape parameters are interpreted as half of the width and half of the height: arcVertex(20, 50, ... ) results in an arc drawn along an ellipse of width 40 and height 100.
Usage
beginShape();
vertex(x1, y1);
arcVertex(w, h, angle, type, direction, x2, y2);
endShape();
Syntax
arcVertex(w, h, angle, type, direction, x2, y2)
Parameters
| Name | Description |
|---|---|
| w | Number: width of ellipse along which arc is drawn |
| h | Number: height of ellipse along which arc is drawn |
| angle | Number: angle by which ellipse is rotated relative to x-axis |
| type | Constant: either MAJOR or MINOR |
| direction | Constant: either COUNTERCLOCKWISE or CLOCKWISE |
| x2 | Number: x-coordinate of ending vertex |
| y2 | Number: y-coordinate of ending vertex |
Tutorial
Related issues
- Rounded corners
- Shape objects
- SVG paths
- Add first class support for SVG imports and exports #4630
- Font paths to points #844 (suggests a complementary path-to-vertices feature)
- Dealing with SVGs #458

Activity
welcome commentedon Oct 7, 2023
Welcome! 👋 Thanks for opening your first issue here! And to ensure the community is able to respond to your issue, please make sure to fill out the inputs in the issue forms. Thank you!
Qianqianye commentedon Oct 14, 2023
Thanks @GregStanton for the suggestion. I'm inviting the current p5.js Core Stewards to this discussion @limzykenneth, @davepagurek, @chihyungchang, @teragramgius, @tuminzee, @Zarkv, @robin-haxx, @Gaurav-1306. Please feel free to leave your comments about this feature request. Thank you!
Garavitey commentedon Oct 14, 2023
Great suggestion.
I would like to work on this one. Let me get back with details of implementation.
GregStanton commentedon Oct 14, 2023
Amazing! Thank you so much @Gaurav-1306! And thank you to @Qianqianye for bringing the others into the conversation!
Verbal version of the tutorial
In case it helps anyone, I'll elaborate slightly on the tutorial. We want to draw an arc along the specified ellipse, from the first vertex to the second vertex. But we need to decide how to do that. We can start by imagining moving the ellipse onto the two vertices. There are two ways to do this; in the example shown, we get one copy of the ellipse attached from below and one attached from above. The vertices divide each ellipse copy into two arcs (major and minor). This means that there are four possible arcs. The
typeanddirectionparameters allow the user to specify which one they want (e.g. the minor clockwise arc is one option). Here's a quick p5 sketch that shows how the type and direction parameters allow you to specify four possible arcs (with different colors for each arc).Specification for out-of-range parameters
It seems like a good idea to be consistent with how the SVG specification handles parameters that are out of range. This comes from the W3C Candidate Recommendation for SVG 2.
I hope this helps!
davepagurek commentedon Oct 14, 2023
I think this makes sense as a way to increase consistency between modes of drawing shapes.
Do you have thoughts on the current API, based on SVG path arc commands, vs something more like the vanilla J's canvas
arcToAPI? https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d#elliptical_arc_curve The API for this one seems a bit more approachable at first glance (although your naming is much clearer than the flag names in the SVG spec!)GregStanton commentedon Oct 15, 2023
Thanks for your feedback @davepagurek! I'm glad you like the naming. I'm also glad you asked about other APIs. I asked myself the same question, and I think it's good to document the rationale here.
The problem with SVG's arc command, and how to mitigate it
It's commonly acknowledged that SVG's arc command is not the simplest. Yet, it does work, and we can mitigate any difficulties. The friendlier API I proposed should help. It should also be possible to improve the graphic tutorial I shared.
The problem with canvas's
arcTo(), and why we can't mitigate itA circular arc made with
arcTo()may end at an unspecified point. (Really,arcToward()is a more accurate name thanarcTo().) This conflicts with p5's functions, which are explicitly vertex based1:quadraticVertex(),bezierVertex()etc. all have "vertex" in the name, and the eponymous vertex is always represented by the final parameters.The problem with canvas's
ellipse(), and why we can't mitigate itThe native canvas API also has a method that creates an elliptical arc as a sub-path. It's simply called
ellipse(). However, its API has the same problem asarcTo()'s.2The benefits of SVG's arc command
SVG's arc command is vertex based, so it's consistent with p5's commands. By adopting a version of it, p5 is not just internally consistent, but it's also consistent with all of SVG's path commands.3 This has benefits for both users and library developers. Users familiar with SVG will immediately understand how
arcVertex()works, and library developers should be able to directly translate SVG path commands to p5 vertex commands.Footnotes
The
curveVertex()function of p5 introduces a subtle variation, in which the vertex is actually a control point (it guides the curve, but the curve does not pass through it). Nonetheless, with a separate function call, the user is able to specify where the curve will end. ↩The SVG arc command and the canvas
ellipse()method implement two different parameterizations of elliptical arcs. The the SVG implementation notes helpfully refer to these as the endpoint parameterization and the center parameterization, respectively. I thought a little about whether a simpler endpoint parameterization is possible, but I'm not sure if it could be simple enough to justify diverging from both the canvas and SVG APIs. ↩Internal consistency is actually cited in the SVG implementation notes as a reason for the design of its arc command. The notes are clearly written and address the same issue that we face. ↩
davepagurek commentedon Oct 15, 2023
That makes sense. In the MDN example, they also follow up arcTo with lineTo to ensure it always ends at the target point. That might be a way of using an API like the native canvas one while still preserving the quality of ending at the specified point?
Aside from the API of arcTo appearing simpler, I'm mostly considering it further because I assume we'll have to end up translating our API into an arcTo command for 2D mode anyway. Although it'll have to be turned into line segments for WebGL, so we'll be doing that part from scratch regardless. I don't have a strong preference, so if there are more issues with a combined arcTo + lineTo, I'm happy to go with the API that you suggested!
GregStanton commentedon Oct 15, 2023
@davepagurek I really appreciate you helping to vet this idea! I think it's always good to thoroughly vet an addition to an API, especially a core feature like this.
I'll respond with some additional downsides of
arcTo()that I see, followed by one approach that may address your concern about the implementation ofarcVertex().Downsides of
arcTo()Here are a few issues in addition to it not ending at a specified point:
lineTo(), since the arc may need to be connected to the most recent path point with a line segment. So, it's not a curve primitive in the same way that a pure circular arc is.In general, I think
arcTo()is mainly provided as a more convenient way to round corners. Its behavior can be achieved in principle with canvas'sellipse()andlineTo()methods. The more general, primitive method isellipse(), which actually draws not just ellipses but also elliptical arcs. My feeling is that the priority is to add general primitives first.2Implementing
arcVertex()Instead of using
arcTo()for 2D mode, one option is to convert the endpoint parameterization of SVG's arc command to the center parameterization of canvas'sellipse(), and then draw it with canvas'sellipse().3 For the mathematical details on this exact conversion, see the SVG implementation notes. The authors of the SVG spec anticipated the need to convert to other APIs.As always, I'm eager to hear feedback on any of this!
Footnotes
For example, the p5.teach add-on library by @two-ticks adds a dependency (anime.js) in order to animate typeset math expressions in the style of Manim. It uses MathJax to convert the expressions to SVG, which is then animated with anime.js. I suspect this requirement could be satisfied with p5 alone if it were possible to reproduce SVG paths with
beginShape()/endShape(). I'm very curious to hear others' thoughts on this. ↩If we want to add a utility function that creates composite paths like
arcTo(), its convenience would need to be weighed against the complication it introduces: it wouldn't correspond neatly to any p5 curve primitive. The convenience might well outweigh that complication! But it's something to consider. ↩When I was looking into this originally, one thing that surprised me is that p5's own
arc()andellipse()are not implemented with the canvas'sellipse(). The implementation approximates the ellipse with Beziér curves. Maybe this was easier to use with WebGL, since the Beziér curves had already been adapted for that? ↩davepagurek commentedon Oct 16, 2023
Thanks for the link, this will be helpful for implementing later! It looks like
ellipse()will be able to do what we need it to.This is a good point. Do you think we can make a version of the API where the elliptical aspects of the command come last and are optional, so that if they're missing we can default them to circular arcs? I assume that will likely be the most common use.
I'm actually not sure why the 2D mode uses Bezier paths. The WebGL mode version just uses trig functions.
GregStanton commentedon Oct 17, 2023
Replying to #6459 (comment) by @davepagurek:
Sure thing! I'm glad that helped.
The
arcVertexAPI that I proposed accommodates the circle case in the same way that p5'sarcdoes. As in the first example of the p5 reference page forarc, the user can create circular arcs by choosing the width and height parameters to be equal. I think it's nice to be as consistent as possible, so this seems like a good solution to me.The only other option that's obvious to me is to do something like p5's
ellipse. In that case, it's possible to omit the height parameter, in which case it works just likecircle, since the height is automatically set equal to the width. If we try this witharcVertexby moving the width parameter to the end, we'd introduce inconsistencies. Most significantly,arcVertexwouldn't end in vertex parameters like p5's other vertex functions.I got curious, so I did a little digging. It looks like the use of Bézier curves in p5's 2D implementation of
arcandellipsedates to p5's addition ofellipseon July 4, 2013. At that time, the canvas didn't have a nativeellipsemethod.1Would it make sense to create a separate issue to update p5's implementation of
arcandellipse, as part of modernization efforts? The current implementation is complicated enough that the source comments include a link to a paper on the underlying math; using the canvas's nativeellipseshould be a pretty significant simplification.Footnotes
According to MDN's browser compatibility table for CanvasRenderingContext2D,
bezierCurveTowas implemented in browsers as early as 2005, whereas theellipsemethod didn't appear in any of the listed browsers until November 2013. ↩davepagurek commentedon Oct 17, 2023
I think that all makes sense, thanks for bearing with me and fur such thorough explanations! I think this API looks good to me then.
For the 2d implementation of ellipse, making another issue for that would be great, thanks!
GregStanton commentedon Oct 18, 2023
Replying to #6459 (comment) by @davepagurek:
Absolutely! I'm glad I'm not the only one considering the design from various perspectives.
Done: #6485
Do you have a recommendation for the next step? I'm not sure if @Gaurav-1306 has been following the discussion, but they expressed interest in working on the implementation. Hopefully, our discussion will help with that. Here are the most relevant parts:
Garavitey commentedon Oct 19, 2023
Hey I have been following your discussions and would still like to implement this.
Let me understand all that you guys discussed and get back with the implementation details.
11 remaining items
Garavitey commentedon Nov 17, 2023
Thanks for the update @GregStanton, i will work on that issue and then as you said will come back for the arcvector.
GregStanton commentedon Jan 27, 2024
Update: Oh, wow. I just had a new idea for a different
arcVertex()API that would be more consistent with #6766.Specifically, we should be able to let the user specify an elliptical arc with commands as simple as
arcVertex(x, y). They'd just need to specify where they want it to start and end, along with three intermediate points that they want the arc to pass through. Mathematically, that data is enough to uniquely determine the arc passing through those points. Altogether, it'd look like this:(Just for now, I'm ignoring the 3D case and texture coordinates, for simplicity.)
This would be a very nice simplification, and if we adopt the proposal in #6766, it'd mean that
arcVertex()would take the same input as all the other vertex functions. We'd need to think through the implications, though. Some initial questions to consider:davepagurek commentedon Jan 28, 2024
I think this is a cool idea, I like the symmetry it has with other APIs! Maybe for comparison, how would it look to draw a rounded rectangle corner with this API? Does it offload a lot of math onto users to generate the three points in a case like that?
Also, since
quadraticVertexgenerally starts with a regularvertex, would your example be something like this to match?GregStanton commentedon Jan 31, 2024
Thanks for your feedback @davepagurek! I'll try to answer your questions concisely.
First question
Task 1: Round the corner of a rectangle
The original API seems easier to use in this case, as we’d expect, but it's still manageable with the new API for users who know a bit of math. The essential lines of code in each case are copied below, from a couple of quick sketches I made. (The second sketch just uses the
point()function to visualize points that would be passed toarcVertex()if the new API were implemented.)Original API:
arcVertex(d, d, 0, MINOR, CLOCKWISE, x + d / 2, y);[full sketch]New API:
arcVertex(cX - r * cos(i * dt), cY - r * sin(i * dt));[full sketch]In general, when the user is already thinking of an ellipse in terms of parameters like width, height, and rotation angle, the new API will require them to use extra math to generate points along that ellipse.
Task 2: Click on points, and generate an ellipse that passes through them
This would be simple with the new API, but for most users, it would be prohibitively difficult with the original API.
Summary: Although the new API offloads more math in a common use case, it makes it more likely that users will be able to accomplish both tasks above.
Second question
For the sake of this discussion, I'm assuming we'll implement the proposal for the new vertex function API. In that proposal, there is no
quadraticVertex(), sincebezierVertex()can be used for Bézier curves of all orders. Also, in that proposal, it's no longer necessary to mix commands to create a single primitive (e.g. all Bézier curves can be created using onlybezierVertex()commands and novertex()commands, just as Catmull-Rom splines can already be created entirely withcurveVertex()commands); for details, see the third problem in the list of ten problems solved by that proposal. In the same way, the idea here is to be able to create arcs using onlyarcVertex()commands.Another possible benefit
With the new API for
arcVertex()and the API in #6766,vertex()works with any number of vertices greater than one,bezierVertex()works with any number of vertices greater than two,curveVertex()works with any number of vertices greater than three, andarcVertex()could actually work with any number of vertices greater than four! When more than five vertices are specifed toarcVertex(), we could fit the points with an approximating arc. This is an important task in computer vision, so there’s plenty of literature on it. For example, based on a quick glance, this paper may provide a good solution.Edit: Added the
vertex()case (supports any number of vertices greater than one). Note that with the proposal in #6766, we no longer need to usevertex()to start a new primitive like a Bézier curve, so I don't think we'd ever call it just once.davepagurek commentedon Feb 1, 2024
For the first question, it seems like we won't really be able to handle both use cases in the same API cleanly, and neither choice would be a regression, so I'm good going with either option.
For the second question, I think I may have missed some details about connected segments of different types, so I've left a comment on the vertex function proposal with more info there. The main concern is that by having variable numbers of function calls per segment, it requires something else to mark the start/end of segments (and I think
begin/endContourin its current form describes something else, so it'd mean having a separate set of markers for separate paths that clip each other with winding order than our markers to separate segments.) I like the idea of a closest-fit, although it has the same issue of requiring markers. Anyway, we can talk about that more on the other PR; as long as we're consistent with arc vertices then we're good!GregStanton commentedon Feb 1, 2024
Thanks @davepagurek! I'll respond to your points and summarize some of the discussion so far.
arcVertex(x, y)vs.arcVertex(w, h, angle, type, direction, x2, y2)Either way, it will at least be possible to create elliptical arcs with
beginShape()/endShape(), so both are an improvement over the current API. I'm currently leaning toward thearcVertex(x, y)API.Benefits of
arcVertex(x, y)Here's an updated list of benefits, including some of the ones I mentioned above:
vertex()works with any number of vertices greater than one,bezierVertex()works with any number of vertices greater than two,curveVertex()works with any number of vertices greater than three, andarcVertex()could work with any number of vertices greater than four!)arcVertex(x, y)for the starting vertex andarcVertex(w, h, angle, type, direction, x2, y2)for the rest of the segment, in order to avoid having to mix vertex types for a single primitive (Problem 3 in #6766). (We could allow mixing just for arc segments, but that would be an inconsistency, since the hope is to eliminate mixing for all the other segment types.)It'd be nice to avoid having to do the extra math for rounded corners, but right now, I'm thinking these other points are pretty compelling. And, at least it'll be possible to make rounded corners with elliptical arcs; in the current version of p5.js, it's not possible at all.
Disambiguating segments
I replied about this point in #6766. Thanks!
Closest fit
Glad you like the idea! Regarding distinct markers for (a) distinguishing primitives (e.g. segments) in composite shapes and (b) distinguishing contours, I think we've found a solution in the discussion on #6766.
GregStanton commentedon Feb 2, 2024
Reminder: This p5.js tutorial opens by saying "This short tutorial introduces you to the three types of curves in p5.js: arcs, spline curves, and Bézier curves." In the summary, it specifies that "You can’t make continuous arcs or use them as part of a shape." This is something we'd want to update.
TheWhoove commentedon Jul 17, 2024
Any progress to push this forward? It would be so useful.
limzykenneth commentedon Jul 18, 2024
@TheWhoove We currently plan to implement this feature along with larger vertex refactor in p5.js 2.0. What can be helpful would be to work on a potential proof of concept in the
dev-2.0branch so some of the larger details can be worked out before we confirm the implementation.SableRaf commentedon Apr 4, 2025
There is a similar issue on the Processing repository here: processing/processing4#310
@limzykenneth I'd be curious to know more about the proposed vertex refactor to see if that is something we should consider for Java/Kotlin as well.
GregStanton commentedon Apr 5, 2025
Hi @SableRaf! Thanks for bringing that Processing issue to our attention! I don't think I was aware of it when I originally made this proposal. I think it's a great sign that the feature is being requested for both p5.js and Processing. That's an extra indication that it's a natural addition.
I haven't had time to look at the issue you shared in detail, but I glanced through it, and I'll share a few points that will hopefully clarify some things. If there's anything else that I can clarify, just let me know.
arcVertex()easier to implement). The refactor has been completed in the dev-2.0 branch, in the sense that it's functional and has been merged, with tests passing. A cleanup phase is still planned, along with some internal improvements and documentation updates. If you'd like, I can ping you when that's all finished. For now, you can get a fairly up-to-date sense of the solution approach from this comment. The main component is a newp5.Shapeclass, which we will likely expose to users in the long run (the plan is for it to be significantly smaller than Processing's PShape, although we did take inspiration from that).arcVertex()yet, I think we're going to go with thearcVertex(x, y)syntax. As I mentioned, this means we'd create an arc by specifying five vertices for it to pass through.arcPoint(),arcTangent()It was pointed out in the issue you shared that we may need to introduce these functions as well, for the sake of consistency with the corresponding functions for Béziers and splines. I'm making a note of this here, as a reminder to look into this. Again, thanks for sharing! That was very helpful.
P.S. I have a high-level implementation plan, as well as some thoughts about the 3D case that I could also share, if you're interested. I'd just need to clean up my notes a bit before posting them on GitHub.
SableRaf commentedon Apr 5, 2025
Thanks for all the context, @GregStanton! Please feel free to ping me when the cleanup phase is done. It’s inspiring to see how p5.js is reimagining things!
Add arcVertex() for elliptical arc segments in custom shapes
Add arcVertex() for elliptical arc segments in custom shapes