Paths

Paths

Paths are the fundamental building blocks in Hobby. A path is a sequence of points connected by curves or lines.

Creating a Path

Use h.path() to create a new path builder:

local h = require("hobby")

local path = h.path()
    :moveto(h.point(0, 0))
    :curveto(h.point(50, 30))
    :curveto(h.point(100, 0))
    :build()

Path Commands

moveto(point)

Sets the starting point of the path.

:moveto(h.point(10, 20))

curveto(point)

Creates a smooth curve to the given point using the Hobby algorithm.

:curveto(h.point(50, 50))

lineto(point)

Creates a straight line to the given point.

:lineto(h.point(100, 0))

curvetowithcontrols(point, c1, c2)

Creates a Bézier curve with explicit control points.

:curvetowithcontrols(
    h.point(100, 0),   -- end point
    h.point(30, 50),   -- control point 1
    h.point(70, 50)    -- control point 2
)

cycle() / close()

Closes the path by connecting back to the starting point.

:cycle()

build()

Solves the path and returns the result. This must be called after defining the path.

local solved_path = path:build()

Direction Control

dir(angle)

Sets the outgoing direction at the current point (in degrees).

:moveto(h.point(0, 0))
:dir(45)              -- leave at 45 degrees
:curveto(h.point(100, 0))

indir(angle)

Sets the incoming direction at the next point.

:curveto(h.point(100, 0))
:indir(0)             -- arrive horizontally

Tension Control

Tension controls how “tight” the curve is. Higher values produce tighter curves.

tension(t)

Sets tension for both incoming and outgoing directions.

:tension(2)           -- tighter curve
:curveto(h.point(50, 50))

outtension(t) / intension(t)

Sets tension separately for outgoing and incoming directions.

:outtension(0.75)     -- looser departure
:intension(2)         -- tighter arrival
:curveto(h.point(50, 50))

tensionatleast(t)

Sets a minimum tension value.

:tensionatleast(1.5)
:curveto(h.point(50, 50))

tensioninfinity()

Creates a straight segment with smooth connections at endpoints.

:tensioninfinity()
:curveto(h.point(50, 50))

Curl Control

Curl controls the curvature at path endpoints.

curl(c)

Sets curl at an endpoint. Default is 1.

:moveto(h.point(0, 0))
:curl(0)              -- straight departure
:curveto(h.point(100, 0))

outcurl(c) / incurl(c)

Sets curl separately for departure and arrival.

:outcurl(0)           -- straight departure
:curveto(h.point(50, 50))
:curveto(h.point(100, 0))
:incurl(2)            -- more curved arrival

Complete Example

local h = require("hobby")

-- A path with various controls
local path = h.path()
    :moveto(h.point(0, 0))
    :dir(90)              -- start going up
    :tension(1.5)
    :curveto(h.point(50, 80))
    :curveto(h.point(100, 0))
    :indir(-90)           -- arrive going down
    :stroke("blue")
    :strokewidth(2)
    :build()

h.svg()
    :padding(10)
    :add(path)
    :write("path_example.svg")

Path example