Skip to content

snakemode/PathMerge

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PathMerge

Join fragmented handwriting strokes in an SVG into continuous paths.

Handwriting fonts vectorised to SVG often emit each letter as many tiny path fragments rather than one stroke. PathMerge reconnects fragments whose endpoints touch (or very nearly touch) into single continuous paths, while leaving genuinely separate letters and strokes alone.

Usage

npm install
npx tsx src/index.ts page3.svg
# or: npm run connect -- page3.svg

The result is written next to the input: page3.svgpage3.connected.svg.

Multiple files and wildcards

Pass several files, a glob, or any mix of the two. Each file is processed independently and gets its own <name>.connected.svg:

npx tsx src/index.ts page1.svg page2.svg     # explicit list
npx tsx src/index.ts 'page*.svg'             # glob (quote it!)

Quote globs so the shell passes the pattern through unexpanded — PathMerge expands it itself, so the behaviour is identical on every platform. Duplicate matches are de-duplicated, and one unreadable or path-less file is reported without aborting the rest of the batch (the process exits non-zero if any file failed).

Options

Flag Default Meaning
--tolerance, -t 0.5 Max gap between two endpoints to treat them as connected (in SVG user units).
--decimals, -d 2 Coordinate precision in the output.
--stats off Print a histogram of nearest-endpoint distances (handy for tuning tolerance).
npx tsx src/index.ts page3.svg --tolerance 0.5 --stats

How it works

  1. Parse every <path> d string into segments with absolute coordinates (relative commands, H/V/S/T shorthands and arcs are all normalised). Working in absolute space means strokes can be reordered, reversed and joined with no relative-offset drift.
  2. Reduce each open stroke to its two endpoints.
  3. Cluster endpoints that fall within tolerance of each other into shared nodes (union-find over a uniform spatial grid, so it stays near-linear).
  4. Build a multigraph whose nodes are those clusters and whose edges are the strokes, then decompose each connected component into trails — continuous walks that never reuse a stroke. Greedy edge-removal walks are used (not Hierholzer) because stroke crossings create junctions of degree ≥ 3 where a component isn't traceable as a single trail; a greedy walk started at an odd-degree vertex provably can't get stuck mid-stroke, so every trail is a genuine gap-free chain.
  5. Emit each trail as one continuous path (orienting/reversing strokes as needed). Closed (Z) shapes and compound paths are passed through untouched.

Choosing a tolerance

--stats shows that for typical exports the touching joints cluster at ≤0.05 units while real inter-letter spacing only begins around ~1.5 units, with a wide flat gap in between. The default of 0.5 sits safely in that gap: it absorbs both exact joints and imperceptible vectorisation near-misses without fusing letters that should stay apart.

Development

npm test        # run the unit tests
npm run typecheck

About

Merge SVG handwriting paths

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors