Hacker News new | past | comments | ask | show | jobs | submit login
New Bézier curves for vector graphics (ad8e.pages.dev)
181 points by ad8e on Sept 10, 2023 | hide | past | favorite | 57 comments



"I don't know of a reasonable way to guess the right location."

1. Drag curve handles out to 1/3 of the length of the curve segment they control.

2. Eschew s-curves between two control points.

3. Don't turn more than about 90º between two control points.

I learnt this about a year into what is now a 23-year career as an Illustrator artist. It has served me well. You will note that the first interactive example on this page is asking you to violate rule 2.

"Béziers can't represent circles. If you try to approximate one by hand, it'll look lopsided."

If you try to draw a circle by hand, it'll look lopsided too. Any pro traditional artist will have a compass and a few circle templates in their kit. In Illustrator there's an ellipse tool one keypress away. I've been drawing at a pro level for about thirty years and while I can probably pick up a pencil and draw a better circle in a couple quick arm motions than you can in a bunch of little sketchy attempts, they're still nowhere near perfect, and they don't need to be.

I also draw about 90% of my paths with the Pencil tool, which just abstracts worrying all of this way. Unless you are doing very geometric work, or require the absolute minimum possible number of points, I feel that using the Pen tool to draw everything is about as sensible as writing a program entirely in assembly language. And if I do need to work under a tight point count constraint, then I will still draw it with the Pencil, then pull out Astute's Smart Point Removal tool, which does a great job of optimizing the heck out of my paths, much better than Adobe's tools for this.


> I feel that using the Pen tool to draw everything is about as sensible as writing a program entirely in assembly language.

As someone who's only ever used the pen tool, I feel mildly attacked!

Jokes aside, I think I agree with you if you have a tablet. I used to draw with a mouse back then, so I'd basically sketch on paper, take a picture or scan it, then use my mouse to pen over it. Sometimes I'd skip the sketching/importing steps, depending on what I'd work on.

Later when I could afford a tablet, I mostly left Illustrator/Inkskape behind in favour of just using Krita for most things. However, if I'm making a vector illustration today, I still use the pen tool... and the mouse, even if I have the tablet. If I were to work on something complex enough, I'd probably sketch it in Krita though, and then use the good'ol pen and mouse...

I'm by no means a professional artist, just do this as a hobby though. So, if my workflows outlined here have mortified you; apologies for that.


The workflow you outline is where I started! It's not one I'd want to use any more, now that I can casually make Illustrator automatically do a lot of work for me, then come back in and refine a few places manually. But it was a good place to begin.

https://egypt.urnash.com/illustratorbook/


I can perhaps refine (1) and provide some insight in support of (2).

It does make intuitive sense for handles to be 1/3 of the length of the curve, as that makes the "speed" close to constant, but this is not the smoothest possible choice in general. In particular, it's not the best approximation to a circular arc, which by most reasonable definitions is the smoothest possible curve. I did the math[1] and found that there's a parabola around each endpoint that does result in an accurate arc approximation, and in fact may be easier to apply as it doesn't move around as the length of the curve changes. Rather, each of the parabolas can be applied independently.

Evidence in favor of this is O(n^5) accuracy scaling to approximate Euler spirals (which are also a good candidate for "smoothest possible curve" depending on the way you define that). I suspect, but haven't yet demonstrated, that there's some variational sense in which this choice is optimum, or at least to a first order approximation.

You can think of cubic Béziers as forming a four-dimensional parameter space (the parameters can be accounted as the lengths and angles of the control handles; in this scheme, the positions of the endpoints are not counted). By applying a rule such as 1/3 arc length, or falling on a parabola, that reduces it to a two-dimensional space (same dimensionality as quadratic Beziers, Euler spirals, and sections of rectangular elastica). I think two dimensions is too few, as it doesn't give you the ability to easily form superellipse shapes, a particular strength of cubic Béziers and quite handy for font design, as superellipse is extremely common in fonts. I think there may be some value in exploring a three-dimensional parameter space (which, among other things, is the count for general elastica) and have some ideas.

As for (2), the problem is that for s-shaped curves, cubic Béziers tend to put curvature maxima near but not exactly on endpoints. Since the curvature maximum is visually salient, you do better subdividing your curves so you can place them at joins. Other curve families, notably those based on elastica and Euler spirals, don't have this problem.

