| Crates.io | perfect_freehand |
| lib.rs | perfect_freehand |
| version | 0.1.0 |
| created_at | 2025-12-20 15:51:01.843257+00 |
| updated_at | 2025-12-20 15:51:01.843257+00 |
| description | A Rust port of the perfect-freehand library for creating smooth, beautiful freehand lines |
| homepage | https://github.com/sibaiper/perfect_freehand |
| repository | https://github.com/sibaiper/perfect_freehand |
| max_upload_size | |
| id | 1996654 |
| size | 32,571 |
A Rust port of perfect-freehand library
A library for creating smooth, natural-looking freehand strokes from input points. It produces an array of outline points that form a polygon around the input, perfect for drawing applications.
Add this to your Cargo.toml:
[dependencies]
perfect_freehand = "0.1"
The main function is get_stroke(), which takes an array of input points (like those from mouse movements) and returns a vector of outline points forming a smooth stroke polygon.
// pseudocode-ish
use perfect_freehand::{get_stroke, InputPoint, StrokeOptions};
fn main() {
// Collect input points from user (e.g., mouse coordinates)
let points = vec![
InputPoint::Array([100.0, 100.0], Some(0.5)),
InputPoint::Array([200.0, 150.0], Some(0.7)),
InputPoint::Array([300.0, 100.0], Some(0.5)),
// ... more points
];
// Create default options
let options = StrokeOptions::default();
// Generate the stroke outline
let outline = get_stroke(&points, &options);
// Use the outline points to draw a path
// (e.g., convert to SVG or render with a graphics library)
}
You can render the stroke points with any graphics library. Here's an example using a hypothetical graphics backend:
use perfect_freehand::{get_stroke, InputPoint, StrokeOptions};
fn render_stroke(points: &[InputPoint]) {
let options = StrokeOptions::default();
let outline = get_stroke(points, &options);
// Draw the polygon outline
for i in 0..outline.len() {
let p1 = outline[i];
let p2 = outline[(i + 1) % outline.len()];
draw_line(p1, p2);
}
}
To get filled strokes, you can triangulate the polygon using a library like earcutr and then render the triangles:
use perfect_freehand::{get_stroke, InputPoint, StrokeOptions};
use earcutr::earcut;
fn render_filled_stroke(points: &[InputPoint]) {
let options = StrokeOptions::default();
let outline = get_stroke(points, &options);
// Convert to vertex coordinates
let mut vertices: Vec<f64> = Vec::new();
for p in &outline {
vertices.push(p[0]);
vertices.push(p[1]);
}
// Triangulate
let triangles = earcut(&vertices, &[], 2);
// Draw each triangle
for tri in triangles.chunks(3) {
let a = outline[tri[0]];
let b = outline[tri[1]];
let c = outline[tri[2]];
draw_triangle(a, b, c);
}
}
This project is a port of perfect-freehand
by Steve Ruiz. Huge thanks to him for the original work. This Rust implementation is based on and improves upon previous Rust ports of the library.
This project is licensed as the original under the MIT License.
Copyright (c) 2021 Steve Ruiz - Original
Copyright (c) 2025 Sibai Eshak - Rust port