Documentation
Build with SimTerm
An open-source Rust framework for building immersive terminal-based games and experiences.
The runtime handles campaign loading, state, logs, terminal UI integration, virtual filesystems, objectives, choices, and reusable mechanics. Campaign data defines the experience.
Quickstart
Install Rust, clone the repository, and run the bundled sample campaign. The sample demonstrates the current terminal-hacking loop, but the framework positioning is broader.
cargo run -p simterm
cargo run -p simterm -- --check --campaign ./examples/sample_campaign
cargo run -p simterm -- --campaign ./examples/sample_campaign
cargo run -p simterm -- --campaign ./examples/sample_campaign --autoplay
cargo run -p simterm -- --campaign ./examples/sample_campaign --autoplay-deterministic
--check loads the campaign and validates basic
invariants without opening the terminal UI.
--autoplay opens the normal TUI and runs a visible
command-by-command playthrough. --autoplay-deterministic
avoids Unstable exploits and probabilistic privilege
escalation, stopping with a log message if no deterministic route
exists. Use --autoplay-delay <ms> to change the
cadence.
Mental model
Framework runtime
simterm-engine owns generic mechanics: data
loading, mutable game state, command effects, campaign
progression, outcomes, and validation helpers.
Terminal frontend
simterm owns CLI parsing, terminal setup,
rendering, input, command dispatch, logs, status views, and
presentation details.
Campaign data
campaign.ron owns content: campaign name, intro,
missions, targets, files, objectives, endings, achievements,
UI theme, and flavor text.
Campaign anatomy
A campaign is either a directory containing
campaign.ron or a direct path to a
.ron file. The root object is Campaign.
Campaign(
name: "My Experience",
intro: ["Opening line"],
missions: [
Mission(
id: "op1",
name: "FIRST CONTACT",
briefing: ["Read the situation."],
objective: Some("/root/flag.txt"),
entry: Active,
target: ( ... ),
),
],
theme: (app_title: "SIMTERM"),
achievements: [
(
id: "read-flag",
title: "First flag",
description: "Read the objective file.",
trigger: ReadFile("/root/flag.txt"),
),
],
)
Most fields have defaults. Start with the sample campaign, change
one thing at a time, then run --check.
Current sample loop
The current public sample models a simulated technical operation. It gives creators a concrete pattern to study while the framework remains capable of supporting other terminal-native experiences.
- Discover: reveal what the player can interact with.
- Analyze: produce clues, findings, or uncertainty.
- Act: commit to a command that changes state.
- Explore: use the virtual filesystem and logs.
- Resolve: complete an objective or choose an ending.
Extensibility
Extend SimTerm by choosing the lowest layer that fits the change. Content changes should stay in RON. New reusable behavior belongs in the runtime. New presentation belongs in the frontend.
Data-only extension
Add missions, text, themes, virtual files, objectives, endings, easter eggs, and sample content without recompiling.
Runtime mechanic
Add shared rules in crates/engine/src/runtime and
expose configuration through model fields in
crates/engine/src/model.
Frontend feature
Add command parsing, rendering, completion, or UI behavior in
crates/simterm/src when the player needs a new
interface.
Design rule
If a change is specific to one story, keep it as campaign data. If multiple campaigns would reuse it, consider making it a framework mechanic with neutral defaults.
Publishing campaigns
Distribute a campaign as a folder containing
campaign.ron and any campaign-adjacent assets you
support. Players can run it with:
simterm --campaign ./your_campaign
The SimTerm framework is MIT licensed. Separately distributed campaigns may use their own licenses.