CLI tool
abey79/vsketch avatar
abey79/vsketch

vsketch treats a pen plotter as the target and the computer as the sketchpad

Generative plotter art environment for Python

609 stars59 forksPythonNOASSERTION

At a glance

What is it?
vsketch is a Python generative art toolkit where the sketch is a class with a draw method and the output is a file for a physical pen plotter, not a picture. Its distinctive feature is the vsk command line tool, which turns the whole loop of writing, previewing, tuning parameters and exporting a hundred seeded variants into a project directory with a config folder and an output folder.
Who is it for?
Adopt vsketch if you draw for a pen plotter and want a Python workflow that ends in plotter-ready files rather than in a picture, since the export path and the vpype integration are the parts you would otherwise build yourself. Skip it if you want to make images, because the whole toolchain is aimed at physical output and the API is deliberately narrow.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Four focuses, and the plotter one explains the rest

vsketch is a Python generative art toolkit for plotters, and the project states four focuses.

The first is accessibility, on the grounds that vsketch is easy to learn and feels familiar thanks to an API strongly inspired by Processing. Processing is the Java library that made generative art accessible to people who came from a design background rather than a mathematics one, and the borrow is deliberate. If you have written a Processing sketch, you can write a vsketch one.

The second is minimised friction, and it is described concretely. vsketch automates every part of the creation process, project initialisation, frictionless iteration and export to plotter-ready files, through a CLI tool called `vsk` and a tight integration with vpype.

The third is plotter-centric, and this is the one that constrains the others. vsketch is made for plotter users, by plotter users, its feature set is focused on the peculiarities of this medium, and it does not aim to solve other problems.

That sentence is doing a lot of work. A pen plotter has physical constraints that a canvas does not. The pen has a diameter, so a line that is thinner than the nib becomes a scratch. The machine has an acceleration limit, so a curve that is too sharp will stall and the motors will skip. The paper is a fixed size and the drawing has to fit inside it. The plot time is proportional to path length, so an unnecessarily detailed drawing takes twenty minutes instead of two.

The fourth focus is interoperability, playing nicely with popular packages such as Numpy and Shapely, which are described as true enablers for plotter generative art. Shapely in particular is how you do geometry properly, and having it available means you are not limited to drawing primitives one at a time.

The project is Python, with the last push on 2026-10-06 and releases 1.2.0 from 2025-08-06, 1.1.0 from 2024-01-10 and 1.0.0 from 2023-07-29. The documentation is at vsketch.readthedocs.io and the project notes that it is at an early stage and needs contributions.

The project structure and the sketch class contract

Creating a project is one command:

bash
$ vsk init my_project

And it produces this:

bash
$ ls my_project
config
output
sketch_my_project.py

So the sketch file is named after the project, and the config and output directories are used by vsk to store configurations and the exported SVGs. That layout is the point of the CLI, because the tool manages a project rather than a single file.

The sketch itself is a class deriving from vsketch.SketchClass with two methods. Here is the canonical example, which reproduces Georg Nees' famous Schotter artwork:

python
import vsketch

class SchotterSketch(vsketch.SketchClass):
    def draw(self, vsk: vsketch.SketchClass) -> None:
        vsk.size("a4", landscape=False)
        vsk.scale("cm")

        for j in range(22):
            with vsk.pushMatrix():
                for i in range(12):
                    with vsk.pushMatrix():
                        vsk.rotate(0.03 * vsk.random(-j, j))
                        vsk.translate(
                            0.01 * vsk.randomGaussian() * j,
                            0.01 * vsk.randomGaussian() * j,
                        )
                        vsk.rect(0, 0, 1, 1)
                    vsk.translate(1, 0)
            vsk.translate(0, 1)

    def finalize(self, vsk: vsketch.Vsketch) -> None:
        vsk.vpype("linemerge linesimplify reloop linesort")

if __name__ == "__main__":
    SchotterSketch.display()

The draw method sets the page size and the unit, then draws. vsk.size takes a paper format and a flag for the orientation, and vsk.scale takes the unit, which here is centimetres.

The geometry is built with a transform stack. pushMatrix pushes the current transform and pops it at the end of the with block, and rotate, translate and rect are applied inside. The random functions are vsk.random and vsk.randomGaussian, and the fact that they are methods on the sketch object rather than calls to a random module is what makes a sketch reproducible from a seed.

