Skip to content
firegiant9000Public

About

Local-first Windows desktop app for building and playing fifth-edition characters and homebrew, offline, with a source-aware rules engine. .NET 10 (WPF + WebView2), React/TypeScript, SQLite.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

TomeStack

Every number explains itself. A local-first Windows character sheet for 5E-compatible play and homebrew: tap any value to see the rule, the source page and the choice behind it. It works offline, with no account.

Status: v0.8.1, an unsigned installer on the Releases page (Windows asks you to confirm the first run). What each release added is in the CHANGELOG.

The Strength score expanded on a character sheet: a table traces the value from the chosen base score of 15, plus 2 from the Soldier background's ability score choice, to 17, citing System Reference Document 5.2.1, page 83

Every calculated value on the sheet expands into its trace: each step, the amount it adds, and the source page it comes from. Values can be overridden with a reason, and the calculated value stays visible next to the override.

  • Classes you can build: All twelve SRD classes, levels 1 to 20, in both rules families, each with its SRD subclass. A few features stay by hand; the sheet lists them.
  • Species and backgrounds: SRD 5.1 has all nine SRD races (with their subraces) and the Acolyte; SRD 5.2.1 has all 9 species, 4 backgrounds and 17 feats it prints. Anything else you add in the homebrew studio.
  • Works today: build under SRD 5.1 (2014) or SRD 5.2.1 (2024) rules as a cancelable draft (classes, level-ups, multiclassing, spells, every choice), and see every calculated field with a source-aware trace. Play: hit points, resources, spell slots, conditions, equipment, rolls, short and long rests, death saves. Author homebrew subclasses and features, review updates, attach your own PDFs to open cited pages, keep campaign profiles, and print a sheet. Back up and restore your whole library, PDFs included, or export one character to back it up or share it.
  • Experimental: reading a PDF's text and proposing candidates (M4). Nothing becomes a rule until you review and publish it, and it has not yet been proven on a real third-party book.
  • Evidence: checks are either fixture-verified (automated tests), Windows-install verified (the CI desktop smoke, or an owner check on an installed build), or accepted in real play. Nothing is accepted in real play yet (that is the M3 gate). See features/m2-acceptance.md.