[1]: https://raphlinus.github.io/curves/2021/02/19/parallel-curve...


The ideal dimensionality of the parameter space depends on the jaggedness of the curve. Derivatives are useful when they stay constant over a stretch of time; when derivatives vary too much, it becomes more efficient to use more points of lower degree. This is the same calculation in other domains of approximation: numerical integration, DiffEq, and Taylor series.

For example, to draw rough surfaces, point-to-point lines are the most efficient way, with a ton of points. For industrial geometric shapes, lines and ellipses become efficient. As the smoothness of the curve goes up, more derivatives become valid. But sometimes those higher derivatives are not useful.

This is why the parent comment likes the Pencil tool; it's optimal for high variation, because it is a local (smoothed) control of position, the zeroth derivative. The cost is some loss of smoothness, which likely doesn't matter for her domain, since her hands move smoothly enough.

I think the Pen tool would be a more competitive alternative with a better control scheme. For example, a Pen tool with local control would unify the Pencil and Pen: letting you draw jagged curves by holding your mouse down, and letting you draw straight lines and smooth curves by clicking. There would be no interruption of flow, as you can use either method freely to continue a curve. They should inherently be the same tool anyway, just with different numbers of derivatives.


For example, to draw rough surfaces, point-to-point lines are the most efficient way, with a ton of points.

I usually just draw a quick simple line and tell Illustrator to rough it up for me. There's a lot of ways to do this; "use a custom brush" is a common one, so's "apply the Roughen effect". These will dynamically generate a buttload of virtual points in the vicinity of the basic path when it gets rendered; the editing view is still just a handful of points. Much easier to edit, much faster to draw. If I need precise, human-defined jagginess to a path, then I whip it out with the Pencil, and push it around with stuff like the Puppet Warp tool, which lets me drop a few pins into a complex set of paths, and distort it based on how I move those around.

Illustrator's Pencil tool actually performs a certain amount of smoothing on the raw positional input from the drawing tablet. There's a slider for how much it does this. I have it right in the middle of the range and it makes for a pretty nice compromise between catching every deliberate motion of my fingers/hand/arm across the tablet, and throwing away the little irregularities that I would be working hard to eliminate if I was working in pen and ink.


I think what you've done is mastered an unintuitive (or even counterintuitive) system. That's well and good, but it doesn't mean the system shouldn't be improved. It would make life no worse for you, and better for people with less experience, less time to experiment.


I don’t think they’re implying it takes 21 years to learn. I’m inexperienced and learned how to accurately follow paths with bezier curves using the same technique after watching a 10 minute Burt Munroy tutorial.


Correct. I have certainly learnt a ton more about how to manipulate vector art in the intervening years, and the set of tools I have available has expanded a lot - Adobe's added a lot of tools to Illustrator, and so has the Illustrator plugin ecosystem. But those three simple rules did a lot to make my Illustrator practice a lot faster.


Cool to see others working on this problem. I hope more people do.

Funnily I've seen a lot of programmers and math folks who express how truly, genuinely beautiful Beziers and the math behind them are. But I've never met an artist or graphic designer who didn't express some deep frustration at Bezier controls and how hard they are to work with.

There are even games[0] which make a mockery out of how hard Bezier controls are to use, where the game is purely using the controls.

Controls are just one side of the problem, in my view; the other side is that cubics are terrible for GPUs, they don't understand them - and I believe many of the best 2D graphics libraries today are not even fully GPU accelerated, e.g. Skia. There are folks working on compute shader-based approaches, where we try to shoe-horn this CPU-focused algorithm into GPUs and pray - but it still isn't really suitable.

The controls suck for artists, and the math sucks for GPUs. This is only true of cubics, if you restrict yourself to quadratics (although that brings other challenges), both the control issue goes away (you can just click+drag the curve!) and the performance issue goes away (quadratics are triangles, GPUs love them)

That's the summary of the talk[1] I gave at SYCL'22. In that talk, I didn't have time to present the downsides of my solution (which are real!) so if you watch it please keep that in mind - the talk is about the problem statement, not a solution. We are exploring a different solution today than what was presented in that talk. My overall point in there, though, is a solid one: vector graphics as they exist today suck for artists and GPUs alike.

