SVG2WaterColor

Study

Working question: what changes when the plotter uses brushes and watercolour instead of pens?

The thing is an older tool for paint refill scheduling and multi-station brush plotting. Its active successor is Gantry.

The current page keeps the project as context. The study note should capture what brush plotting taught about material behavior, timing, refill logic, and why the ideas moved into a broader toolkit.

Deprecated: SVG2WaterColor remains online as a historical project note. The active successor is Gantry, which folds the watercolor command model, station mapping and refill logic into a unified Java plotter toolkit.

A two-stage pipeline that transforms multi-layered SVG designs into physical watercolor paintings via pen plotter. The system handles the unique challenges of painting with real brushes and water-based paint: automatic refill scheduling, multi-station paint management, and precise coordinate mapping between digital canvas and physical machine.

Source: github.com/utrost/SVG2WaterColor · License: AGPL-3.0 · Successor: Gantry

The Challenge

Plotting with ink pens is straightforward because the pen holds enough ink for thousands of millimeters of drawing. A brush loaded with watercolor paint runs dry after a limited distance. The plotter doesn’t know this. It will keep dragging a dry brush across the paper, producing fading strokes and scratches.

SVG2WaterColor solves this by tracking paint capacity and automatically scheduling refill commands at calculated split points within strokes.

Two Stages

Stage 1, Java Preprocessor. Parses the SVG, identifies color layers — Inkscape layer names map to paint station IDs — converts all primitives to paths, linearizes curves at configurable step size, segments strokes by paint capacity, and inserts automatic refill commands.

Stage 2, Python Driver. Reads the command JSON and drives the physical plotter via pyaxidraw or G-code. Handles pen up/down, refill dip sequences at configured station coordinates, inter-layer brush changes, and real-time position reporting.

SVG (Inkscape layers)
  → Java Processor
  → commands.json
  → Python Driver
  → Physical Plot

In Gantry, this split has been removed. JSON remains useful as an interchange/save format, but the live plot path is in-process Java.

Paint Capacity Management

The key concept is maxDrawDistance: the maximum distance in millimeters a brush can draw before it needs to be re-dipped in paint. When a stroke exceeds this distance, the preprocessor splits it at the calculated point, inserts a REFILL command, sends the brush to the paint station, then returns and continues the stroke.

This produces more consistent paint density across the painting, regardless of stroke length.

Multi-Station Setup

Each color layer maps to a physical paint station: a small container of watercolor paint at a known XY coordinate on the plotter bed. The system supports multiple stations with configurable dip behavior and position.

When switching between color layers, the driver prompts the user to swap brushes manually. Full automation would require a brush-changing mechanism, which is possible but not yet built.

Digital Twin

The Swing GUI includes a visualization panel that acts as a digital twin of the plotter. It shows the current brush position, completed strokes, pending commands, and refill trips in real time. A mock mode allows full simulation without hardware, useful for testing station positions and paint capacity settings before committing paint to paper.

The Command Contract

The preprocessor and driver communicate through a JSON file:

{
  "layers": [
    {
      "id": "red_wash",
      "stationId": "red_wash",
      "commands": [
        { "op": "REFILL", "stationId": "red_wash" },
        { "op": "MOVE", "x": 10.5, "y": 20.0 },
        { "op": "DRAW", "points": [{ "x": 10.5, "y": 20.0 }] }
      ]
    }
  ]
}

This separation made the first version easy to reason about: the Java side knew SVG, and the Python side knew hardware. Gantry keeps the command model, but removes the runtime split.

Tech Stack

  • Preprocessor: Java 17, Apache Batik, Jackson, Swing GUI
  • Driver: Python 3, pyaxidraw / G-code
  • Output: physical watercolor plotting through a pen plotter / plotter conversion
  • Formats: A5, A4, A3 and XL with configurable padding

Successor

SVG2WaterColor is no longer the active project. Its ideas live on in Gantry: refill stations are now an optional watercolor stage layered on top of the same pipeline used for ordinary pen plotting.

See also: Gantry, PPCT, SVGToolBox, From Pixel to Pen, Generative Art, CityPlot, Vectorize, VHS, Primitive