|
2 | 2 |
|
3 | 3 | **Product tours and feature showcases for Compose Multiplatform.** |
4 | 4 |
|
5 | | -[](http://kotlinlang.org) |
6 | | -[](https://www.jetbrains.com/lp/compose-multiplatform) |
| 5 | +[](http://kotlinlang.org) |
| 6 | +[](https://www.jetbrains.com/lp/compose-multiplatform) |
7 | 7 | [](https://github.com/MohamedRejeb) |
8 | 8 | [](https://opensource.org/licenses/Apache-2.0) |
9 | 9 | [](https://search.maven.org/search?q=g:%22com.mohamedrejeb.waypoint%22) |
10 | 10 |
|
11 | | -Waypoint is a Compose Multiplatform library for building guided product tours, onboarding flows, feature discovery, and persistent contextual hints. It ships a spotlight overlay, tooltip positioning with auto-flip, pluggable highlight styles, and a state machine for step navigation, all from a simple declarative DSL. |
| 11 | +<p align="center"> |
| 12 | + <img src="docs/assets/tour.gif" width="260" alt="A spotlight tour moving between targets, then switching to dark theme" /> |
| 13 | + <img src="docs/assets/hands-on.gif" width="260" alt="A hands-on step where the user types inside the highlighted field" /> |
| 14 | + <img src="docs/assets/sheet.gif" width="260" alt="A tour scrolling a list and following the user into a bottom sheet" /> |
| 15 | +</p> |
12 | 16 |
|
13 | | -Targets **Android**, **iOS**, **Desktop (JVM)**, and **Web (JS, Wasm)**. |
| 17 | +Waypoint walks your users through your app: it dims the screen, cuts a hole around the thing you want them to look at, and puts a tooltip next to it. You describe the steps in a small DSL, tag your composables with a modifier, and the library handles positioning, animation, scrolling and input blocking. |
14 | 18 |
|
15 | | -## Artifacts |
| 19 | +It runs on **Android**, **iOS**, **Desktop** and **Web** (JS and Wasm) from the same code. |
16 | 20 |
|
17 | | -| Artifact | Description | Platforms | Version | |
18 | | -|----------|-------------|-----------|---------| |
19 | | -| **waypoint-core** | State machine, overlay, tooltip positioning, target registration | Android, iOS, Desktop, Web (JS, Wasm) | [](https://search.maven.org/search?q=g:%22com.mohamedrejeb.waypoint%22%20AND%20a:%22waypoint-core%22) | |
20 | | -| **waypoint-material3** | Material3-styled tooltip with navigation buttons and progress | Android, iOS, Desktop, Web (JS, Wasm) | [](https://search.maven.org/search?q=g:%22com.mohamedrejeb.waypoint%22%20AND%20a:%22waypoint-material3%22) | |
| 21 | +## What it does |
21 | 22 |
|
22 | | -Pick `waypoint-core` alone for full control over the tooltip UI, or `waypoint-material3` for a ready-to-use Material3 experience. `waypoint-material3` depends on `waypoint-core` transitively. |
23 | | - |
24 | | -## Features |
25 | | - |
26 | | -- **Spotlight overlay** with pluggable cutout shapes (Circle, Rect, RoundedRect, Pill) |
27 | | -- **Highlight styles**: Spotlight, Pulse, Border, Ripple, None, or fully Custom, configurable per step |
28 | | -- **Spotlight effects**: Glow, SoftEdge, and custom draw lambdas decorate the cutout |
29 | | -- **Tooltip positioning** with auto-flip and screen-edge clamping |
30 | | -- **Step navigation**: `next`, `previous`, `goTo`, `stop`, `pause`, `resume` |
31 | | -- **Conditional steps** (`showIf`) and lifecycle callbacks (`onEnter`/`onExit`) |
32 | | -- **Interactive tutorials**: the user types and taps inside the highlighted element (`PassThrough`) while the rest of the screen is blocked |
33 | | -- **Event-driven progression** (`advanceOn`) and async gates (`beforeShow`) |
34 | | -- **Steps without a target**, shown as a centered card for intros and outros |
35 | | -- **Multi-element highlight**: one tooltip, multiple targets |
36 | | -- **Cross-hierarchy tours**: targets inside Dialog, Sheet, and Popup via `WaypointOverlayHost` |
37 | | -- **Persistent hints**: ambient beacons that live outside of tours |
38 | | -- **Tour sequences**: chain multiple tours with shared persistence |
39 | | -- **Beacons** (pulse or dot) as standalone attention indicators |
40 | | -- **Auto-scroll** targets into view through nested scroll containers |
41 | | -- **Keyboard navigation** (arrow keys, Enter, Escape) on Desktop and Web |
42 | | -- **Analytics**, **persistence**, **theming**, **accessibility** (live-region + RTL) built in |
43 | | -- Survives **configuration changes** via `rememberSaveable` |
| 23 | +- **Tours**: spotlight, pulse, border or ripple highlights, with a tooltip that flips and clamps to stay on screen. |
| 24 | +- **Hands-on steps**: let the user type or tap inside the highlighted element while the rest of the screen is blocked, and move on when they have done it (`advanceOn`). |
| 25 | +- **Works where your UI is**: targets in scrolling lists are scrolled into view, and a tour can follow the user into a dialog or bottom sheet. |
| 26 | +- **Steps that wait**: hold a step until data has loaded or a screen has opened (`beforeShow`), skip steps that do not apply (`showIf`). |
| 27 | +- **Beyond tours**: persistent hints and beacons for the "new feature" dot that stays until dismissed. |
| 28 | +- **Your design or ours**: a Material3 tooltip out of the box, or draw your own with `waypoint-core`, which has no design opinions. |
| 29 | +- **The boring parts**: keyboard navigation, screen reader announcements, RTL, show-once persistence, analytics hooks, and state that survives configuration changes. |
44 | 30 |
|
45 | 31 | ## Installation |
46 | 32 |
|
47 | | -Add the dependency to your module `build.gradle.kts`: |
48 | | - |
49 | 33 | ```kotlin |
50 | 34 | kotlin { |
51 | 35 | sourceSets { |
52 | 36 | commonMain.dependencies { |
53 | | - // Material3 tooltip (recommended) |
| 37 | + // Material3 tooltip, includes waypoint-core |
54 | 38 | implementation("com.mohamedrejeb.waypoint:waypoint-material3:0.1.0") |
55 | 39 |
|
56 | | - // OR: core only, for custom tooltips |
| 40 | + // or core only, if you draw your own tooltip |
57 | 41 | implementation("com.mohamedrejeb.waypoint:waypoint-core:0.1.0") |
58 | 42 | } |
59 | 43 | } |
60 | 44 | } |
61 | 45 | ``` |
62 | 46 |
|
63 | | -See [installation](docs/installation.md) for the version compatibility table and snapshots. |
| 47 | +Built with Kotlin 2.4.20 and Compose Multiplatform 1.12.1. See [installation](https://mohamedrejeb.github.io/compose-waypoint/installation/) for requirements and snapshots. |
64 | 48 |
|
65 | | -## Quick example |
| 49 | +## Quick start |
| 50 | + |
| 51 | +Three things: describe the steps, tag the targets, wrap the screen in a host. |
66 | 52 |
|
67 | 53 | ```kotlin |
68 | | -enum class OnboardingTarget { SearchBar, AddButton, Profile } |
| 54 | +enum class Onboarding { Search, Add, Profile } |
69 | 55 |
|
70 | 56 | @Composable |
71 | 57 | fun HomeScreen() { |
72 | | - val tourState = rememberWaypointState { |
73 | | - step(OnboardingTarget.SearchBar) { |
| 58 | + // 1. Describe the steps |
| 59 | + val tour = rememberWaypointState { |
| 60 | + step(Onboarding.Search) { |
74 | 61 | title = "Search" |
75 | 62 | description = "Find anything in your workspace." |
76 | 63 | } |
77 | | - step(OnboardingTarget.AddButton) { |
| 64 | + step(Onboarding.Add) { |
78 | 65 | title = "Create" |
79 | 66 | description = "Add a new item with one tap." |
80 | 67 | } |
81 | | - step(OnboardingTarget.Profile) { |
| 68 | + step(Onboarding.Profile) { |
82 | 69 | title = "Your profile" |
83 | 70 | description = "View and edit your account." |
84 | 71 | } |
85 | 72 | } |
86 | 73 |
|
87 | | - WaypointMaterial3Host(state = tourState) { |
| 74 | + // 3. Wrap the screen in a host |
| 75 | + WaypointMaterial3Host(state = tour) { |
88 | 76 | Column { |
89 | | - SearchBar( |
90 | | - modifier = Modifier.waypointTarget(tourState, OnboardingTarget.SearchBar), |
91 | | - ) |
92 | | - FloatingActionButton( |
93 | | - onClick = { /* ... */ }, |
94 | | - modifier = Modifier.waypointTarget(tourState, OnboardingTarget.AddButton), |
95 | | - ) { Icon(Icons.Default.Add, "Add") } |
96 | | - IconButton( |
97 | | - onClick = { /* ... */ }, |
98 | | - modifier = Modifier.waypointTarget(tourState, OnboardingTarget.Profile), |
99 | | - ) { Icon(Icons.Default.Person, "Profile") } |
| 77 | + // 2. Tag the targets |
| 78 | + SearchBar(Modifier.waypointTarget(tour, Onboarding.Search)) |
| 79 | + AddButton(Modifier.waypointTarget(tour, Onboarding.Add)) |
| 80 | + ProfileButton(Modifier.waypointTarget(tour, Onboarding.Profile)) |
100 | 81 | } |
101 | 82 | } |
102 | 83 |
|
103 | | - LaunchedEffect(Unit) { tourState.start() } |
| 84 | + LaunchedEffect(Unit) { tour.start() } |
| 85 | +} |
| 86 | +``` |
| 87 | + |
| 88 | +To turn a step into something the user does instead of something they read: |
| 89 | + |
| 90 | +```kotlin |
| 91 | +step(Onboarding.Search) { |
| 92 | + title = "Try a search" |
| 93 | + description = "Type something to continue." |
| 94 | + interaction = TargetInteraction.PassThrough |
| 95 | + advanceOn { snapshotFlow { query }.first { it.isNotEmpty() } } |
104 | 96 | } |
105 | 97 | ``` |
106 | 98 |
|
| 99 | +## Make it yours |
| 100 | + |
| 101 | +<img src="docs/assets/styles.gif" width="260" align="right" alt="One tour restyled live: spotlight, glow, pulse, border and ripple" /> |
| 102 | + |
| 103 | +The highlight is set for the whole tour or per step: |
| 104 | + |
| 105 | +```kotlin |
| 106 | +WaypointMaterial3Host( |
| 107 | + state = tour, |
| 108 | + highlightStyle = HighlightStyle.Spotlight( |
| 109 | + shape = SpotlightShape.Circle, |
| 110 | + effect = SpotlightEffect.Glow(), |
| 111 | + ), |
| 112 | +) { /* ... */ } |
| 113 | +``` |
| 114 | + |
| 115 | +Colors, typography and dimensions of the Material3 tooltip come from `WaypointMaterial3Theme`. If that is not enough, pass your own composable as `tooltipContent` and draw whatever you like. |
| 116 | + |
| 117 | +<br clear="right" /> |
| 118 | + |
107 | 119 | ## Documentation |
108 | 120 |
|
109 | | -- [Overview](docs/index.md) |
110 | | -- [Installation](docs/installation.md) |
111 | | -- [Quick Start](docs/getting-started.md) |
112 | | -- [Highlight Styles](docs/guides/highlight-styles.md) |
113 | | -- [Custom Tooltips](docs/guides/custom-tooltips.md) |
114 | | -- [Interactive Tutorials](docs/guides/interactive-tutorials.md) |
115 | | -- [Tour Sequences](docs/guides/tour-sequences.md) |
116 | | -- [Persistent Hints](docs/guides/hints.md) |
117 | | -- [Theming](docs/guides/theming.md) |
118 | | -- [Analytics](docs/guides/analytics.md) |
119 | | -- [Persistence](docs/guides/persistence.md) |
120 | | -- [API Reference](docs/api/waypoint-state.md) |
| 121 | +The full docs are at **[mohamedrejeb.github.io/compose-waypoint](https://mohamedrejeb.github.io/compose-waypoint/)**. Good places to start: |
| 122 | + |
| 123 | +- [Quick Start](https://mohamedrejeb.github.io/compose-waypoint/getting-started/) |
| 124 | +- [Highlight Styles](https://mohamedrejeb.github.io/compose-waypoint/guides/highlight-styles/) |
| 125 | +- [Interactive Tutorials](https://mohamedrejeb.github.io/compose-waypoint/guides/interactive-tutorials/) |
| 126 | +- [Tours in dialogs and sheets](https://mohamedrejeb.github.io/compose-waypoint/guides/multi-host/) |
| 127 | +- [Custom Tooltips](https://mohamedrejeb.github.io/compose-waypoint/guides/custom-tooltips/) |
| 128 | +- [Hints](https://mohamedrejeb.github.io/compose-waypoint/guides/hints/) and [Beacons](https://mohamedrejeb.github.io/compose-waypoint/guides/beacons/) |
121 | 129 |
|
122 | 130 | ## Sample |
123 | 131 |
|
124 | | -The `:sample` module contains seven focused demos, runnable on all targets: |
| 132 | +The recordings above come from the `:sample` module, a small trip planner whose onboarding is three chained tours, plus a Lab screen for trying every highlight and tooltip option live. It runs on all targets: |
125 | 133 |
|
126 | 134 | ```bash |
127 | 135 | # Desktop |
|
0 commit comments