The only reason we stick with vector graphics in their current form is because of SVG & compatibility with existing tooling. But isn't it crazy? We have new bitmap image formats all the time, and so few vector graphics formats.

In Mach engine[2] we're continuing to explore this space, end-to-end, from author tooling -> format -> rendering. I'm not claiming we have a perfect solution, we don't, but we're at least thinking about this problem. Kudos to the authors of this article for thinking about this space as well.

[0] https://bezier.method.ac/

[1] https://www.youtube.com/watch?v=QTybQ-5MlrE

[2] https://machengine.org


Postscript used cubic Béziers, but TrueType, specified some ten years later by Apple with the learnings from practical use of Postscript on Macs, opted to only support quadratics instead.

Donald E. Knuth seems to think pretty highly of this decision:

“The quadratic has the great advantage that there's a real cheap way to render them. You can make hardware to draw a quadratic spline lickety-split. It's all Greek mathematics, the conic sections. You can describe a quadratic spline by a quadratic equation (x, y) so that the value of f(x, y) is positive on one side of the curve and negative on the other side. And then you can just follow along pixel by pixel, and when x changes by one and y changes by one, you can see which way to move to draw the curve in the optimal way. And the mathematics is really simple for a quadratic. The corresponding thing for a cubic is six times as complicated, and it has extra very strange effects in it because cubic curves can have cusps in them that are hidden. They can have places where the function will be plus on both sides of the cubic, instead of plus on one side and minus on the other.

“The algorithm that's like the quadratic one, but for cubics, turns out that you can be in something that looks like a very innocuous curve, but mathematically you're passing a singular point. That's sort of like a dividing by zero even though it doesn't look like there's any reason to do so. The bottom line is that the quadratic curves that TrueType uses allow extremely fast hardware implementations, in parallel.”

https://lists.nongnu.org/archive/html/freetype-devel/2000-01...


And then OpenType added cubic bezier back in.... by embedding postscript font definitions.... Before they went one better and added support for embedding SVG for emojis.

