Runeforge ๐ฅโ๏ธ
A modern, modular roguelike library for Rust
๐ฏ About
Runeforge is a pure Rust roguelike library inspired by libtcod, combining a familiar API with modern Rust best practices and GPU-accelerated rendering.
Why Runeforge?
- ๐ฆ Pure Rust - No C dependencies, easier builds
- ๐ฆ Modular - Use only what you need
- โก Fast - GPU-accelerated rendering with wgpu
- ๐ Cross-platform - Windows, macOS, Linux, and WebAssembly
- ๐ Well-documented - Complete API docs and tutorials
- ๐ฎ libtcod-compatible - Familiar API for easy migration
๐ Quick Start
Installation
Add Runeforge to your Cargo.toml:
[dependencies]
runeforge-rl = "0.1"
Hello World
use runeforge_rl::prelude::*;
fn main() {
let mut rng = Rng::new();
let point = IVec2::new(10, 20);
let color = Color::RED;
println!("Random d6 roll: {}", rng.roll_dice(1, 6));
println!("IVec2 at ({:?})", point);
println!("Color: {}", color);
}
๐ฆ Crate Structure
Runeforge is organized as a modular workspace:
| Crate | Description | Status |
|---|---|---|
runeforge-algorithms | Procedural map generation (BSP, Caves, etc.) | โ Complete |
runeforge-color | RGB/HSV color manipulation | โ Complete |
runeforge-direction | Grid-based direction handling | โ Complete |
runeforge-fov | Field-of-view algorithms | โ Complete |
runeforge-geometry | 2D primitives (IVec2, Rect) | โ Complete |
runeforge-input | Keyboard and mouse input | โ Complete |
runeforge-noise | Procedural noise generation | โ Complete |
runeforge-pathfinding | A* and Dijkstra pathfinding | โ Complete |
runeforge-random | RNG with dice notation | โ Complete |
runeforge-terminal | Console rendering (CPU/GPU/ANSI) | โ Complete |
runeforge-tileset | Font and tileset loading | โ Complete |
๐จ Features
Current Features (v0.1)
- โ Color System: RGB/HSV conversion, blending, named colors
- โ Geometry: IVec2 and Rect types with iterators
- โ
Random Numbers: Seedable RNG, dice notation parsing (
3d6+2), weighted selection - โ FOV Algorithms: Symmetric shadowcasting with precise fraction-based calculation
- โ
Pathfinding: A* and Dijkstra pathfinding via the
pathfindingcrate - โ Procedural Generation: BSP dungeons, Cellular Automata caves, and Drunkardโs Walk tunnels
- โ Noise Generation: 2D Perlin noise maps
- โ
Rendering:
- Abstract
Consoletrait for backend-agnostic code - Software backend (CPU buffer, PNG export)
- Terminal backend (ANSI escape codes)
- Abstract
- โ Tilesets: Support for TrueType/OpenType fonts and bitmap tilesets
- โ Input: Action-based input mapping (keyboard/mouse) with support for vi-keys, WASD, arrows
๐ License
Runeforge is licensed under the BSD-3-Clause License, the same as libtcod.
This allows commercial use, modification, and distribution with minimal restrictions.
Getting Started
Welcome to Runeforge! This guide will help you set up your development environment and create your first roguelike application.
Prerequisites
- Rust: You will need a recent version of the Rust toolchain installed. We recommend the latest stable version.
- Install via rustup.rs
Next Steps
- Installation: Add Runeforge to your project.
- Hello World: Write your first Runeforge program.
Installation
Runeforge is available on crates.io.
Adding to Cargo.toml
Add the following to your projectโs Cargo.toml file under [dependencies]:
[dependencies]
runeforge-rl = "0.1"
Feature Flags
Runeforge is modular. By default, it includes the most common features. You can customize your build by enabling or disabling features:
[dependencies]
runeforge-rl = { version = "0.1", default-features = false, features = ["render-wgpu", "fov", "pathfinding"] }
Available Features
render-wgpu: Enable GPU-accelerated rendering (default).render-software: Enable software rendering backend.render-terminal: Enable ANSI terminal backend.fov: Field-of-view algorithms.pathfinding: Pathfinding algorithms.noise: Procedural noise generation.serialization: Serde support for core types.
Hello World
Here is a minimal example to verify that Runeforge is installed and working correctly.
The Code
Create a file named main.rs in your projectโs src directory:
use runeforge_rl::prelude::*;
fn main() {
// Initialize the random number generator
let mut rng = Rng::new();
// Create a 2D integer vector (point)
let point = IVec2::new(10, 20);
// Define a color
let color = Color::RED;
println!("Runeforge Hello World!");
println!("----------------------");
println!("Random d6 roll: {}", rng.roll_dice(1, 6));
println!("Location: ({}, {})", point.x, point.y);
println!("Color: {}", color);
}
Running It
Run the program using cargo:
cargo run
You should see output similar to:
Runeforge Hello World!
----------------------
Random d6 roll: 4
Location: (10, 20)
Color: #FF0000
Architecture
Runeforge is designed as a modular monorepo inspired by bracket-lib. This allows developers to pick and choose exactly which components they need, keeping binary sizes small and compile times fast.
Workspace Structure
The project is organized into several crates within the crates/ directory:
runeforge-rl/
โโโ Cargo.toml # Workspace configuration
โโโ crates/
โ โโโ runeforge-algorithms/ # General roguelike algorithms (drawing, flood fill)
โ โโโ runeforge-color/ # RGB/HSV color manipulation
โ โโโ runeforge-direction/ # Grid direction handling
โ โโโ runeforge-fov/ # Field-of-view algorithms
โ โโโ runeforge-geometry/ # 2D geometric primitives
โ โโโ runeforge-input/ # Input handling
โ โโโ runeforge-noise/ # Noise generation
โ โโโ runeforge-pathfinding/# Pathfinding algorithms
โ โโโ runeforge-random/ # Random number generation
โ โโโ runeforge-terminal/ # Terminal/console rendering
โ โโโ runeforge-tileset/ # Tileset/font loading
โโโ src/ # Facade crate (runeforge-rl)
Crate Dependency Graph
A simplified view of how the core crates interact:
- Core Utilities:
runeforge-geometry,runeforge-color,runeforge-randomare the foundation. - Algorithms:
runeforge-fov,runeforge-pathfinding,runeforge-algorithmsdepend on the core utilities. - Rendering:
runeforge-terminalbrings everything together for display, depending onruneforge-tilesetfor fonts andruneforge-colorfor styling. - Input:
runeforge-inputhandles user interaction.
Design Decisions
1. Pure Rust
Runeforge avoids C dependencies (unlike the original libtcod bindings) to ensure easier cross-platform builds and memory safety.
2. Rendering Strategy
We support multiple backends via traits:
- GPU (wgpu): High performance, hardware acceleration.
- Software: Fallback for systems without GPU access or for simple framebuffer operations.
- Terminal: Direct ANSI output for CLI tools or SSH play.
3. Libtcod Compatibility
While idiomatic Rust is prioritized, the API structure intentionally mirrors libtcod where sensible to make migration easier for developers coming from Python or C++.
Core Modules
Runeforgeโs core functionality is split into several focused crates. These provide the fundamental types and utilities needed for almost any roguelike game.
- Color: Color management, blending, and conversion.
- Geometry: 2D primitives like points, rectangles, and circles.
- Random: Random number generation and dice rolling.
- Direction: Grid movement and direction handling.
Runeforge Color
The runeforge-color crate provides tools for color manipulation.
Features
- RGB & HSV: Support for both Red-Green-Blue and Hue-Saturation-Value color models.
- Blending: Utilities to blend colors (lerp, multiply, add).
- Constants: Predefined named colors (e.g.,
Color::RED,Color::AZURE). - Palette Integration: Optional integration with the
palettecrate for advanced color science.
Usage
#![allow(unused)]
fn main() {
use runeforge_color::Color;
let red = Color::new(255, 0, 0);
let blue = Color::BLUE;
// Linear interpolation (blend)
let purple = red.lerp(blue, 0.5);
}
Runeforge Geometry
The runeforge-geometry crate provides 2D primitives essential for grid-based games.
Key Types
IVec2
Represents a 2D coordinate on a grid (x, y).
#![allow(unused)]
fn main() {
use runeforge_geometry::IVec2;
let p1 = IVec2::new(10, 5);
let p2 = IVec2::new(12, 5);
let distance = p1.distance(p2); // Euclidean distance
}
Rect
Represents a rectangle, useful for rooms and bounds.
#![allow(unused)]
fn main() {
use runeforge_geometry::Rect;
let room = Rect::with_size(10, 10, 5, 5); // x, y, width, height
let center = room.center();
}
Circle
Represents a circle, useful for radial effects.
Iterators
Most shapes implement iterators to allow you to loop over every point contained within them.
#![allow(unused)]
fn main() {
for point in room.iter() {
// Do something at each point in the room
}
}
Runeforge Random
The runeforge-random crate wraps rand to provide roguelike-specific utilities.
Features
- Rng Wrapper: Easy access to a seeded random number generator.
- Dice Rolling: Support for parsing and rolling standard RPG dice notation (e.g., โ3d6+2โ).
- Weighted Selection: Randomly choose items from a list with associated weights.
Usage
#![allow(unused)]
fn main() {
use runeforge_random::Rng;
let mut rng = Rng::new(); // Random seed
// let mut rng = Rng::seeded(12345); // Fixed seed
// Basic random
let val: f32 = rng.random();
// Dice rolling
let damage = rng.roll_dice(3, 6); // 3d6
// let damage = rng.roll_str("3d6+2").unwrap();
}
Runeforge Direction
The runeforge-direction crate helps manage movement on a grid.
Features
- Enumerations:
Directionenum covering Cardinal (N, S, E, W) and Ordinal (NE, NW, SE, SW) directions. - Conversion: Convert between vectors and direction enums.
- Iterators: Iterate over adjacent neighbors.
Usage
#![allow(unused)]
fn main() {
use runeforge_direction::Direction;
let dir = Direction::North;
let delta = dir.as_vec(); // Returns IVec2(0, -1) typically (depending on coordinate system)
}
Algorithms
Runeforge provides several common algorithms used in roguelike development.
- Field of View (FOV): Calculate which tiles are visible to the player.
- Pathfinding: Find the shortest path between two points (A*, Dijkstra).
- Map Generation: Algorithms for procedural dungeon generation.
- Noise: Procedural noise generation (Perlin, etc.).
Field of View (FOV)
The runeforge-fov crate provides algorithms to calculate visible areas on a grid.
Algorithms
- Recursive Shadowcasting: Efficient and visually pleasing.
- Symmetric Shadowcasting: Ensures symmetry (if A sees B, B sees A).
Usage
You must implement the FovMap trait (or similar interface) to provide transparency information about your map to the algorithm.
#![allow(unused)]
fn main() {
use runeforge_fov::{fov_shadowcast, FovMap};
// Implement the trait for your map struct
impl FovMap for MyMap {
fn is_transparent(&self, x: i32, y: i32) -> bool {
// Return true if light passes through this tile
self.tiles[x][y].transparent
}
}
// ... later ...
let mut visible_tiles = HashSet::new();
fov_shadowcast(&map, player_x, player_y, radius, &mut |x, y| {
visible_tiles.insert((x, y));
});
}
Pathfinding
The runeforge-pathfinding crate helps entities navigate your map.
Algorithms
- A* (A-Star): Finds the shortest path to a single destination.
- Dijkstra Map: Calculates distance from one or more starting points to the entire map. Useful for fleeing, chasing multiple targets, or heatmaps.
Usage (A*)
#![allow(unused)]
fn main() {
use runeforge_pathfinding::astar;
let start = IVec2::new(0, 0);
let end = IVec2::new(10, 10);
let path = astar(
&start,
|p| map.get_neighbors(p), // Successors function
|p| p.distance(&end) // Heuristic function
|p| p == end // Success function
);
}
General Algorithms
The runeforge-algorithms crate contains various utilities that donโt fit into other specific categories, particularly for map generation.
Features
- BSP (Binary Space Partitioning): For generating room-based dungeons.
- Cellular Automata: For generating organic-looking caves.
- Drunkardโs Walk: For generating chaotic tunnels or caves.
- Drawing Tools: Bresenham line drawing, circle drawing, etc.
Noise
The runeforge-noise crate wraps noise generation libraries to provide procedural content generation tools.
Features
- Perlin Noise: Smooth, continuous noise useful for terrain heightmaps.
- Simplex Noise: Improved version of Perlin noise.
- Fractal Noise: Combining multiple layers (octaves) of noise for detail.
Usage
#![allow(unused)]
fn main() {
use runeforge_noise::{Perlin, NoiseFn};
let perlin = Perlin::new();
let val = perlin.get([x as f64 * 0.1, y as f64 * 0.1]);
}
System & IO
These crates handle the low-level interaction with the operating system and the user.
- Terminal: Displaying the game grid to the screen.
- Input: Handling keyboard and mouse events.
- Tileset: Loading fonts and graphical tilesets.
Terminal
The runeforge-terminal crate is the primary rendering interface. It provides a virtual console abstraction.
The Console
The Console struct represents a grid of cells. Each cell has:
- A character glyph
- A foreground color
- A background color
Backends
Runeforge supports multiple backends:
- WGPU: Hardware accelerated (default).
- Software: CPU-based rendering.
- Terminal: Direct output to standard output (ANSI).
Usage
#![allow(unused)]
fn main() {
let mut console = Console::new(80, 50);
console.print(5, 5, "Hello World", Color::WHITE, Color::BLACK);
console.set(10, 10, '@', Color::YELLOW, Color::BLACK);
}
Input
The runeforge-input crate standardizes input handling.
Features
- Keyboard: Check key states (pressed, released).
- Mouse: Track mouse position and button clicks.
- Actions: Map raw inputs to game actions (e.g., โWโ, โUp Arrowโ, and โKโ can all map to
MoveNorth).
Tileset
The runeforge-tileset crate handles loading and managing graphical assets for the terminal.
Supported Formats
- Bitmap Fonts: Standard grid-based sprite sheets.
- TrueType/OpenType: Vector fonts rendered to bitmaps.
Configuration
Tilesets are typically configured to map specific indices or characters to regions on a texture.
Tutorials
Learn by doing! These tutorials will guide you through building complete applications with Runeforge.
- Roguelike Demo: A breakdown of the complete roguelike example included in the project.
Roguelike Demo
This tutorial walks through the roguelike_demo example found in examples/roguelike_demo.rs.
Running the Demo
cargo run --example roguelike_demo
Code Breakdown
Coming soon: A step-by-step explanation of the code.
For now, please examine the source code in examples/roguelike_demo.rs.
Contributing
We welcome contributions to Runeforge!
How to Contribute
- Fork the repository.
- Create a feature branch.
- Commit your changes.
- Push to the branch.
- Open a Pull Request.
Guidelines
- Follow the existing code style.
- Run
cargo fmtbefore committing. - Ensure all tests pass with
cargo test. - Add tests for new features.