Turtle Graphics Library

A modern turtle graphics library for Rust built on Macroquad with Lyon for high-quality GPU-accelerated rendering.

Features

  • 🎨 Simple Builder API: Chain commands like forward(100).right(90)
  • Smooth Animations: Tweening support with easing functions and live fill preview
  • 🚀 Instant Mode: Execute commands immediately without animation (speed ≥ 999)
  • 🎯 High-Quality Rendering: Complete Lyon tessellation pipeline with GPU acceleration
  • 🫟 Multi-Contour Fills: Automatic hole detection with EvenOdd fill rule - draw cheese with holes!
  • 📐 Self-Intersecting Paths: Stars, complex shapes - all handled correctly
  • 🐢 Multiple Turtle Shapes: Triangle, classic turtle, circle, square, arrow, and custom shapes
  • 🔍 Structured Logging: Optional tracing integration for debugging (zero overhead when disabled)
  • 💨 Lightweight: Fast compilation and runtime
  • 📤 SVG Export: Export drawings to SVG format with viewBox and padding (feature-gated)

Quick Start

The simplest example to draw a square:

//! Minimal turtle example - just 10 lines!
//!
//! This is the simplest possible turtle program using the macro.

use turtle_lib::*;

#[turtle_main]
fn hello() {
    turtle.set_pen_color(BLUE);
    for _ in 0..4 {
        turtle.forward(100.0);
        turtle.right(90.0);
    }
}

The turtle starts at the center of the window, facing right (0 degrees). The above code draws a blue square.

The turtle_main macro sets up the Macroquad window, turtle initialization, and main loop for you. It expands to code similar to this:

use macroquad::prelude::*;
use turtle_lib::*;

#[macroquad::main("Turtle")]
async fn main() {
    // Create a turtle plan
    let mut plan = create_turtle_plan();

    // Set speed (part of the plan)
    plan.set_speed(100);

    // Draw a square
    for _ in 0..4 {
        plan.forward(100).right(90);
    }

    // Create app (speed is managed by commands)
    let mut app = TurtleApp::new().with_commands(plan.build());

    loop {
        clear_background(WHITE);
        app.update();
        app.render();
        next_frame().await
    }
}

API Overview

Creating Plans

let mut plan = create_turtle_plan();

// Movement
plan.forward(100);
plan.backward(50);

// Rotation
plan.left(90);    // degrees
plan.right(45);

// Circular arcs
plan.circle_left(50.0, 180.0, 36);   // radius, angle (degrees), segments
plan.circle_right(50.0, 180.0, 36);  // draws arc to the right

// Pen control
plan.pen_up();
plan.pen_down();

// Filling (with automatic hole detection)
plan.set_fill_color(BLUE);
plan.begin_fill();
// ... draw shape ...
plan.end_fill();  // Auto-closes and applies fill

// Appearance
plan.set_color(RED);
plan.set_pen_width(5.0);
plan.hide();
plan.show();

// Speed control (dynamic)
plan.set_speed(100);  // Animated mode (< 999)
plan.set_speed(1000); // Instant mode (>= 999)

// Turtle shapes
plan.shape(ShapeType::Triangle);
plan.shape(ShapeType::Turtle);    // Classic turtle shape
plan.shape(ShapeType::Circle);
plan.shape(ShapeType::Square);
plan.shape(ShapeType::Arrow);

// Custom shapes
let custom = TurtleShape::new(
    vec![vec2(10.0, 0.0), vec2(-5.0, 5.0), vec2(-5.0, -5.0)],
    true  // filled
);
plan.set_shape(custom);

// Method chaining
plan.forward(100).right(90).forward(50);

Execution Modes

Speed controlled via commands, allowing dynamic switching during execution:

let mut plan = create_turtle_plan();

// Fast initial positioning (instant mode)
plan.set_speed(1000);
plan.pen_up();
plan.goto(vec2(-100.0, -100.0));

// Slow animated drawing
plan.set_speed(50);
plan.pen_down();
plan.forward(200);
plan.right(90);

// Create app
let app = TurtleApp::new().with_commands(plan.build());

Speed Modes:

  • Speed < 1000: Animated mode with smooth tweening
  • Speed >= 1000: Instant mode (no animation) the bigger the number the more segments will be added per frame.
  • Default speed is 100.0 if not specified

Debugging and Logging

The library uses tracing for structured diagnostic logging. This is completely optional - if you don't set up a subscriber, there's zero overhead.

Enable Logging

// Add to your Cargo.toml:
// tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }

tracing_subscriber::fmt()
    .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
    .init();

Control verbosity with the RUST_LOG environment variable:

# Show debug output
RUST_LOG=turtle_lib=debug cargo run

# Very verbose trace output
RUST_LOG=turtle_lib=trace cargo run

See the complete example: examples/logging_example.rs demonstrates initialization, log levels, filtering, and example output.

SVG Export

Export your turtle drawings to SVG format for use in web applications, vector graphics editors, or further processing.

Enabling SVG Export

Add the svg feature to enable SVG export functionality:

cargo run --example export_svg --features svg

Command-Line SVG Export

When using the turtle_main macro with the svg feature enabled, you can export drawings directly to SVG files using the --export-svg command-line parameter:

# Export any example to SVG without showing the window
cargo run --example macro_demo --features svg -- --export-svg output.svg

# Works with all turtle_main-based examples
cargo run --example hello_turtle --features svg -- --export-svg square.svg

