Turn a photo into string art – thousands of straight threads stretched between nails on a round or square board. String Art Studio computes the thread path, shows a realistic preview while it works, and then guides you through building the real piece step by step.
Desktop app (Electron) · runs fully offline · English, Čeština, Deutsch, Українська, Español · MIT
- Photo → threads in about a second. Crop, zoom and rotate the photo on the board; brightness, contrast and detail sliders show exactly what the generator sees.
- Realistic preview. Threads are rendered with their real thickness relative to the board, so the preview looks like the finished piece – not like a pencil sketch.
- Stops when the picture is done. Light areas need fewer threads; the generator stops when more thread would only make the picture worse (or use an exact thread count).
- Board options. Circle or square, 15–150 cm, 120–360 nails, board and thread colours (including light thread on a dark board).
- Build mode. A big “A16 → C23” display, keyboard control (Space / arrows), auto-advance with a timer and read-aloud, progress that survives closing the app.
- Printable guide (PDF). Materials, thread length, build time, a real-size nail template split across A4 pages with overlap strips and registration crosses, and every step with a checkbox.
- Exports. Nail template SVG (1:1 for a print shop or plotter), PNG 4000 px, vector SVG, steps as
TXT / CSV / JSON (nail coordinates in mm for machines),
.stringartproject files.
| Compare with the photo | Build step by step |
|---|---|
![]() |
![]() |
app/renderer/engine.js – no dependencies, runs in a Web Worker.
- The photo is converted to luminance (with brightness/contrast/detail) and every pixel is expressed as the number of thread crossings it needs: one crossing of a thread of thickness t over a pixel of size p covers c = t / p of it, so after k crossings the pixel brightness is (1 − c)^k.
- Starting from the best line, the generator repeatedly looks at every nail reachable from the current one and picks the chord that removes the most squared error in that “crossings” space (anti-aliased, length-corrected rasterisation). Light pixels push threads away instead of slowly turning the image grey.
- Rules that matter on a real board: a minimum nail skip, no pair used twice, no thread along a square board’s edge, and a continuous thread (each step starts where the last one ended).
- The preview uses the same physical model (exact sub-pixel coverage per thread), so it matches the finished piece.
Requires Node.js 20+.
cd app
npm install
npm start # run the app
npm test # engine unit tests
npm run dist # Windows installer + portable .exe in app/distThe renderer is a plain static page (app/renderer/index.html), so it also runs in a browser served
from any static web server – saving then falls back to downloads.
app/
main.js, preload.js Electron shell: window, file dialogs, PDF printing, .stringart files
renderer/engine.js generator + thread renderer (shared by the app and the tests)
renderer/worker.js runs the generator off the UI thread, streams threads for the live preview
renderer/app.js UI, build mode, exports, printable guide
renderer/i18n.js translations
test/ node:test unit tests
tools/icon.py draws the app icon from geometry
tools/smoke.js dev-only UI smoke test (screenshots + exports)
The original Python/Tkinter prototype is kept in the git history (first commit, d300f74).
Fonts: Fraunces and Inter,
both SIL Open Font License (see app/renderer/fonts). Screenshots use Johannes Vermeer’s
Girl with a Pearl Earring (c. 1665, public domain).
MIT – see LICENSE.


