Penplotting.js is a JavaScript framework for making generative art in SVG format for penplotters. This project is a personal project, and as such, it is a work-in-progress. New features and breaking changes are expected in future updates. Use at your own discretion, feel free to contribute and raise issues.
- Shapes and geometry classes: Vector, Point, Line, Path, Circle, AABB, Matrix
- Seedable PRNG implementations with useful methods
- Quadtree for optimised nearest-neighbour search
- Paper sizes
npm i @jakebeamish/penplotting
To start a new plot, run
npx new-plot
This command runs a shell script that will create boilerplate index.html
,
style.css
and plot.js
files in the current working directory.
Inside plot.js
, adjust the options for initializing the plot. A full list of
options can be found in the Plot constructor docs.
const plot = new Plot({
units: "mm",
title: "My amazing plot",
size: Paper.A5,
strokeWidth: 0.05,
});
The image is defined in a plot.generate()
function in which Vectors and other
shape objects can be created, manipulated, and added to the SVG document with
plot.add(shapes)
, where shapes
is a shape or an array of shapes.
For a complete overview, see the API Documentation.
import {
Plot,
Vector,
Triangle,
Line,
AABB,
Circle,
Path,
PAPER,
PRNG,
} from "@jakebeamish/penplotting";
// Setup a new plot with configuration options
let plot = new Plot({
size: PAPER.A6.landscape(),
backgroundColor: "white",
strokeWidth: 0.3,
});
// Create the work inside the plot.generate() function
plot.generate = () => {
// Initialise PRNG
const prng = new PRNG({ seed: plot.seed.decimal });
// Destructure the plot size for easy access to width and height
const { width, height } = plot.size;
// The Vector constructor takes up to three parameters x, y, and z
// If an argument is not given for a coordinate, the default value is 0
const centre = new Vector(width / 2, height / 2);
// Lines can be created using the constructor, or the fromArray static method
// which requires an array in the format [x1, y1, x2, y2]
const line = Line.fromArray([30, centre.y - 10, 30, centre.y + 10]);
// Shapes are added to the SVG using plot.add()
plot.add(line);
// Circles can be created in a similar way. It requires a position (either as
// a Vector or as individual coordinates), and a radius
const circle = Circle.fromVector(new Vector(50, centre.y), 10);
plot.add(circle);
const square = new AABB(80, centre.y, 10, 10);
const triangle = new Triangle(
new Vector(100, centre.y + 10),
new Vector(110, centre.y - 10),
new Vector(120, centre.y + 10)
);
// AABBs and Triangles can't be added to a plot directly - the lines() method
// can be used to return an array of lines that compose the shape
// plot.add() can be given an (optionally nested) array to add multiple shapes
plot.add([square.lines(), triangle.lines()]);
let randomPoints = [];
for (let i = 0; i < 30; i++) {
randomPoints.push(
Vector.lerp(new Vector(30, 20), new Vector(width - 20, 20), i / 30).add(
new Vector(0, prng.randomBipolarFloat() * 5)
)
);
}
let randomPath = new Path(randomPoints);
let sinPoints = [];
for (let i = 0; i < 100; i++) {
sinPoints.push(
Vector.lerp(
new Vector(30, height - 20),
new Vector(width - 20, height - 20),
i / 100
).add(new Vector(0, Math.sin((i / 100) * Math.PI * 10) * 3))
);
}
let sinPath = new Path(sinPoints);
plot.add([randomPath, sinPath]);
};
plot.draw();
Calling plot.draw()
at the end of the file generates an SVG element
and UI inside index.html
, which can be viewed in a browser.
The above code results in the following output:
Action | Key |
---|---|
Download an SVG file | d |
Regenerate with random seed | r |
The SVG file can be downloaded and optionally processed further. Personally, I use vpype to optimise the file, and then the axidraw Inkscape plugin to control the plotter.
Contributions are welcome. Issues, comments and Pull Requests can be made at https://github.com/jakebeamish/penplot-svg-tool/issues.
The project is tested using jest. Documentation is generated using JSDoc.
This project is licensed under the MIT License. See the LICENSE.md file for details.
This project incorporates code from:
- CodingTrain/Quadtree - Licensed under the MIT License.