#plottery #generative-art #generative #art #plotter #graphics

plottery_server_lib

library for the communication with the pen-plotter server of Plottery, a creative coding framework for generative vector graphics and pen plotting

4 releases (breaking)

0.7.0 Mar 23, 2025
0.6.0 Mar 14, 2025
0.5.0 Mar 8, 2025
0.4.0 Mar 7, 2025

#8 in #generative


Used in 2 crates

GPL-3.0 license

410KB
8K SLoC

Plottery

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

  • plottery_lib (crates.io): Core library – Contains the functionality to generate art. This includes shapes, geometry helpers, structs for composition and other tools.
  • plottery_editor: Plottery Editor (releases) – The GUI Application to create, manage and run projects, preview artworks and control the plotter hardware.
  • plottery_server: Controller for the pen-plotter hardware – The server offers a http interface to send tasks to execute on the hardware and controls the motors. This is highly customized to my personal DIY pen-plotter.
  • plottery_cli (crates.io): Command line interface to create and run projects.
  • plottery_project (crates.io): Library containing functionality to handle Plottery projects.


Editor

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

Projects

Create

To create a new project either use the editor or the command line interface (CLI) like so:

cargo install plottery_cli
plottery new /path/to/folder awesome_project

Projects in Plottery are a wrapper around a regular cargo project. They support a couple of commands when run directly:

cargo run svg # run project and open the result as .svg
cargo run -- --help # get some info

The editor can also be used to run a project and tweak its input parameters.

Parameters

Projects expose parameters as a struct:

#[derive(PlotteryParams)]
pub struct Params {
    num_points: i32,
    points_distance: f32,
}

Generate

generate.rs defines the function used to generate the art. It receives an instance of Params as an argument and returns a Layer:

pub fn generate(params: Params) -> Layer {
    let mut l = Layer::new();

    /* Generate your art here! */

    l.with_name("root").optimize_recursive()
}

Example

This project generates a spiral masked inside a rectangle:

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

// These project parameters are exposed in the Plottery Editor.
#[derive(PlotteryParams)]
pub struct Params {
    #[value(2_000)]
    num_points: i32,

    #[value(10.0)]
    rotations: f32,
}

pub fn generate(params: Params) -> Layer {
    let mut l = Layer::new();
    let size = V2::a6(); // DIN-A6 paper size
    let frame = Frame::new(
        size,
        size.min_axis() * 0.1, // 10% margin of smallest side
    );

    // add outer border as a paper cutting guide
    l.push_rect(frame.outer_rect());

    // generate spiral by collecting from iterator of points
    let path: Path = (0..params.num_points)
        .map(|i| {
            let angle =
                Angle::from_rotations(i as f32 / params.num_points as f32) * params.rotations;
            let radius = i as f32 * 0.005;
            V2::polar(angle, radius)
        })
        .collect::<Path>() // collect points into a Path
        .translate(frame.center()); // translate spiral to center of frame

    // mask path to the inner rect of the frame (outer frame without the margin)
    let masked_path = path.mask_brute_force(&frame.inner_rect().into(), SampleSettings::default());

    // push all elements of inside the inner frame to `l` flat
    l.push_layer_flat(masked_path.inside);

    l.with_name("root").optimize_recursive()
}

Dependencies

~13–25MB
~359K SLoC