{"id":48880955,"url":"https://github.com/jurnalis-project/engine","last_synced_at":"2026-04-21T08:09:20.744Z","repository":{"id":351523470,"uuid":"1211313792","full_name":"jurnalis-project/engine","owner":"jurnalis-project","description":"Stateless, deterministic SRD 5.1 d20 CRPG engine in Rust","archived":false,"fork":false,"pushed_at":"2026-04-15T10:38:16.000Z","size":31796,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-15T12:14:29.390Z","etag":null,"topics":["crpg","d20","game-engine","rpg","rust","srd","tabletop-rpg","text-based-game"],"latest_commit_sha":null,"homepage":"https://github.com/jurnalis-project","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jurnalis-project.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-15T09:12:28.000Z","updated_at":"2026-04-15T10:38:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jurnalis-project/engine","commit_stats":null,"previous_names":["jurnalis-project/engine"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/jurnalis-project/engine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jurnalis-project%2Fengine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jurnalis-project%2Fengine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jurnalis-project%2Fengine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jurnalis-project%2Fengine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jurnalis-project","download_url":"https://codeload.github.com/jurnalis-project/engine/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jurnalis-project%2Fengine/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31869050,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-15T15:24:51.572Z","status":"online","status_checked_at":"2026-04-16T02:00:06.042Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crpg","d20","game-engine","rpg","rust","srd","tabletop-rpg","text-based-game"],"created_at":"2026-04-16T03:00:15.404Z","updated_at":"2026-04-16T03:00:28.116Z","avatar_url":"https://github.com/jurnalis-project.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"assets/wordmark.png\" alt=\"jurnalis-engine\" width=\"444\" /\u003e\n\n  [![Crates.io](https://img.shields.io/crates/v/jurnalis-engine.svg)](https://crates.io/crates/jurnalis-engine)\n  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n\u003c/div\u003e\n\nA stateless, deterministic text-based CRPG engine implementing SRD 5.1 (d20) mechanics. The engine is a standalone Rust library crate — it carries no server, no persistent state, and no runtime dependencies beyond `serde` and `rand`. Embed it in any application or run it directly via the included `jurnalis-cli` binary.\n\nAll game state is serialized to JSON and owned by the caller. On every call the caller passes the current state in; the engine returns the updated state alongside text output. This makes the engine trivially embeddable in web backends, desktop apps, and test harnesses alike.\n\n---\n\n## Features\n\n- **Full SRD 5.1 mechanics** — d20 ability checks, saving throws, skill checks, initiative, combat turns with attack rolls and damage, spell slots, short and long rests, conditions, and AC calculations.\n- **12 character classes** — Barbarian, Bard, Cleric, Druid, Fighter, Monk, Paladin, Ranger, Rogue, Sorcerer, Warlock, Wizard.\n- **3 playable races** — Human, Elf, Dwarf, each with accurate racial trait bonuses.\n- **Stateless design** — the engine holds zero mutable state. State is serialized to JSON after every call and passed back in on the next. Safe to use across threads, processes, or network boundaries.\n- **Deterministic RNG** — seeded from a `u64`. Replay any session exactly by replaying the seed and input sequence.\n- **Ironman mode** — optional flag that gates save/load semantics at the application layer.\n- **Procedural world generation** — location graphs, NPC placement, item tables, and event triggers generated from the seed at game start.\n- **`jurnalis-cli` binary** — a REPL that runs a full game session in a terminal, with built-in `save`/`load` persistence.\n\n---\n\n## Getting Started\n\n### As a library\n\nAdd the crate to your `Cargo.toml`:\n\n```toml\n[dependencies]\njurnalis-engine = \"0.19\"\n```\n\n### Running the CLI\n\nBuild and run the `jurnalis-cli` binary directly from source:\n\n```bash\ngit clone https://github.com/jurnalis-project/engine.git\ncd engine\ncargo run --bin jurnalis-cli\n```\n\nOr install it globally:\n\n```bash\ncargo install jurnalis-engine --bin jurnalis-cli\n```\n\n---\n\n## Public API\n\nThe engine exposes two functions.\n\n### `new_game`\n\n```rust\npub fn new_game(seed: u64, ironman_mode: bool) -\u003e GameOutput\n```\n\nInitializes a new game session and begins the character creation flow. The `seed` value controls all procedural generation for the session. Pass `ironman_mode: true` to signal to your application layer that save/load should be restricted.\n\n### `process_input`\n\n```rust\npub fn process_input(state_json: \u0026str, input: \u0026str) -\u003e GameOutput\n```\n\nAccepts the current serialized game state and a raw text command from the player. Returns the updated state and any text to display. The input string is free-form — the engine's parser handles verb resolution, fuzzy target matching, and dispatch to the appropriate subsystem.\n\n### `GameOutput`\n\n```rust\npub struct GameOutput {\n    pub text: Vec\u003cString\u003e,      // Lines of text to display to the player\n    pub state_json: String,     // Updated game state, serialized as JSON\n    pub state_changed: bool,    // Whether state was mutated by this call\n}\n```\n\n---\n\n## Usage Example\n\n```rust\nuse jurnalis_engine::{new_game, process_input};\n\nfn main() {\n    // Start a new game with a fixed seed (deterministic)\n    let output = new_game(42, false);\n    for line in \u0026output.text {\n        println!(\"{}\", line);\n    }\n\n    // The caller owns the state — pass it back on every call\n    let mut state_json = output.state_json;\n\n    // Drive the game loop\n    let commands = [\"1\", \"3\", \"2\", \"15 14 13 12 10 8\", \"1 2\", \"Aria\", \"look\", \"north\"];\n    for cmd in \u0026commands {\n        let output = process_input(\u0026state_json, cmd);\n        for line in \u0026output.text {\n            println!(\"{}\", line);\n        }\n        state_json = output.state_json;\n    }\n}\n```\n\nThe caller is responsible for storing `state_json` between calls. There is no hidden global state.\n\n---\n\n## Architecture\n\nThe crate is organized into feature modules. Each module owns its domain logic and exposes a public API; modules do not import from each other directly. `lib.rs` is the sole orchestrator — it calls into modules, routes commands, and threads state through the pipeline.\n\n```\nsrc/\n  lib.rs          # Orchestrator: new_game(), process_input()\n  types.rs        # Shared enums and structs (Ability, Skill, Direction, …)\n  state/          # GameState, WorldState, serialization, save/load validation\n  parser/         # Command parsing, verb dispatch, fuzzy target resolution\n  character/      # Character creation, ability scores, races, classes, backgrounds\n  combat/         # Initiative, attack rolls, damage, turn order\n  conditions/     # Status conditions (Blinded, Poisoned, Restrained, …)\n  equipment/      # SRD item tables, AC calculation, equip/unequip\n  leveling/       # XP tracking, level-up, proficiency bonus progression\n  rest/           # Short rest (hit dice recovery) and long rest (full recovery)\n  rules/          # Dice rolling (seeded RNG), skill checks, saving throws\n  spells/         # Spell slot management, spell casting, known/prepared spells\n  world/          # Procedural location graph, NPC generation, item placement, triggers\n  narration/      # Template-based narrator, event-to-text rendering\n  output/         # GameOutput struct\n```\n\nShared data structures (`GameState`, `Ability`, `Skill`, `ItemType`, etc.) live in `state/` and `types.rs` so every module can depend on them without creating cross-module coupling.\n\n---\n\n## Contributing\n\nContributions are welcome. Please open an issue to discuss significant changes before sending a pull request.\n\n1. Fork the repository and create a branch off `main`.\n2. Make your changes. Run the test suite before pushing:\n   ```bash\n   cargo test\n   ```\n3. Ensure no new warnings are introduced:\n   ```bash\n   cargo clippy -- -D warnings\n   ```\n4. Open a pull request against `main` with a clear description of what changed and why.\n\nThere is no minimum issue size — bug reports, documentation fixes, and new mechanics are all appreciated.\n\n---\n\n## License\n\nThis project does not yet have a license file committed to the repository. Until one is added, all rights are reserved. If you want to use this crate in your project, please open an issue to request a license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjurnalis-project%2Fengine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjurnalis-project%2Fengine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjurnalis-project%2Fengine/lists"}