This will:

  • Execute all drawing commands instantly (no animation)
  • Export the result to an SVG file
  • Exit immediately without opening a window

Programmatic SVG Export

You can also export SVG programmatically from your code:

use turtle_lib::*;

// Create your drawing
let mut plan = create_turtle();
plan.forward(100).right(90).forward(100);

// Create app
let mut app = TurtleApp::new().with_commands(plan.build());

// Export to SVG
app.export_drawing("drawing.svg", export::DrawingFormat::Svg)?;

Features

  • Complete Primitive Support: Lines, circles, arcs, polygons, and fills
  • Automatic viewBox: Includes 20px padding around the entire drawing
  • Color and Styling: Preserves colors, pen width, and fill colors
  • Multi-Contour Fills: Exports complex fills with holes using SVG paths
  • Text Support: Exports text elements with positioning

Example

See examples/export_svg.rs for a complete example that draws various shapes and exports them to SVG.

The exported SVG can be opened in any web browser or vector graphics application.

Examples

Run examples with:

cargo run --example square
cargo run --example koch
cargo run --example shapes
cargo run --example yinyang
cargo run --example stern
cargo run --example nikolaus

# SVG export example (requires --features svg)
cargo run --example export_svg --features svg

# Export any example to SVG using CLI parameter (requires --features svg)
cargo run --example macro_demo --features svg -- --export-svg output.svg
cargo run --example hello_turtle --features svg -- --export-svg square.svg

# Logging example - shows how to enable debug output
cargo run --example logging_example
RUST_LOG=turtle_lib=debug cargo run --example logging_example

Available Examples

Basic Drawing

  • square.rs: Basic square drawing
  • koch.rs: Koch snowflake fractal
  • shapes.rs: Demonstrates different turtle shapes
  • stern.rs: Star pattern drawing
  • nikolaus.rs: Nikolaus (Santa) drawing

Fill Examples

  • yinyang.rs: Yin-yang symbol with automatic hole detection
  • fill_demo.rs: Donut shape with hole
  • fill_requirements.rs: Circle with red fill
  • fill_advanced.rs: Complex shapes (star, swiss cheese, multiple holes)
  • fill_circle_test.rs: Circle fills with different angles
  • fill_instant_test.rs: Quick fill test in instant mode

Export

  • export_svg.rs: Demonstrates SVG export functionality (requires --features svg)

Debugging

  • logging_example.rs: Demonstrates how to enable and use tracing/logging output

Basic Fill

let mut plan = create_turtle();
plan.set_fill_color(RED);
plan.begin_fill();

// Draw shape
for _ in 0..4 {
    plan.forward(100);
    plan.right(90);
}

plan.end_fill();  // Auto-closes and fills

Fill with Holes (Multi-Contour)

plan.set_fill_color(BLUE);
plan.begin_fill();

// Outer circle (first contour)
plan.circle_left(90.0, 360.0, 72);

// pen_up() closes current contour
plan.pen_up();
plan.goto(vec2(0.0, -30.0));

// pen_down() starts new contour
plan.pen_down();

// Inner circle (becomes a hole automatically with EvenOdd rule!)
plan.circle_left(30.0, 360.0, 36);

plan.end_fill();  // Auto-detects holes and fills correctly

Architecture

Module Structure

turtle-lib/src/
├── lib.rs          - Public API and TurtleApp
├── state.rs        - TurtleState and TurtleWorld
├── commands.rs     - TurtleCommand enum (consolidated commands)
├── builders.rs     - Builder traits (DirectionalMovement, Turnable, etc.)
├── execution.rs    - Command execution with fill support
├── tweening.rs     - Animation/tweening controller with dynamic speed
├── drawing.rs      - Rendering with Lyon tessellation
├── shapes.rs       - Turtle shape definitions
├── tessellation.rs - Lyon tessellation utilities
├── circle_geometry.rs - Circle arc calculations
└── general/        - Type definitions (Angle, Length, etc.)

Workspace Structure

turtlers/
├── turtle-lib/         - Main library (Macroquad + Lyon)
└── turtle-lib-macros/  - Procedural macros (turtle_main)

Building and Running

# Check all packages
cargo check

# Run specific example
cargo run --example yinyang

# Run SVG export example (requires svg feature)
cargo run --example export_svg --features svg

# Build release version
cargo build --release

# Build with SVG support
cargo build --features svg

Development Status

Completed

  • Turtle movement and rotation (consolidated Move/Turn commands)
  • Pen control (up/down) with contour management
  • Color and pen width
  • Circle arcs (left/right with unified Circle command)
  • Dynamic speed control via SetSpeed commands
  • Instant mode (speed ≥ 1000) and animated mode (speed < 1000)
  • Multi-contour fill system with automatic hole detection
  • Lyon integration for all drawing primitives
  • Multiple turtle shapes with custom shape support
  • Tweening system with easing functions
  • EvenOdd fill rule for complex self-intersecting paths
  • Live fill preview during animation with progressive rendering
  • Multi-contour support - pen_up/pen_down manage contours
  • SVG Export - Export drawings to SVG with viewBox and padding (feature-gated)

License

MIT OR Apache-2.0

Contributing

Contributions are welcome! The library now has a stable foundation with complete Lyon integration and multi-contour fill support.

Description
No description provided
Readme 844 KiB
Languages
Rust 100%