Releases: KodeinKoders/CuP
1.0.0-Beta-13
CuP 1.0.0-Beta-13 (2026-04-09)
This version brings significant updates, including a migration to Material Design 3, new plugins, and a refactoring of how dependencies are managed.
🚀 New Features
- Image Export Plugin: New
cup-plugin-image-exportartifact allows exporting presentation slides as images and/or pdf (only for JVM/Desktop). - Key Events Plugin: New
cup-plugin-key-eventsartifact for handling custom key events in presentations.
🛠 Improvements & Optimizations
- Material 3 Migration: Core UI components, including the presentation overlay and the speaker window, have been migrated from Material Design 2 to Material Design 3.
- Source Code Caching: Performance optimization where source code is parsed once and cached in the
Slidecache.
⚠️ Breaking Changes & Refactoring
- Dependency Management:
- The
CupDependencieshelper has been removed from the Gradle plugin. Users are now encouraged to manage dependencies using standard Gradle version catalogs or explicit declarations. - Several artifacts have been renamed and relocated for better project structure:
cup-source-code→cup-widgets-source-codecup-laser→cup-plugin-lasercup-speaker-window→cup-plugin-speaker-windowcup-widgets-material→cup-widgets-material2(to distinguish from the new Material 3 widgets).
- The
- Material 3 Widgets: Existing Material 2 widgets are still available in
cup-widgets-material2, while new Material 3 widgets are available incup-widgets-material3.
📦 Dependency Updates
- Kotlin: Updated to
2.3.20 - Compose Multiplatform: Updated to
1.10.3(including Material 31.10.0-alpha05) - Dokka: Updated to
2.2.0 - Maven Publish Plugin: Updated to
0.36.0 - Highlight.js: Updated to
11.11.1 - Multiplatform Markdown Renderer: Updated to
0.40.2
1.0.0-beta-12
1.0.0-beta-11
What's Changed
- Fix Gradle failure caused by private execute() TaskAction by @LouisCAD in #9
- kotlin 2.1.0 and compose 1.7.3
- Upgrade Gradle wrapper
New Contributors
Full Changelog: v1.0.0-Beta-10...v1.0.0-beta-11
1.0.0-Beta-10
- Detect when in Speaker Window with
isInSpeakerWindow()
1.0.0-Beta-09
- Kotlin 2.0.20
- Compose 1.6.10
1.0.0-Beta-08
Breaking changes
- Speaker notes are now forcibly in Markdown, so
SpeakerNotesMDis nowSpeakerNotes.
Features
- Speaker notes can now differ per step (if you have very long slides).
Other
- Enhanced Compose performance by enhancing stability (with KotlinX.Collection.Immutable).
- Some plugin API enhancements.
1.0.0-Beta-07
This version brings no change to the presentation API.
UI Changes & fixes
- Tools & overlays now have a light color theme to make it easier on the eye.
- Laser tool is not active anymore in the overview
Changes to plugin API
- Breaking change: The
CupPlugin.overlayfunction now has astate: PresentationStateparameter. - Added the
CupAdditionalOverlay.inMenuconstructor parameter & property to allow the overlay button to appear in an overflow menu.
1.0.0-Beta-06
- Added a new landing page for unsupported browsers (that do not support WebAssembly or Wasm Garbage Collection). Now displays a nice message, instead of a cryptic error message.
- Gradle plugin extensions now implement
ExtensionAware.
1.0.0-Beta-05
Changes
Breaking changes
SlideSpecsare now constructed directly, instead of by copy in a lambda. See the migration guide.
Version updates
- Kotlin 2.0.0.
- Compose 1.6.10.
Migration Guide
Kotlin 2.0.0
You need to add the kotlin("plugin.compose") plugin to your projects. See the dedicated migration guide.
Note that presentations written with CuP 1.0.0-Beta-05 (or superior) must be compiled with at least Kotlin 2.0.0 and Compose 1.6.10.
In Slide: new way of defining SlideSpecs
If you changed the size of a particular slide, or its transitions, you would have changed its specs with:
// Correct up to 1.0.0-Beta-04
// Incorrect starting at 1.0.0-Beta-05
val mySlide by Slide(
specs = {
copy(
size = SLIDE_SIZE_16_9,
startTransitions = coolTransition
)
}
) { /*...*/ }Using copy meant starting form the global "default" slide specs and overriding some of its values.
This mechanism is now done for you (with a merge function). The same code is now expressed much more concisely:
// Correct starting at 1.0.0-Beta-05
val mySlide by Slide(
specs = SlideSpecs(
size = SLIDE_SIZE_16_9,
startTransitions = coolTransition
)
) { /*...*/ }Note that in this example we do not provide endTransitions, which will be merged down from the default presentation specs.
In Slides: new way of defining grouped slides inside transitions
CuP provides a way of applying specific transitions in a group of slides.
For example, this is how you would have all slides in a group use vertical transitions between them (note that this changes neither the startTransitions of the first slide nor the endTransitions of the last slide since this changes the transitions between the slides of the group):
// Correct up to 1.0.0-Beta-04
// Incorrect starting at 1.0.0-Beta-05
val modes = Slides(
slide1, slide2, slide3,
specs = {
copyWithInsideTransitions(
config = it,
startTransitions = TransitionSet.moveVertical,
endTransitions = TransitionSet.moveVertical
)
}
)Due to changes in the way SlideSpecs are defined (explained in the next section), the copyWithInsideTransitions function is replaced by insideTransitionSpecs:
// Correct starting at 1.0.0-Beta-05
val modes = Slides(
slide1, slide2, slide3,
specs = {
it.insideTransitions(
startTransitions = TransitionSet.moveVertical,
endTransitions = TransitionSet.moveVertical
)
}
)Note that it is now the receiver, and no longer a parameter.
In Slides: new way of defining grouped slides SlideSpecs and user data
Slides allows you to group multiple slides, and apply specific SlideSpecs and user data to all slides in its group.
Here's how you would do that:
// Correct up to 1.0.0-Beta-04
// Incorrect starting at 1.0.0-Beta-05
val modes = Slides(
slide1, slide2, slide3,
// Make all slides in the group 16/9.
specs = { copy(size = SLIDE_SIZE_16_9) },
// Attach that data to all slides in the group.
user = MySpecificDataElement("foo-bar")
)We have implemented two changes:
SlideSpecsare now built directly and merged in each Slides.- user data is now built by slide, which allows you to configure it according to its
Slides.Position.
This code is now expressed as such:
// Correct starting at 1.0.0-Beta-05
val modes = Slides(
slide1, slide2, slide3,
// Make all slides in the group 16/9.
specs = { SlideSpecs(size = SLIDE_SIZE_16_9) },
// Attach that data to all slides in the group.
user = { MySpecificDataElement("foo-bar") }
)In essence, both specs and user now have the same logic :
public class Slides(
private val content: List<SlideGroup>,
private val user: ((Slides.Position) -> DataMap)? = null,
private val specs: ((Slides.Position) -> SlideSpecs)? = null
): SlideGroupNote that you can merge SlideSpecs together with the plus operator.
This is how you would set inside transitions and slide size to slides in a group:
// Correct starting at 1.0.0-Beta-05
val modes = Slides(
slide1, slide2, slide3,
specs = {
it.insideTransitionSpecs(
startTransitions = TransitionSet.moveVertical,
endTransitions = TransitionSet.moveVertical
) + SlideSpecs(
size = SLIDE_SIZE_16_9
)
}
)1.0.0-Beta-04
- Kotlin 2.0.0
- Compose 1.6.10