This project was created for the Kotlin Multiplatform Contest.
erzaehler is a small visual‑novel generator to help you practice a language. Provide a topic (or let the app suggest one), choose a language and level, and watch a short scene play out with generated voiceover. Each story is created on the fly, so every run is a little different.
Built with Kotlin Multiplatform and Compose Multiplatform, it runs on Android and iOS with a small Ktor backend that manages story generation and text‑to‑speech.
Unmute the videos.
demo-korean-1.mov
demo-german-1.mov
The project has three modules:
- composeApp: Compose Multiplatform UI and DI (Koin); platform bindings for audio
- shared: domain models, use cases, and repositories
- server: Ktor backend exposing
/topic,/story,/voice; including a small wrapper for the Cartesia API
You’ll run the server once, then start any client target you want.
- macOS (required for iOS; optional for Android)
- Android Studio and Xcode
- JDK 11+ (project targets Java 11)
- Gradle (wrapper included:
./gradlew)
Helpful references:
The server uses:
- Google Gemini for topic/story generation
- Cartesia for text‑to‑speech
Create API keys and export them as environment variables before launching the server:
export GOOGLE_API_KEY=YOUR_GEMINI_KEY
export CARTESIA_API_KEY=YOUR_CARTESIA_KEYThen run the backend:
Or open the project and use the
Run ApplicationKtbutton in your IDE.
./gradlew :server:runThe server starts on http://127.0.0.1:8080.
Notes:
- iOS simulator and Desktop use 127.0.0.1 directly.
- Android emulator uses a separate loopback. Easiest fix: reverse port 8080 so 127.0.0.1 works in the app:
adb reverse tcp/8080 tcp/8080If you cannot use adb reverse, change the client host in shared/src/commonMain/kotlin/com/karastift/erzaehler/Constants.kt (SERVER_HOST) to 10.0.2.2 for the Android emulator.
I recommend to follow the official documentation for running the actual mobile app either on Android or iOS Simulator.
This project uses character sprites from: https://pixelserial.itch.io/rpg-top-down-character-asset-pack
License summary (author’s terms):
- You can: use in personal/commercial projects; modify and include in games (free or paid).
- You can’t: resell or redistribute the assets (even if modified).
Because redistribution is forbidden, the sprites are not included in this repository. To use them locally:
- Download the asset pack and extract it.
- Slice the sprites into frames using the helper script slice-assets.py:
- Copy the generated frames into Compose resources so the app can load them:
- Choose Language and Level which affects story and speech speed.
- Enter a topic or tap the sparkle icon to generate one.
- Tap the submit button and listen!
- Kotlin Multiplatform — shared domain + networking across targets
- Compose Multiplatform — declarative UI for Android, iOS, Desktop, Web
- Ktor — backend server and HTTP client
- Koin — lightweight dependency injection
- Kotlinx Serialization — JSON serialization
- Koog (LLM) — prompt execution for topic/story generation
- Cartesia TTS — voice generation for dialogue
mkdir -p composeApp/src/commonMain/composeResources/drawable
cp presliced_flattened/*.png composeApp/src/commonMain/composeResources/drawable/- 401/403 from backend: verify
GOOGLE_API_KEYandCARTESIA_API_KEYare set in your shell. - Android cannot reach backend: run
adb reverse tcp/8080 tcp/8080(or changeSERVER_HOSTto10.0.2.2).
This project is licensed under the MIT License. See LICENSE.