The bundled content is a small, attributed slice of both SRDs (CC-BY-4.0; see ATTRIBUTION.md). You can also build from source (below). Milestone evidence is in ROADMAP and docs/features/*-acceptance.md.

The character builder's choices step for a Dwarf Soldier Barbarian under SRD 5.2.1: the Soldier's ability score increase is chosen, one of two Barbarian skills is still to pick, and the status line says the draft can be saved now with the open choice listed on the sheet

Characters are built as a cancelable draft. Every option cites its source, and open choices are flagged rather than blocking the save.

Screenshots are from the browser development host (src/DevHost) running the same UI and application service as the desktop shell, with a throwaway data folder.

Specs live in docs/. SPEC is the behavioral source of truth. MVP sets the release boundary, ROADMAP the milestones, and LIVING_SPECS covers the change process and open decisions. Decisions are in docs/decisions/.

Layout

src/RulesCore/      Pure rules: rules-family policies, content/character/provenance types, calculator + trace
src/AppService/     Application service: SQLite store, package export/import, CommandDispatcher (JSON protocol)
src/ImportWorker/   Import contracts; candidates can only become inactive drafts
src/DesktopShell/   WPF + WebView2 shell (TomeStack.exe); in-process service over the message bridge
src/DevHost/        Development-only loopback host for running the UI in a browser; also the restore-drill counter (--drill-report)
src/Ui/             React + TypeScript (Vite)
tests/RulesFixtures/  Original fixture content and characters for both rules families
tests/*.Tests/      xUnit tests
benchmarks/         BenchmarkDotNet measurements, run by hand (docs/performance.md)
docs/               Specs, ADRs, feature docs, changelog, diagram

Dependencies point inward: DesktopShell/DevHost → AppService → RulesCore. RulesCore has no persistence, UI or Windows references.

Prerequisites (Windows 10/11)

  • .NET SDK 10.0.1xx or later (global.json rolls forward)
  • Node.js 22 with npm
  • Microsoft Edge WebView2 Runtime (preinstalled on Windows 11)

Build and test

Run from the repository root (PowerShell or Git Bash). The UI bundle must be built before the desktop shell, which copies it:

npm ci --prefix src/Ui
npm run lint --prefix src/Ui
npm test --prefix src/Ui
npm run build --prefix src/Ui          # typecheck + production bundle -> src/Ui/dist
dotnet build TomeStack.slnx -c Release
dotnet test TomeStack.slnx -c Release
npm run test:e2e --prefix src/Ui       # UI flow against the real DevHost (needs the Release build above)

CI runs the same steps on windows-latest (.github/workflows/ci.yml).

Performance: the measured baseline (a level-20 multiclass sheet, a 500-revision pack import, every SRD formula, update reviews across 100 characters) and how to run the benchmarks are in docs/performance.md.

Run

Desktop app:

dotnet run --project src/DesktopShell

Data goes to %LOCALAPPDATA%\TomeStack (override with TOMESTACK_DATA_DIR or --data-dir <path>; a folder inside OneDrive or another sync root gets a warning). The app seeds the bundled SRD packs. In a Debug build, --devtools enables WebView2 DevTools and TOMESTACK_DEV_FIXTURES=1 also seeds the original test fixtures (DevHost always does); a Release build ignores both (LIVING_SPECS D11).

Self-test. This launches the shell, loads the UI, round-trips commands over the bridge, creates a fixture character, exports it and previews the package. It then exits 0/2 and writes a JSON report:

src/DesktopShell/bin/Release/net10.0-windows/TomeStack.exe --smoke --smoke-report smoke.json
scripts/smoke.ps1 -Exe src/DesktopShell/bin/Release/net10.0-windows/TomeStack.exe       # same run, with the report checked
scripts/single-instance-check.ps1 -Exe src/DesktopShell/bin/Release/net10.0-windows/TomeStack.exe   # two processes on one data folder
scripts/offline-check.ps1 -Mode MissingRuntime     # simulated missing WebView2 runtime (smoke-only flag)
scripts/offline-check.ps1 -Mode AssumeOffline      # turn on airplane mode first

Every script in scripts/ runs under both Windows PowerShell 5.1 and pwsh 7 (checked 2026-09-26: smoke, offline-check in all modes, installer-smoke with both adapters, and pack-installer).

UI with hot reload in a browser (two terminals):

dotnet run --project src/DevHost        # 127.0.0.1:5178, data in %LOCALAPPDATA%\TomeStack-dev
npm run dev --prefix src/Ui             # http://127.0.0.1:5173

The dev host writes a fresh token to <data dir>/devhost.token at each launch, and the Vite proxy attaches it. If you set TOMESTACK_DATA_DIR, set it the same way for both processes.

Self-contained publish:

dotnet publish src/DesktopShell -c Release -r win-x64 --self-contained true -o artifacts/publish

Installer (Velopack, per-user, self-contained, unsigned; ADR-008). Build the UI first. vpk is a repo-local tool, so run dotnet tool restore once:

dotnet tool restore
scripts/pack-installer.ps1        # -> artifacts/installer/<version>/TomeStack.App-win-Setup.exe
scripts/installer-smoke.ps1 -Adapter Velopack -OldBuild artifacts/installer/<old> -NewBuild artifacts/installer/<new>

It installs to %LOCALAPPDATA%\TomeStack.App. Uninstalling removes only that folder, never the data folder. The version comes from Directory.Build.props and must go up with every build you hand out.

Verify a release. A release that lists a SHA256SUMS file also has a build attestation from the Release workflow for each file in it (earlier releases have neither). With the download and SHA256SUMS in one folder, the first command prints True when the hash matches, and the second (needs a recent GitHub CLI) checks that this repository's release.yml built it. Details, and what a release is and isn't, are in SECURITY.md.

(Get-FileHash .\TomeStack.App-win-Setup.exe -Algorithm SHA256).Hash -eq ((Select-String -Path .\SHA256SUMS -Pattern 'TomeStack.App-win-Setup.exe' -SimpleMatch).Line -split '\s+')[0]
gh attestation verify .\TomeStack.App-win-Setup.exe --repo firegiant9000/TomeStack --signer-workflow firegiant9000/TomeStack/.github/workflows/release.yml

Safety defaults

  • Offline: the shell refuses any network request outside the app's virtual host, and the production bundle has a strict CSP.
  • Only published content revisions affect calculations. Imported candidates become drafts, and imported effects are reference-only until reviewed.
  • Package import is preview-then-apply, with size limits, a fixed path layout and SHA-256 verification. Character packages never include PDFs. Only a full library backup contains your managed PDF copies, and it is personal: do not share it.
  • One TomeStack per data folder: a second launch brings the open window forward.
  • Upgrading keeps your library in place, and a full backup moves it to a new PC; see Moving your library to a new version or a new PC. A file for someone on an older version can be saved for that version; the preview lists what the copy leaves out, and your library is unchanged.
  • 2014 and 2024 rules are separate rules-family IDs, and their differences are explicit policy fields.

Code signing policy

Releases up to 0.8.x are unsigned. The project applied to SignPath Foundation for free code signing for open source projects on 2026-11-12 and is waiting for their answer. The first signed release is targeted for 0.9.0 if the application is accepted. The plan and the alternatives are in ADR-024. If the application is declined, releases stay unsigned.

Once accepted, signed releases carry this line:

Free code signing provided by SignPath.io, certificate by SignPath Foundation

  • Team roles: committers and reviewers, and approvers, are the repository owner (firegiant9000). Outside contributions are reviewed by the owner before they are merged.
  • Builds: released files are built from the source in this repository by the GitHub Actions workflow release.yml, which also publishes a build attestation (see "Verify a release" above).
  • Approval: every release will need a manual approval before it is signed. The installer and the app files in it are signed in two separate requests.
  • Accounts: multi-factor authentication is required for every team member with signing or repository access.
  • Privacy: this program will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it. There is no update check and no telemetry. Crash details are saved to a log file in your data folder and are never sent.

License

TomeStack's code is licensed under the Apache License 2.0; see also NOTICE (LIVING_SPECS D07). Fixture content is original to this project. Third-party components are listed in ATTRIBUTION.md, and export and license policy is in ADR-007. TomeStack is not affiliated with or endorsed by Wizards of the Coast, Foundry Gaming LLC or Roll20. Export formats name other software only to say which file they write (for example "Foundry VTT (dnd5e system)", export-adapters.md).

About

Local-first Windows desktop app for building and playing fifth-edition characters and homebrew, offline, with a source-aware rules engine. .NET 10 (WPF + WebView2), React/TypeScript, SQLite.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages