12 unstable releases (3 breaking)

0.4.0 Jan 21, 2024
0.4.0-rc.0 Jan 20, 2024
0.3.0 Dec 28, 2023
0.2.0 Oct 22, 2023
0.1.0-alpha.2 Sep 30, 2023

#65 in Visualization

Download history 9/week @ 2023-11-10 4/week @ 2023-11-17 22/week @ 2023-11-24 5/week @ 2023-12-01 7/week @ 2023-12-08 7/week @ 2023-12-15 97/week @ 2023-12-22 12/week @ 2023-12-29 19/week @ 2024-01-05 6/week @ 2024-01-12 71/week @ 2024-01-19 19/week @ 2024-01-26 15/week @ 2024-02-02 16/week @ 2024-02-09 172/week @ 2024-02-16 406/week @ 2024-02-23

609 downloads per month

MIT license

6.5K SLoC

whiskers: interactive sketches for plotter generative art

github Latest version Documentation GitHub

👉 Try the live demo!

whiskers is a Processing-like interactive sketch environment and API built over vsvg and vsvg-viewer. It's similar to vsketch, but faster, web-ready, and with much stronger foundations.



Simply add whiskers as a dependency to your project:

cargo add whiskers


Here is the code for a basic sketch:

use whiskers::prelude::*;

#[sketch_app]  // <- this is the magic to make the sketch interactive
struct HelloWorldSketch {
    width: f64,   // <- interactive UI is automagically built for these fields
    height: f64,

impl Default for HelloWorldSketch {
    fn default() -> Self {
        Self {
            width: 400.0,
            height: 300.0,

impl App for HelloWorldSketch {
    fn update(&mut self, sketch: &mut Sketch, _ctx: &mut Context) -> anyhow::Result<()> {

        // the `Sketch` API is a delight to work with
            .translate(sketch.width() / 2.0, sketch.height() / 2.0)
            .rect(0., 0., self.width, self.height);


fn main() -> Result {

This is the result:


whiskers is part of the vsvg project.


  • Interactive UI automatically built based on the sketch struct's fields.
  • Sketch parameter UI highly customisable using #[param(...)] attributes (see e.g. asteroid example).
  • Sketch parameter UI easily extendable for custom data types (see e.g. custom_ui example).
  • Page size management UI.
  • Export to SVG.
  • Support for curves (including quadratic Béziers, cubic Bézier, Catmull-Rom splines—circles, ellipses and arcs are supported but internally converted to cubic Bézier).
  • Time parameter management UI (for animated sketches).
  • Random Number Generator UI with seed control (see e.g. asteroid example).
  • Integrated profiler (based on puffin).
  • Grid helper for grid-based sketches.
  • HexGrid helper for hexagonal-grid-based sketches
  • Configuration handling (save/restore config, etc.).
  • Compiled sketches are also a flexible CLI utility with the capability to batch generate sketch outputs with parameter ranges.
  • Export to other format through templating (HPGL, g-code, etc. — for now, please use vpype).
  • ... (please complete this list)

Isn't that vsketch?

Compared to vsketch, whiskers offers the following advantages:

  • It's in Rust, so it's faaast! 🚀
  • Sketches can be compiled to WebAssembly and published on the Web (try it here).
  • It's built on a stack (mainly egui and wgpu) that's much faster and easier to work with.

On the other hand:

  • It's in Rust, which has a steeper learning curve than Python.
  • Since sketches are compiled, the edit code/execute cycle is heavier than with vsketch.

I have the vague dream to slap a Python front-end on top of whiskers to build vsketch 2.0, but that's a lot of work and other things have a higher priority, so no promises on this front.

Running examples

To run the example, use the following command (in this case to run crates/whiskers/examples/asteroid.rs):

cargo run --release --package whiskers --example asteroid

Non-interactive use

The whiskers::Sketch object can be used stand-alone, without the interactive sketch runner. This is useful if you want to use the drawing capabilities in your own tools.

For example, I use whiskers::Sketch to build the generative asteroids in my Rusteroïds toy game.

Here is how the code could look:

use whiskers::prelude::*;

fn main() -> Result {
        .translate(7.0, 6.0)
        .circle(0.0, 0.0, 2.5)
        .translate(1.0, 4.0)
        .rect(0., 0., 4.0, 1.0)


If the viewer feature of *whiskers is enabled (which it is by default), the sketch can be displayed using the basic viewer using sketch.show().


~1M SLoC