A Rust-based 2D graphics generation tool inspired by DrawBot and Processing. Create vector graphics, images, and animations through Rust code. This should be a fun way for type designers, graphic designers, artists, and students to learn Rust programming.
- 🎨 DrawBot-inspired API - Familiar drawing primitives (rect, oval, line, polygon, etc)
- 🎯 Self-contained - Zero system dependencies
- 📦 Multiple output formats - PNG (more coming: SVG, PDF, GIF, MP4)
This is the easiest way to install and ensures you get the latest version:
cargo install --git https://github.com/eliheuer/designbot designbot-cliIf you're contributing to DesignBot or testing local changes:
# Clone the repository
git clone https://github.com/eliheuer/designbot
cd designbot
# Install the CLI (will use git dependencies for user scripts)
cargo install --path designbot-cli --forceImportant: After making local changes, you must push them to GitHub's main branch before the installed CLI can use them when compiling user scripts.
After installation, the designbot command will be available in your terminal (usually in ~/.cargo/bin/designbot).
First run: The CLI will compile dependencies (takes ~1-2 minutes)
Subsequent runs: Uses a persistent cache at ~/.designbot/cache (~0.5 seconds)
To clear the cache if needed:
rm -rf ~/.designbot/cache# Create a simple design script
designbot --render my_design.rs --output my_design.pngPerfect for type designers testing fonts:
// font_test.rs
use designbot::prelude::*;
fn main() {
let mut ctx = Canvas::new(1200.0, 800.0);
let mut renderer = Renderer::new(1200, 800);
// Load your font
renderer.load_font("fonts/MyFont-Regular.ttf").unwrap();
ctx.background(Color::rgb(255, 255, 255));
ctx.fill(Color::rgb(0, 0, 0));
ctx.font("MyFont");
// Test different sizes
ctx.font_size(72.0);
ctx.text("The quick brown fox", 50.0, 100.0);
ctx.font_size(48.0);
ctx.text("jumps over the lazy dog", 50.0, 200.0);
ctx.font_size(24.0);
ctx.text("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 50.0, 300.0);
ctx.text("abcdefghijklmnopqrstuvwxyz", 50.0, 350.0);
ctx.text("0123456789 !@#$%^&*()", 50.0, 400.0);
renderer.render_to_png(&ctx, "font_test.png").unwrap();
}Run with:
designbot --render font_test.rs --output font_test.pngExamples output to the current directory:
# Run from the designbot git repo
cd designbot
cargo run --example basic_shapesThis generates basic_shapes.png in your current directory.
Create a file my_design.rs:
use designbot::prelude::*;
// Just drawing commands - no main function needed
ctx.fill(Color::rgb(255, 100, 100));
ctx.rect(100.0, 100.0, 400.0, 400.0);
ctx.fill(Color::rgb(100, 255, 100));
ctx.oval(200.0, 200.0, 200.0, 200.0);Run with:
designbot --render my_design.rs --output my_design.pngCreate a file custom_design.rs:
use designbot::prelude::*;
fn main() {
let mut ctx = Canvas::new(800.0, 600.0);
// Draw shapes
ctx.fill(Color::rgb(255, 200, 100));
ctx.rect(100.0, 100.0, 600.0, 400.0);
// Render
let renderer = Renderer::new(800, 600);
renderer.render_to_png(&ctx, "output.png").unwrap();
}Run with:
designbot --render custom_design.rs --output custom.pngCreate examples in examples/ directory:
// examples/my_example.rs
use designbot::prelude::*;
fn main() {
let mut ctx = Canvas::new(600.0, 600.0);
ctx.fill(Color::rgb(100, 200, 255));
ctx.oval(100.0, 100.0, 400.0, 400.0);
// Output to current directory
let renderer = Renderer::new(600, 600);
renderer.render_to_png(&ctx, "my_example.png").unwrap();
println!("Rendered my_example.png");
}Run with:
cargo run --example my_example
# Generates my_example.png in current directorylet mut ctx = Canvas::new(800.0, 600.0);ctx.rect(x, y, width, height);
ctx.oval(x, y, width, height);
ctx.line(x1, y1, x2, y2);
ctx.polygon(&[(x1, y1), (x2, y2), ...], close);ctx.fill(Color::rgb(255, 0, 0));
ctx.stroke(Color::black());
ctx.stroke_width(2.0);
ctx.no_fill();
ctx.no_stroke();ctx.save(); // Push state
ctx.translate(x, y);
ctx.rotate(degrees);
ctx.scale(factor);
ctx.restore(); // Pop state// Set font and size
ctx.font("Arial");
ctx.font_size(48.0);
ctx.fill(Color::black());
// Draw single-line text
ctx.text("Hello World", 100.0, 100.0);
// Draw multi-line text box with word wrapping
ctx.text_box("Long text that wraps...", 100.0, 200.0, 400.0, 200.0);// Load custom fonts from files
let mut renderer = Renderer::new(800, 600);
renderer.load_font("fonts/MyFont-Regular.ttf").unwrap();
renderer.load_font("fonts/MyFont-Bold.ttf").unwrap();
// Use the loaded fonts
ctx.font("MyFont");
ctx.text("Custom Font", 100.0, 100.0);
// System fonts still work too
ctx.font("Arial");
ctx.text("System Font", 100.0, 200.0);let renderer = Renderer::new(width, height);
renderer.render_to_png(&ctx, "output.png").unwrap();designbot/
├── designbot/ # Core library (Canvas, Colors, Shapes)
├── designbot-render/ # Rendering backend (Vello integration)
├── designbot-cli/ # CLI application
├── examples/ # Example scripts with outputs
└── docs/ # Documentation and project plan
- vello_cpu - CPU-based 2D rendering (faster for reading back to CPU memory)
- AnyRender - Portable rendering abstraction across backends
- Kurbo - 2D curves and paths (including native Ellipse type)
- Peniko - Styling primitives
- wgpu - GPU access
- image - Image encoding/decoding
✅ Phase 1 Complete: Basic rendering infrastructure
- Project structure and workspace
- CLI with script compilation
- Vello renderer integration
- PNG output
- Canvas management
✅ Phase 2 Complete: Core drawing API
- Shape primitives (rect, oval, line, polygon)
- Fill and stroke colors
- Graphics state stack (save/restore)
- Basic transformations (translate, rotate, scale)
- Text rendering with Parley
- Custom font loading
- Path operations (bezier curves)
🔧 Current Improvements:
- Migrating to vello_cpu for better CPU readback performance
- Integrating AnyRender for portable rendering across backends
- Using Kurbo's native Ellipse type for oval rendering
🔜 Coming Soon:
- Gradients
- Image placement
- SVG/PDF output
- Animation support
- Advanced path operations
See docs/PROJECT_PLAN.md for the full roadmap.
# Run tests
cargo test
# Build all packages
cargo build --workspace
# Run clippy
cargo clippy --workspace
# Format code
cargo fmt --allCheck out the examples/ directory for more:
basic_shapes.rs- All primitive shapes (rect, oval, line, polygon)basic_text.rs- Text rendering and custom font loadinggrid.rs- Using state transformations for layout- More examples coming soon!
To run the text examples with custom fonts:
- Create
examples/fonts/directory (already exists) - Download fonts (e.g., Inter) and place
.ttffiles in the directory - See
examples/fonts/README.mdfor detailed setup instructions
The examples will fall back to system fonts if custom fonts aren't found.
Apache-2.0
Inspired by DrawBot by Just van Rossum and Frederik Berlaen. Built on crates from the Linebender ecosystem.