The finalize method is where the plotter-specific work happens. It calls vsk.vpype with a chain of operations, here linemerge, linesimplify, reloop and linesort. Those are all things a plotter cares about: merging the lines the drawing is made of, simplifying them, re-looping the path so the pen travels efficiently between strokes, and sorting them so the order reduces travel.

And the file ends with the display call under a main guard, which is what lets the same file run as a script and be picked up by the CLI.

The class-based structure is why the live parameter tuning in the next section works, since the parameters are class attributes and the tool can change them and re-run the draw method.

Parameters that you can move while the viewer is open

The second half of the example adds interactive parameters, and it is the most distinctive thing about the toolkit.

You declare them as class attributes:

python
class SchotterSketch(vsketch.SketchClass):
    columns = vsketch.Param(12)
    rows = vsketch.Param(22)
    fuzziness = vsketch.Param(1.0)
    
    # ...

And then use them in draw instead of hard-coded numbers. The draw method changes to iterate over self.rows and self.columns, and to scale the randomness by self.fuzziness:

python
    def draw(self, vsk: vsketch.SketchClass) -> None:
        vsk.size("a4", landscape=False)
        vsk.scale("cm")

        for j in range(self.rows):
            with vsk.pushMatrix():
                for i in range(self.columns):
                    with vsk.pushMatrix():
                        vsk.rotate(self.fuzziness * 0.03 * vsk.random(-j, j))
                        vsk.translate(
                            self.fuzziness * 0.01 * vsk.randomGaussian() * j,
                            self.fuzziness * 0.01 * vsk.randomGaussian() * j,
                        )
                        vsk.rect(0, 0, 1, 1)
                    vsk.translate(1, 0)
            vsk.translate(0, 1)

The behaviour to notice is what happens when you save the file. The documentation says to hit ctrl-S or cmd-S, and corresponding buttons just appeared in the viewer without even needing to restart it.

So the workflow is a live preview with sliders. The viewer picks up the class attributes, renders them as controls, and when you change one the drawing updates. That is a real change from the usual generative art loop, where you edit code, re-run, and look at the result, and the edit-run-look cycle is where the time goes.

Once you have found a combination you like, you save it. The Save button takes a name, and the documentation walks through entering a Best config as the name. That configuration is then stored in the project's config directory and can be loaded at any time.

So the three artefacts are the sketch, the configuration, and the exported output, and the tool keeps them separate. That is what makes a sketch reproducible and what lets you go back to a drawing you liked three months ago.

Batch export is a seed range, not a loop

The last step of the workflow is the one that is specific to this medium.

The reasoning is stated plainly. Being extremely picky, it would be nice to generate one hundred versions of the sketch with various random seeds, in the hope of finding the most perfect version for plotting and framing. And `vsk` does this for you, using all CPU cores available:

bash
$ vsk save --config "Best config" --seed 0..99 my_project

The seed argument accepts a range, 0..99, so a hundred variants are produced in one command rather than a hundred invocations. The files all land in the project's output subdirectory.

This is the feature that makes sense only for a plotter, and it is worth understanding why. On screen, seed 42 is a picture and seed 43 is a picture. On a pen plotter, seed 42 is a physical object that took twenty minutes to draw and will sit on a wall, and the difference between two seeds might be the difference between a drawing that frames well and one that does not. The only way to find out is to draw both, or at least to see them side by side first.

The multiprocessing support matters here. A sketch can take seconds to render, and a hundred of them serially is a coffee break. Spreading that across all the cores turns it into a wait you can watch.

The random seed handling is also a first-class concept. The feature list mentions batch export to SVG with random seed and configuration management as well as multiprocessing support, and there is a dedicated example directory named random_seed in the examples tree, which suggests the behaviour is worth its own demonstration.

And the drawing is exported as SVG, not as a raster image, which is what a plotter needs. The SVG is the intermediate that the plotter's own driver software will turn into pen movements.

Installation and the examples

The recommended installation is with pipx:

bash
$ pipx install vsketch

The reason for pipx rather than a plain pip install is that a plotter toolkit is a command line tool first, and pipx installs it as an isolated application with its own environment, so it does not fight with anything else in your Python setup.

The examples are not bundled with the package, so they have to be downloaded separately. After decompressing the archive they are run with the run subcommand:

