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 library for drawing in SVG, but with a nicer API.
Basically I made this to generate stuff to plot. My first generated drawings for a 2D plotter. And my Second collection. And a Third collection. And a Fourth collection.
A ready to play with CodeSandbox.
Full soure code for the library and this site
npm install solandra-svg
yarn add solandra-svg
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], c, i) => {
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(new Transform().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(new Transform().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(
Transform.of({ translate: center, scale: (4 + n) / 14 })
),
() => {
s.path(
Attributes.of({
opacity: (8 - n) / 10,
})
).rect([0, 0], 1, 1)
s.path(
Attributes.of({
stroke: { h: n * 4, s: 90, l: 50 },
transform: Transform.of({ rotate: n }),
})
).ellipse([0, 0], 1, 0.8)
}
)
})
The full code for all these examples is available on GitHub.