# pintr: a photograph turned into a single-line plotter drawing

> pintr converts an image into a plotter-like line drawing, locally in the browser, by walking the picture one segment at a time and asking, at every step, which of several candidate lines would make the result look most like the original. The output is deliberately simple SVG, a single polyline, and the whole thing is a Next.js application with a small TypeScript core.

**javierbyte/pintr** — Create single line illustrations from your pictures.

- Repository: https://github.com/javierbyte/pintr
- Website: https://javier.xyz/pintr
- Stars: 835 · Forks: 60
- Language: TypeScript
- License: BSD-3-Clause
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/javierbyte-pintr

## Everything happens on your machine

Pintr turns images into plotter-like line drawings and creates single line SVG illustrations from pictures, and the first thing the README says about it is where the processing happens.

All the processing is made locally, your images never leave your computer, and you are free to use them as you please. For a tool that takes photographs as input, that is the sentence that matters, and it is also a design constraint rather than a policy promise, since the work is done with the canvas and the drawing code in your own browser.

The implementation is a Next.js application written in TypeScript. The project file gives the shape: a development server, a production build, a start script and a type check that runs the compiler without emitting. The dependencies are React and the Next.js framework, a canvas utility library, and a third-party package for the media partner of the framework. The development dependencies are the type definitions, the linter and the compiler.

The package version is 1.0.0 and the repository publishes no GitHub releases, so the version lives in the manifest rather than in a tag. The licence is BSD-3-Clause.

The repository layout is conventional for a web application, with an app directory, a library directory holding the drawing code, a public directory for the static assets, the entry point and the framework configuration, and a pnpm workspace file with a lock file. The drawing code itself is the interesting part, and the README documents how it works in four steps.

## The algorithm asks which line would look most like the original

The fourth numbered step in the README describes the trick, and it is the part that makes the tool interesting.

The image is first normalised for brightness and transformed to grayscale, with the aim of making the lightest zone white and the darkest black. Then a point in the canvas is selected at random, and a line starts looking for different paths to draw next. At each step the pencil draws imaginary lines to different points of the image and asks itself which one of those points would make the drawing look more like the original image, then it picks that one, draws the line and moves the cursor.

So the process is a greedy walk with a scoring function. Nothing is traced, nothing is fitted and no contour is extracted. The algorithm repeatedly asks a local question, and the result is a line that wanders across the picture while always trying to look like the picture.

The amount of imaginary lines is controlled by the definition slider, and the README explains the trade-off with a joke that also happens to be the right technical summary: more lines mean more precise but less terrifying images. Every candidate the pencil considers is drawn mentally and evaluated, so raising the definition means evaluating more candidates per step, which buys accuracy and costs a drawing that is arguably more frantic while it is being made.

The randomness at the start is what keeps the result from converging on one canonical trace. Different runs of the same image give different drawings, which is a feature when the output is meant to look handmade.

## Batched drawing, and an SVG that is only a polyline

The third and fourth steps cover how the drawing is made and how it leaves the tool.

Lines are batched to be drawn and get flushed almost every frame. That is a performance decision with a visible consequence: the drawing appears progressively on the canvas, and the batching is what stops the browser from doing one layout per segment. On a large image with a high definition setting, the number of candidate lines is large enough that drawing each one immediately would make the interaction unusable.

The export is the other end. Results are exported as SVG as a very simple polyline, which is to say the whole drawing is a single path element with a list of points, and the PNG export is taken directly from the canvas. There is no layer structure, no fill, no per-segment metadata. One path, one colour, one stroke.

That minimalism is not an accident, because the tool is aimed at plotters. A plotter draws a pen line, so the output format is exactly what a pen needs, and the README shows the results photographed after being drawn on an AxiDraw, with a credit to the person who helped make them.

The animated example makes the same point from another direction. It is an exported SVG animated using a library that draws the path progressively in the browser, so the single polyline becomes a stroke that appears over time, which is what a plotter does anyway. The output format and the animation are the same artefact.

## Face detection is what makes the portraits work

