12 releases
Uses new Rust 2024
| new 0.2.8 | Feb 15, 2026 |
|---|---|
| 0.2.7 | Feb 15, 2026 |
| 0.2.5 | Jan 22, 2026 |
| 0.1.2 | Dec 29, 2025 |
| 0.0.1 | May 28, 2025 |
#169 in Graphics APIs
195KB
4.5K
SLoC
spottedcat
A simple, clean 2D graphics library for drawing images using Rust and wgpu.
Features
- Simple API: Only 4 main types to learn:
Context,Spot,Image, andrun - GPU-accelerated: Built on wgpu for high-performance rendering
- Image operations: Load from files, create from raw data, extract sub-images
- Flexible drawing: Position, scale, rotate images with ease
Quick Start
Add to your Cargo.toml:
[dependencies]
spottedcat = { version = "0.1.0" }
Basic Example
use spottedcat::{Context, Spot, Image, DrawOption};
struct MyApp {
image: Image,
}
impl Spot for MyApp {
fn initialize(_context: &mut Context) -> Self {
let image = Image::new_from_file("image.png")
.expect("Failed to load image");
Self { image }
}
fn draw(&mut self, context: &mut Context) {
let opts = DrawOption::default()
.with_position([spottedcat::Pt::from(100.0), spottedcat::Pt::from(100.0)])
.with_scale([2.0, 2.0]);
self.image.draw(context, opts);
}
fn update(&mut self, _context: &mut spottedcat::Context, _dt: std::time::Duration) {}
fn remove(&self) {}
}
fn main() {
spottedcat::run::<MyApp>(spottedcat::WindowConfig::default());
}
API Overview
Core Types
Context
Drawing context for managing render commands. Accumulates drawing operations during a frame.
Methods:
new()- Create a new contextbegin_frame()- Clear previous frame's commands- Use
Image::draw(context, options)to queue an image for drawing
Spot (trait)
Main application trait defining the lifecycle of your app.
Required methods:
initialize(&mut context)- Set up initial state and load resourcesdraw(&mut context)- Render the current frameupdate(event)- Handle events (reserved for future use)remove()- Cleanup on shutdown
Image
Handle to a GPU texture that can be drawn to the screen.
Methods:
new_from_rgba8(width, height, rgba)- Create from raw pixel datanew_from_file(path)- Load from image file (PNG, JPEG, etc.)new_from_image(image)- Clone an existing imagesub_image(image, bounds)- Extract a region from an imagedestroy()- Free GPU resources
DrawOptions
Options for controlling how images are rendered.
Fields:
position: [f32; 2]- Top-left corner in screen pixelsrotation: f32- Rotation in radiansscale: [f32; 2]- Scale factors (applied after the image's intrinsic size)
Bounds
Rectangle for defining sub-regions of images.
Fields:
x: u32- X coordinatey: u32- Y coordinatewidth: u32- Widthheight: u32- Height
Functions
run(init)
Main entry point. Creates a window, initializes graphics, and runs the event loop.
Arguments:
init: fn(&mut Context) -> Box<dyn Spot>- Function to create your app
Advanced Usage
Creating Sub-Images
Extract regions from existing images without duplicating GPU memory:
let full_image = Image::new_from_file("spritesheet.png")?;
let sprite = Image::sub_image(
full_image,
Bounds::new(0, 0, 32, 32)
)?;
Drawing with Transformations
let opts = DrawOption::default()
.with_position([spottedcat::Pt::from(400.0), spottedcat::Pt::from(300.0)])
.with_rotation(std::f32::consts::PI / 4.0) // 45 degrees
.with_scale([2.0, 2.0]); // Double size
image.draw(&mut context, opts);
Creating Images from Raw Data
let mut rgba = vec![0u8; 64 * 64 * 4];
// Fill with your pixel data...
let image = Image::new_from_rgba8(64, 64, &rgba)?;
Dependencies
~17–42MB
~589K SLoC