SimTerm docs

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.

  1. Discover: reveal what the player can interact with.
  2. Analyze: produce clues, findings, or uncertainty.
  3. Act: commit to a command that changes state.
  4. Explore: use the virtual filesystem and logs.
  5. Resolve: complete an objective or choose an ending.

Authoring workflow

Recommended loop

Copy the sample, make a small data change, validate, run, then repeat. Avoid editing Rust until a mechanic truly cannot be expressed as campaign data.

cp -r examples/sample_campaign campaigns/my_campaign
cargo run -p simterm -- --check --campaign ./campaigns/my_campaign
cargo run -p simterm -- --campaign ./campaigns/my_campaign

Useful authoring rules

  • Keep story, branding, objectives, and flavor in campaign data.
  • Give every playable mission a completable path.
  • Use VFS files for clues, rewards, and environmental storytelling.
  • Use hashes, encoded files, reversible binaries, and local enumeration vectors for offline analysis or reversing puzzles.
  • Use endings when the final outcome should branch.
  • Use campaign achievements with ReadFile, CompleteMission, ChooseEnding, and CampaignComplete triggers when you want progress badges tied to your story.
  • Keep the sample fictional and safe to publish.

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.

Reference links