
Template for creating animated, interactive slide decks with modular structure, customizable theming, and ready-to-use components for building polished presentations quickly.
Ski is a programmable presentation framework built on Compose Multiplatform. It allows Kotlin engineers to build slide decks the same way they build UI: with composables, state, and reusable components.
Ski targets Web (Wasm) and Desktop (JVM), enabling you to run the same presentation as a browser app or a desktop application.
Traditional slide tools are document-based. Engineers build interfaces using components, state, and predictable layout systems. That mismatch creates friction.
Ski aligns presentations with how Kotlin developers already work.
Built on Compose Multiplatform, Ski treats slides as composables instead of static pages. Layout is declarative. Animations are state-driven. Components are reusable. Slide progression can be modeled as UI state instead of duplicated screens.
If you can build it in Compose, you can present it.
Slides are composables.
You can:
Your presentation becomes an application, not a sequence of static documents.
Reveals and transitions are powered by Compose state.
Build animated lists, counters, diagrams, and charts using Compose animation APIs. No timeline editors. No slide duplication to simulate progression. Behavior is defined entirely in Kotlin.
Ski launches two synchronized windows:
Both windows stay synchronized on the current slide index. Screen-specific animation state is intentionally isolated per window.
On Web, this feature relies on browser popup APIs and is currently less stable than the Desktop implementation.
For UI-focused talks, you can demonstrate composables directly inside your slides.
Trigger state changes. Show layout behavior. Animate transitions. Walk through UI concepts without switching applications or embedding screen recordings.
./composeApp -> Application host for Web and Desktop targets
./shared -> Shared design system, resources, and reusable components
./segments -> Individual slide decks or modular presentation sections
composeApp contains the Compose Multiplatform entry points (commonMain, jvmMain, wasmJsMain).shared centralizes reusable UI primitives and design elements.segments encourages modular talk organization and reuse across presentations.PresentationDeck is the runtime engine that manages slide lifecycle, navigation, theming, and background rendering.
PresentationDeck(
mainFrame = mainFrame,
guidesFrame = guidesFrame,
background = background,
navigator = navigator,
slides = slides,
shareFrame = true
)SlideConfig definitionsSkiFrame overlay applied consistently across slidesSkiFrame overlay applied to each slideFrames provide decorative overlays or structural borders around slide content.
Built-in frames are available via FrameBuilder().
val mainFrame = FrameBuilder()
.setFrame { snake }
.setOpacity(FRAME_OPACITY)
.build()Frames are composable-driven and can be extended or replaced.
Hint: To use a shared frame instead of having each slide define its own, see PresentationDeck.kt
Ski components can be used locally within the repository or consumed as a dependency.
To use local shared components:
use_local_shared_components = trueThis flag can be toggled in gradle.properties.
# macOS/Linux
./gradlew :composeApp:wasmJsBrowserDevelopmentRun
# Windows
.\gradlew.bat :composeApp:wasmJsBrowserDevelopmentRun# macOS/Linux
./gradlew :composeApp:run
# Windows
.\gradlew.bat :composeApp:runPlease check the suggested prompt to use with your AI tool of choice.
Happy pitching!
Ski is a programmable presentation framework built on Compose Multiplatform. It allows Kotlin engineers to build slide decks the same way they build UI: with composables, state, and reusable components.
Ski targets Web (Wasm) and Desktop (JVM), enabling you to run the same presentation as a browser app or a desktop application.
Traditional slide tools are document-based. Engineers build interfaces using components, state, and predictable layout systems. That mismatch creates friction.
Ski aligns presentations with how Kotlin developers already work.
Built on Compose Multiplatform, Ski treats slides as composables instead of static pages. Layout is declarative. Animations are state-driven. Components are reusable. Slide progression can be modeled as UI state instead of duplicated screens.
If you can build it in Compose, you can present it.
Slides are composables.
You can:
Your presentation becomes an application, not a sequence of static documents.
Reveals and transitions are powered by Compose state.
Build animated lists, counters, diagrams, and charts using Compose animation APIs. No timeline editors. No slide duplication to simulate progression. Behavior is defined entirely in Kotlin.
Ski launches two synchronized windows:
Both windows stay synchronized on the current slide index. Screen-specific animation state is intentionally isolated per window.
On Web, this feature relies on browser popup APIs and is currently less stable than the Desktop implementation.
For UI-focused talks, you can demonstrate composables directly inside your slides.
Trigger state changes. Show layout behavior. Animate transitions. Walk through UI concepts without switching applications or embedding screen recordings.
./composeApp -> Application host for Web and Desktop targets
./shared -> Shared design system, resources, and reusable components
./segments -> Individual slide decks or modular presentation sections
composeApp contains the Compose Multiplatform entry points (commonMain, jvmMain, wasmJsMain).shared centralizes reusable UI primitives and design elements.segments encourages modular talk organization and reuse across presentations.PresentationDeck is the runtime engine that manages slide lifecycle, navigation, theming, and background rendering.
PresentationDeck(
mainFrame = mainFrame,
guidesFrame = guidesFrame,
background = background,
navigator = navigator,
slides = slides,
shareFrame = true
)SlideConfig definitionsSkiFrame overlay applied consistently across slidesSkiFrame overlay applied to each slideFrames provide decorative overlays or structural borders around slide content.
Built-in frames are available via FrameBuilder().
val mainFrame = FrameBuilder()
.setFrame { snake }
.setOpacity(FRAME_OPACITY)
.build()Frames are composable-driven and can be extended or replaced.
Hint: To use a shared frame instead of having each slide define its own, see PresentationDeck.kt
Ski components can be used locally within the repository or consumed as a dependency.
To use local shared components:
use_local_shared_components = trueThis flag can be toggled in gradle.properties.
# macOS/Linux
./gradlew :composeApp:wasmJsBrowserDevelopmentRun
# Windows
.\gradlew.bat :composeApp:wasmJsBrowserDevelopmentRun# macOS/Linux
./gradlew :composeApp:run
# Windows
.\gradlew.bat :composeApp:runPlease check the suggested prompt to use with your AI tool of choice.
Happy pitching!