bash
$ vsk run path/to/vsketch-master/examples/schotter

The examples directory is worth browsing on its own, because the names are a catalogue of the techniques the library supports. There are schotter and random_flower and random_lines and quick_draw and prime_circles for the generative side, polygon and shape_basic and shape_pixel and shape_playground for the drawing primitives, and bezier_bugs and noise_bezier and easing and noise_plotloop for the curve and timing work.

Several of those names are warnings rather than topics. bezier_bugs and hidden_line_removal and point_transform suggest the library has opinions about the geometry that a plotter needs, and the fact that there is an example named after a bug category means the author expected people to hit it.

There are also the ones that show the integration with the wider ecosystem. shapely shows the geometry library in use, subsketch shows one sketch calling another, postcard and detail show page and zoom considerations, and basic_plotloop shows the loop that most sketch-based plotter art is built from.

The installation instructions have their own page, and the project documentation also has an overview page, an autoapi reference, and a contributing page.

Where this sits against Processing and against a plotting library

The comparison with Processing is explicit in the project, and it is worth being precise about what is borrowed and what is not.

What is borrowed is the API shape. A class with a draw method, a transform stack with push and pop, a size and a scale, and a set of drawing primitives. Someone who has written a Processing sketch can move to vsketch and be productive quickly.

What is not borrowed is the output. Processing draws to a screen. vsketch produces SVG for a machine with a pen attached to a stepper motor, and everything about the tool is shaped by that. The vpype call in finalize, the randomised export, the batch seeding, the size call that takes a paper format, the scale call that takes centimetres. None of those exist in Processing because none of them mean anything there.

The comparison with a plotting library such as Matplotlib is also instructive and the answer is that they solve different problems. Matplotlib is a data visualisation library and it is excellent at putting a data series on axes. A pen plotter drawing is not a chart, it is a physical composition, and the interesting problems are about pen pressure, path efficiency, paper boundaries and how a shape feels when a real nib draws it.

So the honest description of vsketch is a sketch API that happens to output for a plotter, with a project management layer around it. The API is small on purpose, because the plotter-centric focus means it only covers what that medium needs.

The one thing to weigh is that the project is explicitly early and asking for contributions, particularly on documentation. The sketch API is well covered by the worked example, but the CLI has more to it than the example shows, and the documentation suggests using the integrated help with `vsk --help` to find the rest of the possibilities.

For anyone coming from Processing, the two things worth reading in the docs are the overview and the autoapi reference, since the API reference is generated from the source and therefore complete.

Editorial conclusion

Adopt vsketch if you draw for a pen plotter and want a Python workflow that ends in plotter-ready files rather than in a picture, since the export path and the vpype integration are the parts you would otherwise build yourself. Skip it if you want to make images, because the whole toolchain is aimed at physical output and the API is deliberately narrow. Verify first which plotter and pen you are targeting, since the exported SVG has to suit a specific machine, that you install with pipx rather than into your environment, because the project recommends a standalone install, and how you want the geometry post-processed, since the finalize step hands the drawing to vpype and that is where a lot of the visual character comes from.

Frequently asked questions

What is vsketch and what does it produce?

It is a Python generative art toolkit for plotters with an API strongly inspired by Processing, and it produces plotter-ready SVG files rather than images. It is a sum of two things: a CLI tool named vsk that automates project creation, live rendering with live reload and custom parameters, and batch export to SVG with random seed and multiprocessing, plus the sketch API itself.

How do I create and run a vsketch project?

Install it with `pipx install vsketch`, then run `vsk init my_project`, which creates a config directory, an output directory and a sketch file named after the project. Write your sketch as a class deriving from vsketch.SketchClass with a draw method, then run it with `vsk run my_project`. The examples are downloaded separately and run with `vsk run path/to/vsketch-master/examples/schotter`.

How do vsketch parameters and batch export work?

Parameters are declared as class attributes with `vsketch.Param`, for example columns, rows and fuzziness, and they appear as controls in the live viewer when you save the file. You can save a configuration with a name through the Save button, and `vsk save --config "Best config" --seed 0..99 my_project` exports a hundred seeded variants in parallel across all CPU cores into the project's output directory.

Official sources

  1. abey79/vsketch on GitHub
  2. Issues
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/abey79-vsketch.svg)](https://hysenlabs.com/projects/abey79-vsketch)

Was this useful?