Every smooth curve you see on a computer screen - every letter in this font, every icon in your interface, every path in a vector illustration - is built from the same mathematical foundation: Bézier curves. Named after French engineer Pierre Bézier who developed them for automotive design at Renault in the 1960s, these curves have become the universal language for describing smooth shapes in computer graphics.
But Bézier was not alone in this discovery. At almost exactly the same time, Paul de Casteljau was developing identical mathematics at Citroën. The algorithms we use today bear his name, while the curves carry Bézier's - a quirk of publication timing and corporate secrecy. De Casteljau's work remained classified as a trade secret until years after Bézier had published. This parallel invention speaks to the fundamental nature of these curves - they are not arbitrary constructions but rather the natural mathematical solution to the problem of describing smooth shapes with a small number of parameters.
Understanding Bézier curves is essential for anyone working with digital graphics, typography, or design software. When you use the pen tool in Illustrator, adjust a curve in Figma, or examine a font's glyph outlines, you are directly manipulating Bézier mathematics. Even if you never implement these algorithms yourself, understanding the underlying principles will make you a more effective designer and help you troubleshoot the inevitable quirks that arise when curves misbehave.
The problem of describing curves
How do you tell a computer to draw a curve? This seemingly simple question has no obvious answer. You could specify every point along it, but that would require infinite data for a truly smooth curve - and how would you know which points to choose? You could use mathematical functions like parabolas or sine waves, but most interesting shapes do not fit such simple formulas. The letter 'S' is not a sine wave; the outline of an apple is not a parabola.
Early computer graphics struggled with this problem. Engineers tried storing curves as lists of coordinate pairs, but files became enormous and scaling was problematic - zooming in revealed the jagged truth of finite point lists. A circle stored as 100 points looks smooth at small sizes but reveals its polygonal nature when magnified. They tried polynomial equations, but fitting curves to desired shapes required solving complex systems of equations, and even small adjustments to one part of the curve could cause unpredictable changes elsewhere.
Bézier curves solve this problem elegantly. Instead of describing the curve directly, you specify a small number of control points - typically three or four. The curve is then defined as a mathematical function of these control points, producing a smooth, predictable shape that designers can intuitively manipulate. Move a control point and the curve follows in a natural, predictable way. The mathematics guarantees smoothness while the control points provide creative freedom.
Linear interpolation: the foundation
To understand Bézier curves, we must start with the simplest case: a straight line between two points. Given points P₀ and P₁, any point on the line between them can be written as a weighted average: P(t) = (1-t)P₀ + tP₁, where t ranges from 0 to 1. When t=0, you get P₀; when t=1, you get P₁; when t=0.5, you get the midpoint. This is not just abstract mathematics - it is the foundation upon which all Bézier curves are built.
This formula is called linear interpolation, or 'lerp' in graphics programming. The parameter t acts like a slider: at t=0.25, you are one-quarter of the way from P₀ to P₁. The weights (1-t) and t always sum to 1, ensuring the result stays on the line segment. This 'partition of unity' property is crucial - it means the interpolated point is always a valid weighted average, never extrapolating beyond the control points.
// Linear interpolation (lerp) - the foundation of all Bézier curves
function lerp(p0: Point, p1: Point, t: number): Point {
return {
x: (1 - t) * p0.x + t * p1.x,
y: (1 - t) * p0.y + t * p1.y
}
}
// As t goes from 0 to 1, this traces a straight line from p0 to p1
// The beauty is in its simplicity - and its power when applied recursivelyWhat makes linear interpolation powerful is that it works component-wise. We interpolate x-coordinates independently from y-coordinates. This extends naturally to 3D (add z) or even higher dimensions. It also means that any property that can be represented numerically can be interpolated: colors, opacity, scale, rotation angles. The same mathematical operation that draws lines also enables smooth animations and gradient transitions.
Quadratic Bézier curves
A quadratic Bézier curve uses three control points: P₀, P₁, and P₂. The curve starts at P₀ and ends at P₂, with P₁ influencing its shape without lying on the curve itself. This off-curve control point is what gives Bézier curves their characteristic behavior - it 'pulls' the curve toward itself without the curve actually passing through it (except in special cases).
To find a point on the curve for a given t, we apply linear interpolation twice - a process that reveals the elegant recursive structure at the heart of all Bézier curves. First, interpolate between P₀ and P₁ to get an intermediate point A. Then interpolate between P₁ and P₂ to get intermediate point B. Finally, interpolate between A and B to get the actual point on the curve. As t varies from 0 to 1, this process traces out a smooth parabolic arc.
Interactive Cubic Bézier Curve
De Casteljau's Algorithm: At t=0.50, linearly interpolate between each pair of points recursively until one point remains. The cream point shows B(t) on the curve.
The geometric interpretation is beautiful: imagine the two line segments P₀P₁ and P₁P₂. Place a point on each segment at the same proportional position t. Connect these two points with a new line segment. The point at position t on this new segment lies on the Bézier curve. As t slides from 0 to 1, this construction sweeps out the entire curve. This visualization, which you can see in the interactive diagram above, makes the curve's behavior intuitive even without understanding the underlying mathematics.
De Casteljau's algorithm
This recursive interpolation process is called de Casteljau's algorithm, named after Paul de Casteljau who developed it independently of Bézier in 1959. For a curve with n+1 control points, the algorithm performs n levels of interpolation, reducing the number of points by one at each level until a single point remains - the point on the curve at parameter t.
The algorithm's elegance lies in its generality: the same simple operation (linear interpolation) applied recursively produces curves of any degree. A quadratic Bézier requires two levels of interpolation. A cubic requires three. A degree-10 curve requires ten. The complexity scales linearly with the degree, making it practical to compute curves with many control points.
// De Casteljau's algorithm for any degree Bézier curve
function deCasteljau(points: Point[], t: number): Point {
// Base case: single point is the result
if (points.length === 1) return points[0]
// Recursive case: interpolate between adjacent pairs
const newPoints: Point[] = []
for (let i = 0; i < points.length - 1; i++) {
newPoints.push(lerp(points[i], points[i + 1], t))
}
// Recurse with one fewer point
return deCasteljau(newPoints, t)
}
// To draw a curve: evaluate at many t values
function drawBezier(points: Point[], segments: number = 100): Point[] {
const curve: Point[] = []
for (let i = 0; i <= segments; i++) {
curve.push(deCasteljau(points, i / segments))
}
return curve
}De Casteljau's algorithm has another crucial property: numerical stability. When computing with floating-point numbers, errors can accumulate and magnify through repeated operations. The de Casteljau algorithm is remarkably stable because it only performs convex combinations - weighted averages where the weights are non-negative and sum to 1. This means intermediate results always stay within the convex hull of the control points, preventing the explosive error growth that plagues many numerical algorithms.
Cubic Bézier curves
While quadratic curves are simpler, cubic Bézier curves with four control points are the workhorses of computer graphics. They offer more flexibility than quadratics - you can independently control the tangent direction at each endpoint by adjusting the adjacent control point. This makes them ideal for design work where you need precise control over how curves enter and leave connection points.
The two interior control points (P₁ and P₂) act as 'handles' that pull the curve in their direction. The curve starts at P₀ heading toward P₁, and arrives at P₃ coming from the direction of P₂. The distances from the endpoints to their handles control how strongly the curve is pulled in those directions. Long handles create pronounced bulges; short handles keep the curve closer to the straight line between endpoints.
This tangent property is what makes cubic Béziers so useful for design. When you adjust a handle in Illustrator or Figma, you are changing the direction and magnitude of the curve's tangent at that endpoint. The other end remains unaffected - true local control. In contrast, moving any control point of a quadratic curve affects the entire curve's shape.
Font designers predominantly use cubic Béziers (in PostScript and OpenType CFF fonts) because they need this precise control. The curves that form a lowercase 'a' must enter and exit their connection points at exact angles to create optically pleasing shapes. Quadratic curves, used in TrueType fonts, require more control points to achieve the same visual results, making them less efficient for complex letterforms.
Bernstein polynomials: the explicit formula
While de Casteljau's algorithm is elegant and numerically stable, it is sometimes useful to express Bézier curves as explicit polynomial formulas. The mathematical basis for these formulas is Bernstein polynomials, developed by Russian mathematician Sergei Bernstein in 1912 - decades before their application to computer graphics.
For a cubic Bézier, the point at parameter t is: P(t) = (1-t)³P₀ + 3(1-t)²tP₁ + 3(1-t)t²P₂ + t³P₃. The coefficients (1-t)³, 3(1-t)²t, 3(1-t)t², and t³ are the Bernstein basis polynomials of degree 3. They have remarkable properties: each is non-negative for t in [0,1], and they sum to exactly 1 for any t. This partition of unity is what keeps the curve within the convex hull of its control points.
// Bernstein basis polynomials for cubic Bézier
function B0(t: number): number { return (1-t) * (1-t) * (1-t) }
function B1(t: number): number { return 3 * (1-t) * (1-t) * t }
function B2(t: number): number { return 3 * (1-t) * t * t }
function B3(t: number): number { return t * t * t }
// Explicit cubic Bézier evaluation
function cubicBezier(p0: Point, p1: Point, p2: Point, p3: Point, t: number): Point {
return {
x: B0(t)*p0.x + B1(t)*p1.x + B2(t)*p2.x + B3(t)*p3.x,
y: B0(t)*p0.y + B1(t)*p1.y + B2(t)*p2.y + B3(t)*p3.y
}
}
// Both approaches give identical results - choose based on contextThe Bernstein form is useful for deriving properties of Bézier curves analytically. For instance, the derivative (tangent vector) at any point can be expressed as another Bézier curve of one lower degree. The curve's arc length, while not expressible in closed form, can be efficiently approximated using Gaussian quadrature. These analytical properties make Bézier curves amenable to rigorous mathematical treatment.
Continuity and smoothness
Real designs require more than a single curve segment. A font glyph might contain dozens of Bézier segments; a complex illustration might contain thousands. When joining multiple Bézier curves into a longer path, the transitions between segments can have different levels of smoothness, classified using continuity notation from differential geometry.
C⁰ continuity (positional continuity) means the curves simply meet at the same point - there is no gap, but there may be an abrupt change in direction, creating a visible corner. This is often intentional in design, for corners and sharp features.
G¹ continuity (geometric continuity) means the tangent directions match at the junction - no visible kink - but the 'speed' along the curve may change abruptly. This is sufficient for visual smoothness in most design applications. You achieve G¹ continuity by ensuring the handles on either side of a junction point are collinear (on the same line).
C¹ continuity (parametric continuity) means both tangent direction and magnitude match. This is important for animation paths where sudden speed changes would be visible, and for applications like CNC machining where the cutting tool's velocity matters. You achieve C¹ by making handles not just collinear but also equal in length.
Higher orders of continuity (C², C³, etc.) match higher derivatives - curvature and its rate of change. These matter for specialized applications like highway design (drivers feel curvature changes) or camera paths (viewers perceive acceleration changes). Typical graphic design rarely needs beyond G¹.
Bézier curves in CSS and animation
Web developers encounter Bézier curves through CSS timing functions. The cubic-bezier() function defines an easing curve for transitions and animations, mapping input time (0 to 1) to output progress (0 to 1). The curve is a cubic Bézier with fixed endpoints at (0,0) and (1,1), and you specify the two control point positions.
/* Common easing curves expressed as cubic-bezier */
.ease-in { transition-timing-function: cubic-bezier(0.42, 0, 1, 1); }
.ease-out { transition-timing-function: cubic-bezier(0, 0, 0.58, 1); }
.ease-in-out { transition-timing-function: cubic-bezier(0.42, 0, 0.58, 1); }
/* Custom bouncy easing - y values can exceed 0-1 range */
.bouncy { transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55); }Unlike spatial Bézier curves, CSS timing functions can have y-values outside the 0-1 range, allowing 'overshoot' effects like bouncing. The x-values must stay within [0,1] to maintain a valid time mapping (time only moves forward). Tools like cubic-bezier.com let you visually design these curves and copy the resulting function values.
Beyond Bézier: B-splines and NURBS
Bézier curves have limitations that become apparent in certain applications. Adding control points increases the polynomial degree, making computation more expensive. Moving any control point affects the entire curve - there is no truly local control. For long, complex curves, these issues become significant.
B-splines (basis splines) address these limitations. A B-spline curve is defined by control points and a 'knot vector' that determines how influence is distributed. Moving one control point only affects a local portion of the curve. The degree remains fixed regardless of how many control points you add. This makes B-splines ideal for modeling long, flowing shapes like car bodies or aircraft fuselages.
NURBS (Non-Uniform Rational B-Splines) extend B-splines further by adding weights to control points and allowing non-uniform knot spacing. The 'rational' part enables exact representation of conic sections - circles, ellipses, parabolas, hyperbolas - which standard polynomial curves can only approximate. NURBS are the standard representation in CAD/CAM systems where mathematical precision matters for manufacturing.
The mathematics of Bézier curves underlies nearly every vector graphic you encounter. From the letters on this page to the icons on your phone to the curves in CAD software designing the next generation of products, these elegant mathematical objects have become the universal language for describing smooth shapes. Understanding them deeply - not just as tool users but as practitioners who grasp the underlying principles - opens doors to more sophisticated design work and troubleshooting capabilities.