Skip to content

Repository files navigation

Plottery

crates.io docs.rs license editor release

Plottery is a generative art engine for pen-plotters written in Rust.


Pen plotter drawing of a gold maze-like line pattern on black paper Pen plotter drawing of a Sierpinski triangle in a peach-to-pink gradient Three framed pen plotter drawings on a sunlit wall Pen plotter drawing of flowing curved strokes in pink, orange and blue Pen plotter drawings of nested rounded line patterns in blue and pink Pen plotter drawing of a grid of hatched squares in pink, orange and blue Close-up of a pen plotter drawing of overlapping looped lines in black, pink and cyan Four pen plotter cards with black looping ring patterns around different centre shapes Stippled white concentric rings plotted on black paper Pen plotter drawing of a grid of square tiles with different line and curve patterns Framed black pen plotter drawing of a swirling form made of many fine lines

Install

On macOS, this installs the newest editor and, if cargo is installed, the matching plottery CLI:

curl -fsSL https://raw.githubusercontent.com/TobiasGrothmann/plottery/main/scripts/install_macos.sh | bash

CLI only: cargo install plottery_cli.

Editor

The editor lets you manage, preview and run Plottery projects.

Plottery editor with parameter sliders, a Truchet tile preview, layers and a build console

Projects

A project is a regular cargo package that depends on Plottery. Create one with the editor or the CLI:

plottery new /path/to/folder awesome_project

Its src/generate.rs turns a Params struct into a Layer:

use plottery_lib::*;
use plottery_project::*;

#[derive(PlotteryParams)]
pub struct Params {
    pub paper: Paper,
    #[value(12)]
    #[range(1, 50)]
    pub circles: i32,
}

pub fn generate(params: Params) -> Layer {
    let frame = params.paper.frame();
    let step = frame.inner_rect().width() * 0.5 / params.circles as f32;
    let circles = (1..=params.circles).map(|i| Circle::new(frame.center(), step * i as f32));

    let mut l = Layer::new();
    l.push(frame.outer_rect());
    l.push_many(circles);
    l.with_name("root").optimize_recursive()
}

Run it in the editor, with plottery run, or with cargo run svg to open the result as .svg.

Examples

Spiral example: one continuous blue spiral line Scribbles example: a grid of squares that get more scribbled towards the bottom Pebbles example: rows of pebble shapes filled with concentric contour lines Poster example: the word Plottery in a single-line script font above a paragraph of text

  • spiral: a path collected from polar points, masked to the margin, in named and colored sublayers. Its center is set by clicking the drawing, its direction by an enum.
  • scribbles: squares that dissolve into scribbles, with a seed, a noise param, an easing curve and random ranges.
  • pebbles: closed Hobby splines through random points, with rings inside.
  • poster: a title fitted to the page width and a wrapped paragraph, fonts and text set in the editor.

Every example is a complete project that builds against this repository: in a clone, open its folder in the editor or run plottery run examples/spiral.

Parameters

Every field of Params shows up in the editor. #[value(..)] sets the default, #[range(min, max)] shows a slider, #[section("..")] groups fields and /// comments become tooltips. All attributes and supported types are listed in the project README, and the examples use many of them.

Text & Fonts

Text is drawn with single-line fonts, so every glyph is a set of pen strokes. The bundled fonts are embedded in the library and load with no setup:

let font = Font::bundled(BundledFont::HersheyScript);
let text = Text::new("Hello plotter", &font)
    .size(1.5) // em height in cm
    .in_rect(frame.inner_rect()) // wraps words at the rect's width
    .align(TextAlign::Center)
    .vertical_align(VerticalAlign::Center)
    .to_layer(SampleSettings::default())
    .expect("text");
l.push_layer(text);

Anchoring to a rect, wrapping, justify, fitting and rotation are shown in the text layout samples. Font::load reads SVG, TTF and OTF files, Font::load_single_line keeps the strokes of single-line TrueType fonts open, and Font::system("Helvetica") finds an installed font. The poster example picks its fonts and text in the editor. All 65 bundled fonts are shown in the fonts README.

Hershey Script single-line font sample EMS Readability single-line font sample Relief Single Line font sample Hershey Gothic English single-line font sample

Development

Building from source, tests and releasing are described in DEVELOPMENT.md.

License

GPL-3.0. The bundled fonts have their own licences, see plottery_fonts.