Tech stack
The game
Section titled “The game”| Layer | Tech | Why |
|---|---|---|
| App | Flutter (Dart) | Cross-platform, mature, 60fps custom rendering. |
| Game loop | Flame | Audio + input on the play surface. |
| Cards | Flutter CustomPainter | Every pip, every face, every shuffle animation. No third-party card lib. Cards are the soul of the visual identity; we build it. |
| Sim | Pure Dart | lib/sim/ has no Flutter imports. Engine, cascade, arcana behavior. |
| Persistence | SharedPreferences (JSON) | Local-first. The web build uses IndexedDB under the hood; same API. |
| Tests | flutter_test + golden_toolkit | 1869 unit + golden + integration tests. |
| Determinism | Custom Rng(seed) | Bit-exact replay from share codes. |
Why no card library
Section titled “Why no card library”Per CLAUDE.md:
Don’t import a card-rendering library. Cards are the soul of the visual identity; build a custom CustomPainter and own it.
The same rule shipped ThePit’s chart from scratch and produced a
visual identity nobody else has. Pale Jack’s cards live in
lib/ui/cards/card_painter.dart (~2000 lines).
Why offline-first
Section titled “Why offline-first”Per CLAUDE.md:
Don’t require connectivity. Offline-first, no service. Pale Jack is a downloadable game that must work end-to-end on an airplane, in a basement, with the wifi off. No runtime LLM, no live leaderboards, no cloud saves, no online auth, no telemetry that blocks gameplay.
The web build at palejack.com is a static PWA that caches everything on first load and runs offline thereafter.
Build flags
Section titled “Build flags”const bool kCampaignMode = bool.fromEnvironment( 'CAMPAIGN', defaultValue: !kIsWeb,);| Build | Value | Behavior |
|---|---|---|
| Web | false | Single-night demo. |
| Native (default) | true | Full 7-night campaign. |
| Override | --dart-define=CAMPAIGN=true/false | Either path. |
Deploy
Section titled “Deploy”| Surface | Pipeline | Trigger |
|---|---|---|
| palejack.com (game) | .github/workflows/deploy.yml → Cloudflare Pages | every push to main |
| wiki.palejack.com (this site) | .github/workflows/wiki-deploy.yml → Cloudflare Pages | every push to main |
Both workflows have cancel-in-progress set so rapid pushes
cleanly supersede.
The wiki itself
Section titled “The wiki itself”This wiki is built with Astro Starlight.
Source lives in wiki/. Content is plain Markdown in
wiki/src/content/docs/*.md. Edit any page via the Edit this page
link in the footer.
Cross-project
Section titled “Cross-project”../ThePit/ is the sibling project. It pioneered:
- The Flutter + Flame + CustomPainter pipeline.
- The deterministic seeded RNG (
lib/sim/rng.dart). - The
ShareCodePIT-/PJK- prefix codec. - The
RunPersistenceControllerFTL no-save-scum pattern. - The
golden_toolkitgolden-test harness.
Pale Jack lifts those patterns wholesale; the simulation domain is fresh.
Where to read the code
Section titled “Where to read the code”| Want | Read |
|---|---|
| Cascade math | lib/sim/cascade_resolver.dart |
| Engine | lib/sim/engine.dart |
| Night flow | lib/sim/night.dart |
| Arcana catalog | lib/sim/arcana/arcana.dart |
| Dealer voice | lib/sim/dealer_voice.dart |
| Campaign state | lib/data/campaign_state.dart |
| Book of Hours | lib/data/book_of_hours.dart |
| Top-level UI | lib/main.dart, lib/ui/table_screen.dart |
| Tests | test/sim/, test/data/, test/ui/, test/integration/, test/golden/ |