A mobile-first remake of the 1992 German strategy classic PCKaiser++ (Martin Gelter & Lorenz Giefing) for Android, iOS and Linux desktop — Flutter + Flame. Rule one of 30 medieval realms: build, trade, marry, scheme, elect a Kaiser and conquer, until one dynasty rules the whole map. 1–16 human players hot-seat on one device; the AI plays the rest.
PCKaiser was built almost entirely through AI-assisted "vibe coding" — the rules engine, the Flutter client and this documentation were largely generated by an LLM agent from natural-language prompts and an interactive review loop. Expect the quirks that come with that: treat the code as a hobby project, review before relying on it, and don't assume every line was hand-audited. Contributions and bug reports are welcome.
| Path | What it is |
|---|---|
client/ |
Flutter app (UI, Flame map, save slots, online lobby) |
packages/game_core/ |
Pure Dart rules engine — all game logic, no Flutter deps |
backend/ |
V2 online server: Dart shelf REST API over game_core |
packages/game_core/tool/sim_report.dart |
Headless 200-year simulation report (dev tool) |
packages/game_core/tool/balance_sim.dart |
Runaway-leader balance probe over N seeded worlds (dev tool) |
imgs/ |
Original tile graphics (38 indices, see §24 of the spec) |
store/ |
Store-listing metadata (EN/DE) |
ORIGINAL_GAME.md |
The traced spec of the original game — source of truth for all rules |
ARCHITECTURE.md |
System architecture incl. the V2 online design |
PROJECT_REQUIREMENTS.md |
Product requirements for V1 |
CHECKLIST.md |
Phase-by-phase progress tracker |
docs/HISTORY.md |
Dated decision & fix log (lookups) |
- Flutter ≥ 3.44 (stable) — includes the Dart SDK.
Install: https://docs.flutter.dev/get-started/install, then make sure
flutter/binis on yourPATH(flutter doctorto verify). - For Android builds: Android SDK + platform tools (easiest via Android
Studio;
flutter doctorwalks you through it). - For iOS builds: a Mac with Xcode; standard Flutter iOS setup.
- For Linux desktop builds on Debian/Ubuntu:
clang,cmake,ninja-build,pkg-config,libgtk-3-devandlibstdc++-12-dev.
No other services are needed — the local game is fully offline. Online play (beta) additionally needs a running server (see below).
# 1. Fetch dependencies (game_core is wired in via a path dependency)
cd client
flutter pub get
# 2. List connected devices / emulators
flutter devices
# 3. Run (debug)
flutter run # picks the default device
flutter run -d <device-id> # or pick one explicitly
flutter run -d linux # Linux desktopUseful during development:
flutter run --profile # realistic performance (60 fps target)
dart run tool/sim_report.dart # in packages/game_core: headless 200-year sim
dart run tool/balance_sim.dart 20 mittel # concentration/catch-up metrics over 20 worldsClient build-time flags (--dart-define), all optional:
| Define | Effect |
|---|---|
PCKAISER_SERVER_URL=https://… |
Bakes in the online server URL (skips the in-app prompt). |
PCKAISER_INSTANCE=2 |
Separate online profile — run two instances on one machine for multiplayer testing. |
Run this before every push — keep it green (no CI for the app yet; Jenkins will be used for the backend later):
# Rules engine
cd packages/game_core
dart pub get
dart analyze --fatal-infos
dart test # includes the 200-year full-AI smoke test
# App
cd client
flutter pub get
flutter analyze
flutter test
# Online server
cd backend
dart pub get
dart analyze --fatal-infos
dart testcd backend
dart pub get
dart run bin/server.dartEnv: PORT (default 3000), STORE_DIR (default ./data),
FIREBASE_SERVICE_ACCOUNT (base64 service-account JSON — enables FCM
push; without it pushes are logged only).
Containerized (build from the repository root so game_core is in
context), with an Nginx example in backend/deploy/:
docker compose -f backend/deploy/docker-compose.yml up -d --build--build is required after a game_core change — without it the old
image (and old rules) keeps running. Verify the deployed build with
GET /version (no auth), which reports the server's app version:
curl https://your-server.example.com/version
# {"data":{"app_version":"0.1.1","schema_version":1},"error":null}If that version is stale, the redeploy did not pick up the new
game_core/app build (e.g. the server's checkout was not pulled before
--build). Online clients on a different app_version are told to update
before they may take their turn.
Compose env (set in the shell or in backend/deploy/.env):
PCKAISER_PORT — host port the server is published on
(default 3000, bound to localhost; point Nginx at it), plus
FIREBASE_SERVICE_ACCOUNT as above.
The store is a JSON file store under STORE_DIR (one document per match —
the same GameState JSON the client saves locally); swap in PostgreSQL
behind lib/src/store.dart for multi-node setups.
Client: bake the server address into the build —
flutter run --dart-define=PCKAISER_SERVER_URL=https://kaiser.example.com
flutter build apk --dart-define=PCKAISER_SERVER_URL=https://kaiser.example.comWith the define set, "Online spielen (Beta)" only asks for a player name; without it (dev builds) the address can be entered in the app. Create a match, share the match ID, and play your turns as they come — the server validates every action, hides foreign realms per seat and auto-resolves expired turns (configurable timer).
Testing multiplayer on one machine: two desktop instances normally share the same profile file and therefore the same player identity. Give the second instance its own identity with
flutter run -d linux --dart-define=PCKAISER_INSTANCE=2(any suffix works — it picks the profile file pckaiser_online_2.json,
so the instance registers as its own player).
Online matches notify the player when it is their turn ("Du bist am Zug !"), when a decision awaits them and when war breaks out. Push is strictly optional: without the Firebase config below the app builds and runs normally (the server just logs what it would have sent), and the client asks the player for notification permission via the system dialog the first time they use online play.
One-time Firebase setup (free Spark plan suffices — FCM costs nothing):
-
Create a project at https://console.firebase.google.com.
-
Android: add an Android app with package name
com.pckaiser.app, downloadgoogle-services.jsonand put it atclient/android/app/google-services.json. That file's presence activates the Google-services Gradle plugin; rebuild the app. -
Server: Project settings → Service accounts → Generate new private key, then pass the JSON base64-encoded to the server:
export FIREBASE_SERVICE_ACCOUNT=$(base64 -w0 service-account.json) dart run bin/server.dart # or set it in backend/deploy/.env
-
iOS (needs an Apple Developer account): add an iOS app with bundle id
com.pckaiser.app, put the downloadedGoogleService-Info.plistintoclient/ios/Runner/(add it to the Runner target in Xcode), enable the Push Notifications capability and Background Modes → Remote notifications, and upload your APNs auth key under Project settings → Cloud Messaging.
Token flow: the client uploads its FCM token on launch and after online
setup (PATCH /players/:id); the server sends via the FCM HTTP-v1 API
after each saved turn. Tapping a notification opens the match directly.
cd client
flutter build apk # output: build/app/outputs/flutter-apk/app-release.apkWithout a release keystore this falls back to debug signing — fine for sideloading on test devices, not accepted by the Play Store.
-
Create a keystore once (keep it safe — losing it means losing the ability to update the app):
keytool -genkey -v -keystore ~/pckaiser-release.jks \ -keyalg RSA -keysize 2048 -validity 10000 -alias pckaiser -
Create
client/android/key.properties(git-ignored, never commit):storeFile=/home/you/pckaiser-release.jks storePassword=... keyAlias=pckaiser keyPassword=...
-
Build:
cd client flutter build apk --release # APK for direct distribution flutter build appbundle --release # AAB for the Play Store
Outputs land in
client/build/app/outputs/.
cd client
flutter build ipa --releaseRequires a Mac with Xcode and an Apple Developer account; then upload via Xcode/Transporter to TestFlight.
- Bump
version:inclient/pubspec.yaml(e.g.0.2.0+2— the+Nbuild number must increase for every store upload). - Run the full test suites (see above).
flutter build appbundle --releasewith the release keystore.- Upload to Play Console → Internal testing (beta round), promote to
production after the round. Store texts live in
store/metadata.md; screenshots still need to be taken on a device. - iOS:
flutter build ipa --release→ TestFlight.
App icons are generated from the original castle tile; regenerate after
changing client/assets/icon/* with:
cd client && dart run flutter_launcher_iconsThe V2 online backend (Dart shelf + PostgreSQL, Docker + Nginx) is designed
in ARCHITECTURE.md but not implemented yet; this section will grow when
it lands.
benchmark/ is a git submodule
(Vincenius/pckaiser-benchmark):
a self-contained benchmark for autonomous coding agents, cut from this
repository's own history. 15 independent tasks, each a user-facing problem
statement against a deterministic commit, scored by hidden tests that live
outside the agent's workdir — plus wall-clock time and token spend as
separate metrics.
git submodule update --init # after cloning this repository
benchmark/scripts/run-benchmark.sh --agent claude --model opus # whole suite
benchmark/scripts/setup-task.sh task-004 /tmp/bench/task-004 # one task: start state
benchmark/scripts/evaluate-task.sh task-004 /tmp/bench/task-004 # one task: scoreIt reads this repository's git history and never writes to it. Philosophy,
task list, scoring, anti-gaming design, agent runners and how to add a
task: benchmark/README.md.
Phases 0–6 of CHECKLIST.md are implemented and tested (~240 tests across
engine and client): complete rules engine (economy, dynasty, elections,
war, espionage, world events, AI) plus the playable Flutter client.
Phase 7 (device validation, beta) is in progress — the app has not yet had
its first on-device visual pass. Open items: CHECKLIST.md; history:
docs/HISTORY.md.
Maintenance note: this README is part of the definition of done — update it with every change to setup, build, test or deploy steps (see
CLAUDE.md).
Released under the MIT License — © 2026 Vincent Will.
PCKaiser is a fan remake. PCKaiser++ and its name belong to their original
authors (Martin Gelter & Lorenz Giefing); this project is an independent, non-commercial
homage and is not affiliated with or endorsed by the original. The original
tile graphics in imgs/ are included for reference and remain the property
of their respective owners.
0 comments
log in to comment.