Keyboard shortcuts

Press โ† or โ†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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:

CrateDescriptionStatus
runeforge-algorithmsProcedural map generation (BSP, Caves, etc.)โœ… Complete
runeforge-colorRGB/HSV color manipulationโœ… Complete
runeforge-directionGrid-based direction handlingโœ… Complete
runeforge-fovField-of-view algorithmsโœ… Complete
runeforge-geometry2D primitives (IVec2, Rect)โœ… Complete
runeforge-inputKeyboard and mouse inputโœ… Complete
runeforge-noiseProcedural noise generationโœ… Complete
runeforge-pathfindingA* and Dijkstra pathfindingโœ… Complete
runeforge-randomRNG with dice notationโœ… Complete
runeforge-terminalConsole rendering (CPU/GPU/ANSI)โœ… Complete
runeforge-tilesetFont 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 pathfinding crate
  • โœ… Procedural Generation: BSP dungeons, Cellular Automata caves, and Drunkardโ€™s Walk tunnels
  • โœ… Noise Generation: 2D Perlin noise maps
  • โœ… Rendering:
    • Abstract Console trait for backend-agnostic code
    • Software backend (CPU buffer, PNG export)
    • Terminal backend (ANSI escape codes)
  • โœ… 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.

Next Steps

  1. Installation: Add Runeforge to your project.
  2. 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-random are the foundation.
  • Algorithms: runeforge-fov, runeforge-pathfinding, runeforge-algorithms depend on the core utilities.
  • Rendering: runeforge-terminal brings everything together for display, depending on runeforge-tileset for fonts and runeforge-color for styling.
  • Input: runeforge-input handles 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 palette crate 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: Direction enum 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

  1. Fork the repository.
  2. Create a feature branch.
  3. Commit your changes.
  4. Push to the branch.
  5. Open a Pull Request.

Guidelines

  • Follow the existing code style.
  • Run cargo fmt before committing.
  • Ensure all tests pass with cargo test.
  • Add tests for new features.