(I ported a tiny TrueType renderer from C to Ruby, and looked at what it'd take to add OpenType support, since OpenType uses the same container format; font file formats look like they were designed by a drunk student as a prank)


Wow, I didn't know Knuth said that. I would've been 7 years old at the time - wild.


Knuth has been saying interesting things for a very long time. He began _The Art of Computer Programming_ project in 1962.


Yeah, I’m thinking that I met DEK before the parent poster was born (he told me that I would be able to be his student because I wasn’t taller than him. Spoiler: I was never his student).


those are both Bezier curves. They're just second vs. first order Bezier curves, but all the same math applies, and polybeziers are so much harder to work with when they're quadratic instead of cubic, it's not even funny.


> But I've never met an artist or graphic designer who didn't express some deep frustration at Bezier controls and how hard they are to work with.

That surprises me, because Illustrator (especially earlier versions) is all about Bezier curves, and in my experience it doesn't take long before you start to "think" like the Pen tool. I don't recall working with an artist who couldn't intuit how they worked after creating with them for a few weeks.


You can easily learn how to use them.

That doesn't mean they don't stop being frustrating.

I will commonly wish there was a method to change a curve in a single drag in some particular situation, rather than 20 drags of fiddling with beziers, trying to figure out if adding another control point is necessary or redundant.

Just because you figure out the intuition behind them doesn't turn them into an efficient way of achieving results. Because the intuition of beziers translates poorly to our innate human/artistic intuitions of curves.


> I will commonly wish there was a method to change a curve in a single drag in some particular situation…

If I understand what you want, you'd probably really dig the Curvature tool. https://www.youtube.com/watch?v=xzilL2zvldo


OMG yes. I had no idea that had been invented and added to Illustrator -- that's exactly what I've been looking for. Thank you so much!


That is exactly the type of user interface I am advocating for, I love that.

Give me that + fast/efficient GPU-animated keyframes of those curves, and I'm 100% sold.


Are Bézier curves with handles “worth it”? I've always found the easiest method for drawing curves to be, simply, “give me the (cubic) spline curve that goes through these points”. You place your points and continuity conditions determine the cubic, as described in https://mathworld.wolfram.com/CubicSpline.html .


It of course depends on what you need, what you’re doing. The cubic Bézier curves with handles are probably the best thing for animation curves, specifically because having handles allow you to break the continuity of the curve, and change direction suddenly. Animators need this when tweaking motion curves on a timeline. Think of abrupt changes in speed, like with collisions.

Splines with tangent handles are much better for font design as well, than splines without handles.

Splines defined by points and not tangents are useful for different reasons, and they’re not great if you want to have sharp changes of angle. You can do it by duplicating control points, but that causes some math mayhem in some situations.

In computer graphics people use the “Catmull-Rom” spline a lot, which is a type of interpolating spline that goes through the control points. https://en.wikipedia.org/wiki/Centripetal_Catmull–Rom_spline

People also use the B-spline as well, which is smoother and nicer than the Catmull-Rom spline, but it’s an approximating spline that doesn’t usually go exactly through the control points. https://en.wikipedia.org/wiki/B-spline

Both of these get used in CG for hair and fur - which is a good example of an application of curves that doesn’t require sharp angles along the splines.


That's exactly what I've always been curious about!

It seems vastly more intuitive to place points rather than adjust handles. (And set directions for endpoints if the curve is open.)

And obviously a practical tool will provide the capability to join separate cubic splines at sharp angles.

Does anyone know of a GUI drawing tool based on this? I've always wanted to experiment with it. Because I've always wanted to either confirm that it's a great idea that we should all be using instead of beziers, or else discover if there's an immediately obvious reason once you try it out that it's a terrible idea.


I have used this in some commercial software before (maybe Illustrator?); my experience was not positive. When you move a node, some not-so-close curves start wiggling, and you think, "I already set that part correctly, stop moving please". It behaves very poorly around rounded corners. Adding points causes the curves to shift, usually not how you want, and then you try to add more points, which causes more shifts, etc. Arc length-based interpolation might do better in this respect, as opposed to the (# of points)-based interpolation which I expect it used.

The alternative, which obeys similar principles, is the Pencil tool. This simply spams out a ton of points to match what you draw. https://news.ycombinator.com/item?id=37460009 mentions that these points can be capably reduced, which could serve your purpose.


It looks like the conclusion is "let's use rational Bezier curves instead of plain Bezier curves", in which case: you can, you just have more parameters to tweak now. Also calling this "new" is a bit disingenous given that rational Beziers have been around half a century now. They're useful, but if you only look at Bezier curves from the tooling side of things, you're going to miss the reason why we use them so much. And the biggest mistake in design software is having tools that actually let you work with the datatypes that your final product is going to end up using. Need a circle? Draw a circle based on a center point and a radius. Good tooling won't surface that fact that it's going to end up being a Bezier curve, it just lets you design with the primitives you need, and will take care of the conversion as needed when you export it to whatever format your deliverable needs to be.

Making people draw Bezier curves just because "the file format uses those" is by far the bigger problem here.


There are a few misunderstandings here. Rational Bézier curves are incidental in this article, and the conclusion is not that they are correct. They were just a convenient curve I used to express the main message of local control, and the article endorses looking for other curves that fit the properties.

The parameter count has not gone up; it's equal to or less than usual Bézier control handles, because I forced the parameters to take specific values.

The part that is "new" about the Béziers is the new formula that selects one specific Bézier out of all the possible choices. I think this linguistic accusation is silly; for example, if someone discovers a new rock, it would be fair to call it a "new rock" even though rocks have been discovered thousands of years ago.

These curves are also unrelated to the file format; the curves are designed to fit how the user thinks about curves rather than be computer-efficient. For the tooling point, I think you are agreeing with me while arguing; I agree that there's no reason the curve should match what is used in the final product, and some of the other curve choices I considered require a complex conversion step.


Maybe I'm not reading what you wrote, but what I'm getting from the writeup is not that you're describing a new set of curve constraints, not a new Bezier curve (even if we just go by the list of constraints you're trying to satisfy), so that doesn't feel like a linguistic accusation so much as a pretty important thing to call out?

In the analogy of rocks: we've certainly been discovering rocks thousands of years ago, but if you pick up the same rock that others have already picked up, from the same patch that we've been picking up rocks from for a long time, but using a different set of rules to decide how to pick the rock up, that's not a new rock. That's a new method.

So describing it as a new methodoly for finding appropriate Bezier curves, rather than finding new Bezier curves, would make it much more clear what you're doing. And new methodologies are always exciting.


This article is really stretching when the conclusion is smacking him in the face: "Use quadratic Beziers."

The original article points out that quadratic Beziers have most of the desirable properties with very few of the downsides.

It used to be that the issue was that you would have to use significantly more quadratic Beziers to approximate something that a much smaller number of cubic Bezier's could do. This was a big deal when a font file might clog up a floppy disk.

Now that we're slinging around gigabyte patch files. Do we really care?


There are these civilized curves

https://en.wikipedia.org/wiki/Non-uniform_rational_B-spline

which you never saw because patents kept them off the markets until Beziers were completely entrenched.


This is a nice post but not a valid Show HN - please see https://news.ycombinator.com/showhn.html.

I've taken "Show HN" out of the title now.


I was really hyped up by the beginning of the article, but it seems really miss the points with the conclusion.

I don't think it is easier to manipulate with the last two examples, and I am guessing no actual graphic artist has read this or play with this before you publish it. To think of ways to improve bezier curves for vector graphics, you need to fully contextualize your thinking about the use case; this is not an academic mathematical discussion after all. Based on my understanding, your finding has no mathematical value as Pomax pointed it out, it is not new, it is an old math with a few constraints that is pre-defined, based on your assumption of what graphic artist wanted most of the time, which I agree is a good direction.

I strongly suggest for anyone to try to make a better vector graphics tool, try to draw a letter S with the new approach as a test case, you can choose an existing font to match. And know existing vector graphics rules, here is a couple as example:

- add anchor points at the horizontal and vertical extrema of your paths

- control points should not cross path with one another

Curves that doesn't follow these rules are valid, fine mathematical curves, but graphic artists has practices this for years to rule out them as bad for the purpose of graphic design. Again, the goal is to find the more much smaller set of suitable curves from the infinite realm of mathematical possibilities, for the context of graphic design


The goals look quite similar to my hyperbezier explorations. There's an online demo of the first draft[1], and a Zulip thread on some progress toward a second draft[2]. The tl;dr is that I think I have the mathematics of the curve family, but I haven't finished the mapping between control points and the parameters of the curve family.

Both drafts have (exact) Euler spirals inside their parameter space, and thus circular arcs as well. I think that's a good criterion for a Bézier successor.

It's on the back burner for now, but I hope to get back to it, and am open to collaboration.

[1]: https://www.cmyr.net/blog/hyperbezier.html

[2]: https://xi.zulipchat.com/#narrow/stream/260979-kurbo/topic/H...


> Béziers can't represent circles. If you try to approximate one by hand, it'll look lopsided.

Many graphics algorithms (vector operations: scale, translate, rotate; raster operations like rasterisation and interpolation) specialise for straight lines (and hence also triangles), Bézier curves, circles, etc separately, rather than forcing everything to be a Bézier curve.


"Béziers can't represent circles" is not exactly wrong, but is not really the full picture.

Often you don't need to _represent_ a circle. TrueType fonts (quadratics) and OpenType fonts (cubics) can't mathmatically _represent_ a circle, either, but does that mean no font has circles in it? Sometimes an approximation is pretty damn good.

Also conics (rational quadratic Beziers), which Microsoft has a surprisingly good article on[0], can represent circles.

[0] https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user...


Fortunately fonts usually don't contain perfect circles anyway, because the designer will optically correct any circles so that they don't appear to bulge. Kabel is the closest font I found with circular formas; LineTo's Circular is also quite close but slightly taller than wider.


Fonts are supposed to contain perfect circles; try searching for "circle" in a Unicode character map. They only don't in practice because quadratic and cubic Bezier splines can't do them.


And they don't have to. The approximation of a circle with a bunch of cubic curves is so accurate [1] that you'd need to print a huge circle and then sit there with a measuring tape to be able to even tell it's not a perfect circle. Which is why "you can't draw a circle with Bezier curves" is only a mathematical "problem", it's not an actual problem.

[1] https://pomax.github.io/bezierinfo/#circles_cubic


It's a UI problem, not a mathematical problem. No set of curves can represent everything exactly, but they all can get close. The goal is just to make it easy to get close.

The computer can produce a near-perfect circle with Béziers for each 1/4 arc, and near-perfect circles are usually good enough. It's just inconvenient. It's also hard to manipulate the generated circle; the user might have a clear image of his head of the changed circle he wants, but pushing the control points to get there is not easy.

The mathematical "axioms" in the article are only attempting to provide a clean interface, so that the user can easily translate what is in his head to what the program creates. The circle axiom says, "The user often wants a circle, and also expects a circle, so let's produce the expected circle." There's no other mathematical purity involved.


I like using the "split tweak" method to do my curves. Converts polygons to curves. Works VERY well. Very intuitive, straightforward and ez. It's a variety of bezier.

Alg :

    given polygon P.
    For each vertex V in P.
        Get the midpoints of the 2 segs adjacent to V. M0 M1. Add those 2 points to the polygon.
        Get the midpoint of seg(M0, M1). M2. Move V to the midpoint of (V,M2).
Repeat 2 or 3 times or whatever. Each iteration increases smoothness.

And here's the code for that

https://github.com/johnalexandergreene/Geom_2D/blob/master/C...

There's a version of that for open curves too, elsewhere in that package .


The guy from the mach engine has also talked about issues dealing with Bézier curves and came up with a interesting set a primitives: Triangles, quadratic curves and semi-circles.

Mostly this is make it easier to do vector graphics on a gpu, which is why I'm interested in it, but I think it might be easier to understand.


I found the examples extremely easy to align with the target, but I've also been using Adobe Illustrator for over 20 years.


Just trying to align curves to targets was fun. Someone should build a whole game on this idea.



Obligatory links for anyone that is interested in learning more about Bézier curves:

https://pomax.github.io/bezierinfo/

https://pomax.github.io/bezierjs/

https://github.com/Pomax/bezierjs



Might I also add: https://youtu.be/aVwxzDHniEw?feature=shared Which works through them from first principles with beautiful animations.


I personally really like this video, but it's interesting how when I showed it to a group of CS undergrad students, they all loved the animations but performed poorly on a post-video quiz about the topic. I knew the content already, but I wonder if this video is really as educational as it appears to be.


Her other video on the subject https://www.youtube.com/watch?v=jvPPXbo87ds&t is far more interesting and informative imo.


good work. i've always found bezier curves impractical and overrated, using standard polynomial interpolations or more easily understood variants.


Do you have any publicly available code on github?


The source code is visible with Ctrl+U, I didn't minimize anything. The g9 use is pretty neat. It definitely deserves the shout-out I gave it.

I just now uploaded a worse C++ desktop version with saving and loading: https://github.com/ad8e/local-curves This desktop version is 5 years old. I think the web version is better. This github repo is only interesting if you want to copy code from it; it's not practical as a drawing tool.


Ok thanks. I will possibly try to port to SkiaSharp in the future to learn how your code works.


beautifully made. However I think one's intuition for where the control points go and what they do are very clear if you've ever taken calculus. The line segments control the direction and magnitude of the tangent to the curve at that position. If you understand that, then it makes the motivating problem go away, and all the challenge problems are easy to solve.


It's not as easy to visualize the tangent magnitude as you are suggesting, because the time parametrization makes the calculation fail - the curve doesn't travel forward at a constant rate. This is best seen with the second example: If the left handle is fully extended and the right handle is 0, the Bézier curve looks almost exactly the same as when the handles are reversed. Here's a picture: https://i.imgur.com/WkanN1G.png

The handle varies from 0 to full-strength, but the magnitude of the tangent vector stays constant. This means the handle doesn't decide the magnitude. Tracing the path in your head to visualize the changing tangent vectors would mean visualizing a competition between t^2, (1-t)^2t, and (1-t)^3, which I find difficult, even with some calculus knowledge.


This isn't true, and is obvious when you try to split a bezier without distorting its shape.

As a bezier is just repeated interpolations, the tangents and their lengths can be derived from the intermediate interpolations [1]. This means that if you split a bezier near an existing control point, the new point will have wildly unbalanced tangents on both sides, and yet, connect into the exact same cubic curve.

So both your intuition and your confidence in it are... wrong.

[1] https://i.stack.imgur.com/I9wKC.png


Interactive curves are primarily meant to be used by designers. They are a tool. When the tool is not intuitive, it’s not really a solution to say “designers should just take calculus and it makes the problem go away.”




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: