Canvas Curves
Quadratic and cubic Bézier curves let you draw smooth, organic lines by pulling a straight segment toward one or two control points.
Beyond Straight Lines
beginPath(), moveTo(), and lineTo() only ever produce straight edges. To draw smooth, flowing curves — arches, waves, leaf shapes, speech bubbles — Canvas provides two curve methods that both start from the current point set by a prior moveTo() or lineTo(): quadraticCurveTo() for simple curves with one control point, and bezierCurveTo() for more flexible curves with two.
Quadratic Curves with quadraticCurveTo()
quadraticCurveTo(cpx, cpy, x, y) draws a curve from the current point to (x, y), bending toward a single control point at (cpx, cpy). The curve never actually touches the control point — it only gets pulled toward it, the way a rubber band bends toward wherever you pinch it. Moving the control point further from the straight line between the start and end points produces a more pronounced bulge.
Example
<!DOCTYPE html>
<html>
<body>
<canvas id="scene" width="300" height="200" style="border:1px solid #ccc;"></canvas>
<script>
const ctx = document.getElementById('scene').getContext('2d');
ctx.beginPath();
ctx.moveTo(30, 120);
ctx.quadraticCurveTo(120, 20, 210, 120);
ctx.strokeStyle = '#0891b2';
ctx.lineWidth = 4;
ctx.stroke();
</script>
</body>
</html>Cubic Bézier Curves with bezierCurveTo()
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) works the same way but with two control points instead of one. The curve leaves the current point heading toward the first control point and arrives at (x, y) coming from the direction of the second control point, which makes it possible to draw S-shapes and other curves that a single control point cannot reach. Illustration and vector-graphics software use this same cubic Bézier model, so a curve designed in a tool like Figma or Illustrator maps directly onto bezierCurveTo() calls.
Example
<!DOCTYPE html>
<html>
<body>
<canvas id="scene" width="300" height="220" style="border:1px solid #ccc;"></canvas>
<script>
const ctx = document.getElementById('scene').getContext('2d');
ctx.beginPath();
ctx.moveTo(30, 130);
ctx.bezierCurveTo(30, 30, 170, 200, 210, 60);
ctx.strokeStyle = '#db2777';
ctx.lineWidth = 4;
ctx.stroke();
</script>
</body>
</html>- quadraticCurveTo(cpx, cpy, x, y) uses one control point
- bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) uses two control points
- Both methods draw from the current point set by the prior moveTo() or lineTo()
- Control points are never drawn themselves; they only shape the curve
- Two control points make S-curves and complex bends possible; one control point cannot
Example
<!DOCTYPE html>
<html>
<body>
<canvas id="scene" width="300" height="200" style="border:1px solid #ccc;"></canvas>
<script>
const ctx = document.getElementById('scene').getContext('2d');
const x = 40, y = 30, w = 170, h = 100, r = 20;
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.lineTo(x + w - r, y);
ctx.quadraticCurveTo(x + w, y, x + w, y + r);
ctx.lineTo(x + w, y + h - r);
ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
ctx.lineTo(x + 60, y + h);
ctx.lineTo(x + 40, y + h + 30); // speech bubble tail
ctx.lineTo(x + 50, y + h);
ctx.lineTo(x + r, y + h);
ctx.quadraticCurveTo(x, y + h, x, y + h - r);
ctx.lineTo(x, y + r);
ctx.quadraticCurveTo(x, y, x + r, y);
ctx.closePath();
ctx.fillStyle = '#f8fafc';
ctx.fill();
ctx.strokeStyle = '#334155';
ctx.lineWidth = 3;
ctx.stroke();
</script>
</body>
</html>Exercise: Canvas Curves
How many control points does quadraticCurveTo() use to shape its curve?