A tiny Rust + WASM library that converts SVG path data to flattened polylines using the Lyon geometry library.
- 🚀 Fast: Built with Rust and Lyon for optimal performance
- 🎯 Adaptive flattening: Uses tolerance-based curve approximation (not fixed steps)
- 📦 Tiny: Optimized WASM binary for minimal size
- 🔧 Easy integration: Returns points ready for use with libraries like Clipper
- ✅ SVG compatible: Supports most common SVG path commands (M, L, H, V, C, Q, Z)
- Install Rust: https://rustup.rs/
- Install wasm-pack:
cargo install wasm-pack - (Optional) Install wasm-opt for further optimization: https://github.com/WebAssembly/binaryen
Windows:
build.batUnix/Linux/macOS:
chmod +x build.sh
./build.shManual build:
wasm-pack build --target web --out-dir pkg --release<!DOCTYPE html>
<html>
<head>
<script type="module">
import init, { flatten_svg_path } from './pkg/svg_flatten.js';
async function run() {
await init();
// SVG path data
const pathData = "M10,10 C20,20 30,20 40,10 L50,5 Z";
const tolerance = 0.1; // Lower = more points, higher = fewer points
try {
const flattened = flatten_svg_path(pathData, tolerance);
// Get points as flat array [x1, y1, x2, y2, ...]
const points = flattened.get_flat_array();
console.log('Flattened points:', points);
// Or access individual points
for (let i = 0; i < flattened.length; i++) {
const x = flattened.get_x(i);
const y = flattened.get_y(i);
console.log(`Point ${i}: (${x}, ${y})`);
}
flattened.free(); // Clean up memory
} catch (error) {
console.error('Error flattening path:', error);
}
}
run();
</script>
</head>
<body>
<h1>SVG Flatten Demo</h1>
<p>Check the console for output</p>
</body>
</html>import init, { flatten_svg_path } from './pkg/svg_flatten.js';
async function example() {
await init();
const pathData = "M0,0 Q50,50 100,0";
const tolerance = 1.0;
const flattened = flatten_svg_path(pathData, tolerance);
const points = flattened.get_flat_array();
console.log('Points:', points);
flattened.free();
}
example();Flattens an SVG path data string into a polyline.
Parameters:
d: SVG path data string (e.g., "M10,10 C20,20 30,20 40,10")tolerance: Flattening tolerance. Lower values = more points, higher precision
Returns: FlattenedPath object
length: Number of points in the flattened pathget_point(index): Get a point at the given indexget_x(index)/get_y(index): Get X/Y coordinate at indexget_flat_array(): Get all points as[x1, y1, x2, y2, ...]arrayfree(): Clean up memory (important!)
| Command | Description | Status |
|---|---|---|
| M, m | Move to | ✅ |
| L, l | Line to | ✅ |
| H, h | Horizontal line | ✅ |
| V, v | Vertical line | ✅ |
| C, c | Cubic Bézier curve | ✅ |
| Q, q | Quadratic Bézier curve | ✅ |
| Z, z | Close path | ✅ |
| S, s | Smooth cubic Bézier | ❌ |
| T, t | Smooth quadratic Bézier | ❌ |
| A, a | Elliptical arc | ❌ |
- 0.01-0.1: High precision, many points (good for small shapes)
- 0.1-1.0: Medium precision, balanced (good for most use cases)
- 1.0-5.0: Low precision, few points (good for large shapes or performance)
The flattened points can be directly used with polygon clipping libraries:
// For clipper-lib or similar
const points = flattened.get_flat_array();
const polygonPath = [];
for (let i = 0; i < points.length; i += 2) {
polygonPath.push({ X: points[i], Y: points[i + 1] });
}MIT License - feel free to use in your projects!