A comprehensive character creation and management system for Savage Worlds Adventure Edition (SWADE), built with Rust.
This application enables players and game masters to create, manage, and advance SWADE characters with full support for:
- Character Creation Wizard - UI-agnostic character creation system
- Character Management - Save, load, and organize multiple characters
- Character Advancement - Track experience and apply advances
- Rules Validation - Automatic enforcement of SWADE game rules
- Game Data Queries - Comprehensive CLI for viewing all SWADE rules data
The system supports both Wild Cards (player characters and major NPCs) and Extras (minor NPCs), with complete tracking of attributes, skills, edges, hindrances, powers, and arcane backgrounds.
- Rust 1.85+ - Install via rustup
- Node.js 18+ - Install from nodejs.org or via a version manager
- Tauri system dependencies - Platform-specific requirements:
- macOS: Xcode Command Line Tools (
xcode-select --install) - Linux: See Tauri Linux prerequisites
- Windows: See Tauri Windows prerequisites
- macOS: Xcode Command Line Tools (
# Install frontend dependencies
cd swade-gui
npm install
# Run the desktop application (development mode with hot reload)
npm run tauri dev
# Build for production
npm run tauri buildThe database is embedded in the application binary - no additional setup required.
- Rust 1.85+ - Core application logic and business rules (uses Rust 2024 edition)
- rusqlite - Embedded SQLite database with bundled library
- serde - JSON serialization and deserialization
- thiserror - Comprehensive error handling
- specta - TypeScript type generation from Rust types
- Tauri 2 - Native desktop application framework
- Svelte 5 - Reactive frontend framework
- TailwindCSS 4 - Utility-first CSS framework
- TypeScript - Type-safe frontend development
- tauri-specta - Automatic TypeScript bindings generation
- SQLite - Embedded database with all SWADE game rules data
- Embedded Distribution - Database compiled into binary, extracted to user data directory
- Version Tracking - Automatic updates when rules data changes
The project uses a layered architecture with clear separation of concerns:
┌─────────────────────────────────────────────────────────────┐
│ Presentation Layer │
│ (CLI / Desktop GUI) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Service Layer │
│ (Data Loading & Query Orchestration) │
│ CharacterService, EdgeService, SkillService, etc. │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ View Models │
│ (Rich Domain Objects with Business Logic) │
│ CharacterView, EdgeView, SkillValue, RequirementTree, etc. │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Base Models │
│ (Pure Data Structures) │
│ Character, Edge, Skill, Modifier, Requirement, etc. │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Repository Layer │
│ (Database Access - CRUD Only) │
│ 42 Repositories for all database tables │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Database Layer │
│ (SQLite with Embedded Rules Data) │
│ Connection Management, Embedded Database, Versioning │
└─────────────────────────────────────────────────────────────┘
- Layered Architecture - Strict separation between presentation, data loading, domain logic, and storage
- Repository Pattern - All database access through type-safe repository objects
- Dual Model System - Base models (pure data) separate from view models (data + domain logic)
- Rich Domain Models - Business rules (SWADE mechanics, requirement evaluation, cost calculation) live in view models, not services
- Service Layer - Thin orchestration layer for loading data and assembling view models; no business logic
- Embedded Database - SQLite database compiled into binary with automatic updates
- Type-Safe Domain Modeling - Rust's type system enforces SWADE rules at compile time
- Automatic Type Generation - View models are automatically exported to TypeScript for the frontend
The project uses tauri-specta to automatically generate TypeScript types from Rust view models:
Rust View Models (swade-core) TypeScript Types (swade-gui)
───────────────────────────── ────────────────────────────
CharacterView ───────► CharacterView
EdgeView ───────► EdgeView
Die, Rank, Modifier ───────► Die, Rank, Modifier
... (50+ types total) ... (auto-generated)
How it works:
- View models in
swade-corederivespecta::TypealongsideSerialize/Deserialize - Tauri commands in
swade-guiare annotated with#[specta::specta] - On dev build, TypeScript bindings are auto-generated to
swade-gui/src/lib/bindings.ts - Frontend imports typed
commandsobject instead of using rawinvoke()
Benefits:
- Type changes in Rust immediately surface as TypeScript compiler errors
- No manual type synchronization between frontend and backend
- Generated command wrappers provide full autocomplete and type checking
- Result types properly model success/error states
The database schema is designed to be:
- Programmatic - Integer die sizes (4, 6, 8, 10, 12) for easy calculations
- Flexible - String-based targeting allows for derived stats and future expansion
- Extensible - Source tracking supports multiple rulebooks
- Comprehensive - Handles full complexity of SWADE character mechanics
Game Rules Data:
attributes- The five core attributes (Agility, Smarts, Spirit, Strength, Vigor)skills- All available skills with linked attributesranks- Character progression ranks (Novice → Legendary)ancestries- Character races/species with racial abilitiesedges- Character advantages organized by categoryhindrances- Character disadvantages (minor/major variants)powers- Arcane powers with costs and effectsarcane_backgrounds- Types of magic/psionics availablegear- Equipment items with categories and statsgear_categories- Hierarchical equipment categorizationweapon_stats- Weapon-specific statistics (damage, range, etc.)armor_stats- Armor-specific statistics (protection values)shield_stats- Shield-specific statisticsammunition_stats- Ammunition-specific statistics
Flexible Systems:
modifiers- Changes to attributes, skills, and derived stats- Die increments (d6 → d8)
- Roll bonuses (+2 to rolls)
- Flat bonuses (Pace +2)
- Descriptive abilities
requirements- Prerequisites for edges, powers, etc.requirement_expressions- Tree structure for complex logical requirements (AND/OR/NOT)ancestry_choices- Choice-based bonuses (free edges, heritage traits)gear_modifiers- Modifiers granted by equipmentgear_requirements- Prerequisites for equipment use
Character Data:
characters- Main character records with point trackingcharacter_attributes- Character's attribute valuescharacter_skills- Character's skill valuescharacter_edges- Edges taken by charactercharacter_hindrances- Hindrances selectedcharacter_powers- Powers knowncharacter_arcane_backgrounds- Arcane background selectionscharacter_gear- Equipment owned by charactercharacter_advances- Character advancement historycharacter_modifiers- Custom modifiers applied to charactercharacter_notes- Character notes and backstory
- Point Tracking - Automatic tracking of attribute, skill, and hindrance points
- Requirement Validation - Expression trees support complex prerequisites
- Modifier Application - Type-safe modifier system with multiple value types
- Ancestry Choices - Flexible system for free edges, mandatory hindrances, heritage traits
- Foreign Key Constraints - Data integrity enforced at database level
- Version Tracking - SHA256 checksums enable automatic updates
For complete database documentation, see ./db/README.md.
Contributions are welcome! Please follow these guidelines:
- Follow Rust standard formatting (
cargo fmt) - Run Clippy and fix warnings (
cargo clippy) - Add documentation for public APIs
- Include examples in documentation
- NO DOCTESTS
- Tests should be within a module in the file that they're testing
- Add unit tests for new functionality
- Ensure all tests pass (
cargo test) - Test error cases, not just happy paths
- Respect layer boundaries (no cross-layer calls)
- Keep business logic in view models
- Keep data access in repositories