Two third-party libraries do the heavy lifting, and the README is precise about which does what.

Pixel data and resizing were made using a canvas image utility package. Better face definition was done with a face detection library, and this second one is the more interesting of the pair, because a portrait is the hard case for a greedy line walk.

The reason is the nature of the scoring function. The pencil asks which candidate point would make the drawing look more like the original, and for a face that question is dominated by the arrangement of the features rather than by the general tonal distribution. A drawing that gets the shape of the head and the shading right but places an eye in the wrong place looks wrong in a way that a photo of a building does not, because a human reader of a line drawing is looking for the face first.

So the face detection library changes what the candidate points are and how the comparison is weighted, and the README credits it with better face definition. It is a good example of a small dependency that changes the quality of the output rather than just enabling a feature.

The grayscale normalisation is the other half of the picture. Mapping the lightest zone to white and the darkest to black is what gives the line walk a stable target to chase, and it is why the tool produces the high contrast look associated with pen plotting rather than a grey wash.

## The core is being made platform neutral, and it is still local

There is a paragraph in the README that looks like a footnote and is really a roadmap.

The platform-neutral, incremental generator is documented in the core readme inside the library directory, and the README says it is currently a local module, and that this refactor does not create or publish a package.

Three things are happening there. The generator is being rewritten to be platform neutral, which means the same code can run in the browser and somewhere else, presumably a command line tool or a service, without a canvas. It is being made incremental, which means the drawing can be produced in steps rather than in one long pass, and that is what makes the per-frame flush in the browser possible in the first place. And it is not being published yet, which is the part an adopter has to notice.

So there is no package to add to a project today. The library is a set of files in a repository, with functions for grayscale conversion, for the scan, for the drawing and for the SVG generation, each of them linked from the README so a reader can follow the pipeline file by file.

For a web application that is a reasonable position, since the tool is the site. For somebody who wants the generator in their own pipeline, the work is to copy the code and to run the refactor to completion, and the README's core documentation is the place to see how far that has been taken.

## Conclusion

Adopt pintr if you want a fast line drawing of a picture, for a plotter, for an illustration or for a design reference, and you are willing to accept that the result is an approximation produced by a greedy walk rather than a traced contour. Do not adopt it as a vectoriser for artwork that has to match the source closely, because the algorithm optimises for resemblance rather than for fidelity. Before you rely on the output, check the definition setting, since it trades precision against how wild the intermediate drawing looks, and note that the core is a local module today, so there is no published package to depend on and you would be vendoring the code.

## FAQ

### What does pintr do with my images?

It turns them into plotter-like line drawings and single-line SVG illustrations. All the processing is made locally, the images never leave your computer, and the README says you are free to use them as you please. The project is BSD-3-Clause licensed.

### How does the pintr drawing algorithm work?

The image is normalised for brightness and turned to grayscale, then a random point is selected and a line starts looking for paths to draw. At each step the pencil draws imaginary lines to different points of the image and picks the one that would make the drawing look most like the original, then draws it and moves on.

### What does the definition slider change in pintr?

It controls how many imaginary lines the pencil considers at each step. The README says more lines mean more precise but less terrifying images, so the setting trades accuracy against how wild the intermediate drawing looks.

### What format does pintr export?

SVG, as a very simple polyline, which is a single path element holding the points. The PNG export is taken directly from the canvas. The README also shows the exported SVG animated with a library that draws the path progressively, and plotter drawings made with an AxiDraw.

### Can I install pintr as a package?

Not yet. The README says the platform-neutral incremental generator is documented in the core readme in the library directory, that it is currently a local module, and that the refactor does not create or publish a package. The application itself is a Next.js project with the usual development, build and start scripts.

## Sources

- [Issues](https://github.com/javierbyte/pintr/issues)
- [javierbyte/pintr on GitHub](https://github.com/javierbyte/pintr)
- [License: BSD-3-Clause](https://github.com/javierbyte/pintr/blob/master/LICENSE)
- [Project website](https://javier.xyz/pintr)
- [README](https://github.com/javierbyte/pintr/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/javierbyte-pintr
