A Mini-Motorways-style resource/traffic game: you draw a road network and cars route themselves from houses to destinations along the shortest connected path. Built with Kotlin Multiplatform + Compose Multiplatform so the same game code runs on Android now and iOS later.
- docs/ARCHITECTURE.md — code layout, tech design, build/toolchain, and the pick-up-from-fresh guide. Start here.
- docs/DESIGN.md — the game design.
- docs/ROADMAP.md — status + the deferred/punted backlog.
- CLAUDE.md — quick rules for AI-assisted work in this repo.
composeApp/
src/commonMain/kotlin/com/example/stroads/
game/ # PURE Kotlin simulation — no UI, no platform types (portable)
Grid.kt # board + tiles
Pathfinder.kt # A* over the road network ("fast path algo")
Car.kt # a car following a cached path
GameWorld.kt # spawn/update loop, one house + one destination
ui/
GameScreen.kt # Compose Canvas rendering + tap-to-place + game loop
App.kt # root composable (shared by both platforms)
src/androidMain/ # MainActivity + manifest + theme (Android entry point)
src/iosMain/ # MainViewController (iOS entry point)
iosApp/ # Xcode project that hosts the shared Compose UI on iOS
The golden rule for portability: keep game/ free of Compose and platform
imports. Rendering/input live in ui/. That separation is what lets iOS reuse
100% of the game and most of the drawing.
java isn't on PATH globally; use the Android Studio bundled JBR:
export JAVA_HOME="/home/kalieki/Downloads/android-studio-quail3-linux/android-studio/jbr"
export PATH="$JAVA_HOME/bin:$PATH"./gradlew :composeApp:assembleDebug # build the Android APK
./gradlew :composeApp:installDebug # build + install on a connected device/emulatorOr just open the folder in Android Studio and press Run.
Testing is a standing requirement: add or update tests with every change, and commit only when they're green. Run the suite on the JVM (no device):
./gradlew :composeApp:testAndroidHostTestWhat's covered (all in composeApp/src/commonTest):
game/— the whole simulation is pure, platform-free Kotlin, so it's fully unit-tested: buildings/footprints, grid rules, weighted A*, the car lifecycle, and the office-never-oversubscribed reservation invariant.ui/pure logic — the isometric projection is kept Compose-free (Iso) and tested, including aproject↔cellAtround-trip that guards tap→cell mapping.
Design rule that makes this possible: keep logic out of Compose. game/ has no
Compose/platform imports, and rendering math (projection, sprite mapping) is
extracted from the Compose renderer so it's testable without UI infrastructure.
Compose recomposition/rendering itself (e.g. HUD bindings) is verified on the emulator; a Robolectric/Compose-UI-test harness is a possible future addition.
The Gradle/Kotlin side is fully wired (iOS targets + framework + iosMain).
On a Mac with Xcode: open iosApp/iosApp.xcodeproj, set your signing Team
in iosApp/Configuration/Config.xcconfig (or the Signing pane), and Run.
The build phase invokes ./gradlew :composeApp:embedAndSignAppleFrameworkForXcode
to compile the shared framework.
iOS cannot be compiled on Linux — Apple targets require macOS. The
.xcodeprojhere is the standard KMP template; if Xcode complains, let it re-sync the file references (or regenerate from the KMP wizard) — the Swift/Kotlin sources are the real content.
Kotlin 2.2.10 · Compose Multiplatform 1.8.2 · AGP 9.3.1 · Gradle 9.5 · JDK 25 · compileSdk/targetSdk 37 · minSdk 24.