Writing Your First Story
This guide walks through creating component stories step by step using a standard project generated from the Kotlin Multiplatform Wizard (kmp.new).
Prefer cloning a working project? Clone the starter template: github.com/aryapreetam/storytale-sample
1. Project Generation via kmp.new
Navigate to kmp.new and configure your project:

Wizard Settings
| Setting | Value | Notes |
|---|---|---|
| Project Name | storytale-sample |
Standard project directory identifier. |
| Project ID | org.storytale.sample |
Base package name for multiplatform sources. |
| Build System | Gradle | Storytale integrates directly into the Gradle Multiplatform toolchain. |
| UI Targets | Android, iOS, Desktop, Web | Select "Share UI via Compose Multiplatform" across targets. |
Download, unzip, and open the project in IntelliJ IDEA or Android Studio.
2. Project Structure & Plugin Setup
The generated storytale-sample project organizes shared UI and platform host targets cleanly:
storytale-sample/
├── gradle/
│ └── libs.versions.toml
├── shared/
│ ├── build.gradle.kts # Multiplatform configuration & Storytale plugin
│ └── src/
│ ├── commonMain/kotlin/ # Production Compose UI components
│ ├── androidMain/kotlin/
│ ├── jvmMain/kotlin/
│ └── wasmJsMain/kotlin/
├── androidApp/ # Android application host
├── desktopApp/ # Desktop JVM application host
├── webApp/ # Wasm Browser application host
└── iosApp/ # Xcode project & iOS application host
Open shared/build.gradle.kts and apply the Storytale plugin:
We can also write alias(libs.plugins.storytale) if we have it defined in libs.versions.toml.
Click Sync Now in your IDE. Once synced, Storytale automatically hooks into your targets and registers gallery tasks:


shared/build.gradle.ktsstorytale group- (1) Apply Storytale Plugin: Added to the shared multiplatform module
plugins { ... }block. - (2) Multiplatform UI Targets: Storytale configures galleries across all declared targets (
android,jvm,wasmJs,ios). - (3) Shared Compose Dependencies: Common UI libraries and dependencies declared in
commonMainare directly available to your stories. - (4) Automatic Task Generation: Tasks for code generation and running galleries appear in the Gradle tool window under the
storytaletask group.
Android Device Test Manifest & .gitignore
Storytale automatically synthesizes shared/src/androidDeviceTest/AndroidManifest.xml during Gradle execution to configure the instrumented APK runner for ADB. Because this file is generated on-the-fly and removed by ./gradlew clean, add it to your .gitignore:
3. Define Your First Story
Stories live in the commonStories source set, parallel to commonMain. In IntelliJ IDEA or Android Studio, right-click shared/src → New → Directory. Enter commonStories as the directory name.
The IDE helper suggests available source roots: select commonStories/kotlin. Inside this directory, create the package folder structure matching your project ID (e.g. org/storytale/sample/).


- (5) Add stories here: Create story files inside
shared/src/commonStories/kotlin/using the.story.ktextension (e.g.Button.story.kt). - (6) Write story with parameters & state: Define stories using Kotlin backtick identifiers (
`Primary Action Button`) and interactive knobs (val text by parameter("Click me!")). - (7) Run gallery for target: Double-click any of the target-specific story tasks from the Gradle tool window (e.g.
jvmStoriesRun,wasmJsBrowserStoriesDevelopmentRun) or execute them via terminal.
Create shared/src/commonStories/kotlin/org/storytale/sample/Button.story.kt:
package org.storytale.sample
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import org.jetbrains.compose.storytale.story
val `Primary Action Button` by story(group = "Buttons") {
val text by parameter("Click me!")
val isEnabled by parameter(true)
Button(
onClick = {},
enabled = isEnabled
) {
Text(text)
}
}
4. Run the Gallery
Run the interactive gallery on any platform target from the Gradle tool window or via CLI. Each platform provides a dedicated gallery runner:
Launches a native desktop window running the Compose Multiplatform gallery.

# Local development server with HMR
./gradlew :shared:wasmJsBrowserStoriesDevelopmentRun
# Build production distribution for static hosting
./gradlew :shared:wasmJsBrowserStoriesProductionExecutableDistribution
Starts a local development server or compiles optimized web assets ready for static hosting.
Live Starter Gallery: Hosted directly from the sample's production distribution at aryapreetam.github.io/storytale-sample.
Builds the gallery test APK, installs it to your connected device or emulator via ADB, and launches the gallery activity.
# Apple Silicon (M1/M2/M3/M4)
./gradlew :shared:iosSimulatorArm64StoriesRun
# Intel Mac (x86_64) — requires CMP 1.10 profile
./gradlew :shared:iosX64StoriesRun -PcmpProfile=1.10
Compiles the native iOS binary, installs it to the booted iOS simulator, and launches the gallery. Compose Multiplatform 1.11+ dropped iosX64 binaries; pass -PcmpProfile=1.10 when targeting Intel-based Mac simulators.
Grouping & Organizing Stories
Organize stories hierarchically using slashes in the group parameter:
val `Primary Button` by story(group = "Components/Buttons") {
Button(onClick = {}) { Text("Primary") }
}
val `Secondary Button` by story(group = "Components/Buttons") {
OutlinedButton(onClick = {}) { Text("Secondary") }
}
val `Text Input` by story(group = "Components/Inputs") {
TextField(value = "", onValueChange = {})
}
The gallery navigation tree mirrors these group paths, allowing large design systems to be structured cleanly into categories and subcategories.
How Compile-Time Registration Works
Storytale eliminates manual story registration and runtime reflection:
- Compiler Plugin Detection: The Storytale Kotlin compiler plugin scans
commonStoriesduring compilation forby story(...)property delegates. - Synthetic Code Generation: It generates platform-specific registration code that collects all story metadata, parameters, and composable content blocks.
- Target Entry Point Generation: For each enabled target (JVM, Android, Wasm, iOS), Storytale synthesizes an isolated gallery application entry point containing the full story catalog, navigation sidebar, and parameter inspector.
- Zero Production Overhead: Story code and test runners live exclusively in
commonStoriesand never pollute release binaries or production source sets.
Next Steps
- storytale-sample Starter: Clone the pre-configured starter repository with all targets enabled.
- gallery-demo Showcase: Explore full-featured story suites with complex states, animations, and custom themes in the sample project, or test drive the Live Web Showcase.
- Interactive Parameters: Expose editable knobs, booleans, dropdowns, and color pickers in the gallery inspector sidebar.
- Decorators & Theming: Wrap stories with theme providers, padding, surface containers, and device frame previews.
- Multiplatform Workflows: Configure target architecture, source set inheritance, and CI deployment pipelines.