perfect_freehand 0.1.0

A Rust port of the perfect-freehand library for creating smooth, beautiful freehand lines
Documentation
  • Coverage
  • 45%
    27 out of 60 items documented0 out of 27 items with examples
  • Size
  • Source code size: 32.05 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 3.5 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 17s Average build duration of successful builds.
  • all releases: 15s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Homepage
  • Repository
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • sibaiper

Perfect Freehand

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.

Installation

Add this to your Cargo.toml:

[dependencies]

perfect_freehand = "0.1"

Usage

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)
}

Rendering

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);
    }
}

Acknowledgements

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.

License

This project is licensed as the original under the MIT License.


Copyright (c) 2021 Steve Ruiz - Original
Copyright (c) 2025 Sibai Eshak - Rust port