s.times(25, () => {
s.strokedPath((attr) =>
attr.fill(
s.sample([0, 20, 40]), 90, 50, 0.2)
)
.moveTo(s.randomPoint())
.arcTo(s.randomPoint())
})
A little, zero dependency, library for drawing in SVG, with a fluent TypeScript (many things use chained methods). This style is a little unconventional but has some interesting benefits with fewer imports or things you have to remember.
There are four key parts
This is the main class. It is the thing that creates SVGs, but it also offers many convenient functions and handles pseudo-randomness. In most examples an instance of this is accessed via s.
The main thing that allows you to assemble drawings. Get started with s.path or another more specific call.
These set up things like strokes and fills and transforms. You can create a new instance of each with s.T or s.A and start using chained calls to configure.
Because you want to create SVGs with TypeScript.
I initially made this to create things with an AxiDraw plotter. My first generated drawings for a 2D plotter. And my Second collection. And a Third collection. And a Fourth collection. I've been using it more recently for creating cut and fold scupltures/pop ups with a Cricut machine.
A ready to play with CodeSandbox.
Full soure code for the library and this site
Support for OkLCH colours.
Easy Regular Polygons.
Quickly create graphics that tile the canvas without having to worry about all the low lever details.
s.forTiling(
{ n: 5, type: "square", margin: 0.1 },
([x, y], [dX]) => {
const path = s
.strokedPath((attr) =>
attr.stroke(355, 10, 10, 0.9).fill(340, 90, 70, 0.2)
)
.moveTo([0.5, 0.5])
s.times(10, () => {
const pt = s.randomPoint()
path.lineTo([x + pt[0] * dX, y + pt[1] * dX])
})
}
)
Curves are easy and fun to draw with an API from Solandra that actually makes sense.
s.times(15, () => {
let start = [s.random(), bottom] as Point2D
let end = [s.random(), bottom] as Point2D
s.strokedPath((attr) => attr.stroke(20, 90, 60, 0.5))
.moveTo(start)
.curveTo(end, { curveSize: 3 })
start = [s.random(), 0] as Point2D
end = [s.random(), 0] as Point2D
s.strokedPath((attr) => attr.stroke(0, 90, 60, 0.5))
.moveTo(start)
.curveTo(end, { polarlity: -1, curveSize: 3 })
})
Rectangles are easy to draw and the framework takes care of alignment.
s.times(25, () => {
s.strokedPath((attr) => attr.fill(220, 90, 50, 0.2)).rect(
s.randomPoint(),
s.gaussian({ sd: 0.05, mean: 0.2 }),
s.gaussian({ sd: 0.1, mean: 0.3 })
)
})
Ellipses are easy to draw and the framework takes care of alignment.
s.times(35, () => {
const size = s.gaussian({ sd: 0.2, mean: 0.25 })
s.strokedPath((attr) =>
attr.fill(s.sample([130, 200, 210]), 90, 40, 0.2)
).ellipse(s.randomPoint(), size, size / 1.25)
})
An elegant algorithm for smooth a path of lines. Repeatedly cut the corners. In solandra-svg this is only applied to lines (as it doesn't make sense for other path segments).
const { bottom } = s.meta
s.times(4, (n) => {
const path = s
.strokedPath((attr) =>
attr.strokeOpacity(0.2 + n * 0.1).stroke(15, 90, 60)
)
.moveTo([0.1, bottom * 0.4])
for (let i = 0.1; i <= 0.9; i += 0.2) {
path.lineTo([i, bottom * 0.4 + 0.3 * Math.cos(i * 10)])
}
path
.map((el) => {
if (el.kind === "line" || el.kind === "move") {
return { ...el, to: v.add(el.to, [0, 0.1 * n]) }
} else {
return el
}
})
.chaiken(n + 1)
})
s.strokedPath((attr) =>
attr
.fill(210, 90, 20, 0.5)
.transform(s.T.rotate(Math.PI / 8))
).rect([0.3, 0.3], 0.2, 0.3)
const path = s.strokedPath().ellipse([0, 0], 0.3, 0.4)
s.times(20, (n) => {
s.clonePath(path).configureAttributes((attr) =>
attr
.transform(s.T.scale(n / 2, n / 2))
.stroke(n * 5, 90, 40)
)
})
solandra-svg offers a closure based API for building svg groups. You use the same fluent Attributes api to set up their attributes.
const { center } = s.meta
s.times(8, (n) => {
s.group(
Attributes.stroked.transform(
s.T.translate(center).scale((4 + n) / 14)
),
() => {
s.path(s.A.opacity((8 - n) / 10)).rect([0, 0], 1, 1)
s.path(
s.A.stroke(n * 4, 90, 50).transform(s.T.rotate(n))
).ellipse([0, 0], 1, 0.8)
}
)
})
Solandra SVG is made by James Porter. The full code for all these examples is available on GitHub.