{"id":13658261,"url":"https://github.com/svenjacobs/reveal","last_synced_at":"2025-08-22T17:20:01.295Z","repository":{"id":79794887,"uuid":"568775557","full_name":"svenjacobs/reveal","owner":"svenjacobs","description":"Reveal effect (coach mark) for Compose Multiplatform targeting Android, iOS, Desktop and Web","archived":false,"fork":false,"pushed_at":"2025-08-18T17:36:40.000Z","size":2680,"stargazers_count":547,"open_issues_count":8,"forks_count":16,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-08-18T19:25:08.610Z","etag":null,"topics":["android","coach-mark","coach-mark-android","coach-marks","coachmarks","compose","compose-multiplatform","ios","jetpack-compose","kmp","kotlin","kotlin-multiplatform","onboarding","reveal","showcase","tap-target","tour","tutorial","user-onboarding","walkthrough"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/svenjacobs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-11-21T11:38:46.000Z","updated_at":"2025-08-18T17:26:49.000Z","dependencies_parsed_at":"2023-07-19T07:45:33.590Z","dependency_job_id":"59516da1-a445-494c-ae70-025bb1357e8e","html_url":"https://github.com/svenjacobs/reveal","commit_stats":null,"previous_names":[],"tags_count":41,"template":false,"template_full_name":null,"purl":"pkg:github/svenjacobs/reveal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svenjacobs%2Freveal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svenjacobs%2Freveal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svenjacobs%2Freveal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svenjacobs%2Freveal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/svenjacobs","download_url":"https://codeload.github.com/svenjacobs/reveal/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svenjacobs%2Freveal/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271673536,"owners_count":24800710,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-22T02:00:08.480Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","coach-mark","coach-mark-android","coach-marks","coachmarks","compose","compose-multiplatform","ios","jetpack-compose","kmp","kotlin","kotlin-multiplatform","onboarding","reveal","showcase","tap-target","tour","tutorial","user-onboarding","walkthrough"],"created_at":"2024-08-02T05:00:58.117Z","updated_at":"2025-08-22T17:20:01.288Z","avatar_url":"https://github.com/svenjacobs.png","language":"Kotlin","readme":"![Deploy Release](https://img.shields.io/github/actions/workflow/status/svenjacobs/reveal/deploy-release.yml?label=Deploy%20Release)\n![Compose Multiplatform](https://img.shields.io/badge/Compose%20Multiplatform-1.8.1-blue)\n![Android](https://img.shields.io/badge/Android-green)\n![iOS](https://img.shields.io/badge/iOS-slategray)\n![Desktop](https://img.shields.io/badge/Desktop-tomato)\n![Web](https://img.shields.io/badge/Web-gold)\n\nReveal effect (also known as coach mark, onboarding, tutorial, walkthrough, etc.) with a beautiful\nAPI for [Compose Multiplatform](https://www.jetbrains.com/lp/compose-multiplatform/) targeting\nAndroid, iOS, Desktop and Web.\n\n![Demonstration](./assets/demo.gif)\n\n## Terminology\n\n| Term        | Description                                                                                |\n|-------------|--------------------------------------------------------------------------------------------|\n| Revealable  | An element which is revealed on the screen.                                                |\n| Reveal area | The area which is revealed around the revealable. Usually with a slight padding.           |\n| Overlay     | The overlay which greys out all contents except revealable. Can contain explanatory items. |\n\n## Getting started\n\n### Compose Multiplatform\n\nAs of version `3.0` Reveal is based on Compose Multiplatform targeting Android, iOS, Desktop and\nWeb. However please note that except Android the other platforms are currently not well tested and\nsome of the targets are still alpha or experimental.\n\nWhen using Reveal on Android, please make sure that the version of Google's Jetpack Compose is\ncompatible with the version of Compose Multiplatform that Reveal uses, which you can\nfind [here](./gradle/libs.versions.toml#L5).\n\n### Installation\n\nThe minimum supported Android SDK is 21 (Android 5.0), which is a requirement of Jetpack Compose.\nAdd Reveal as a dependency to your project. It's available on Maven Central.\n\n```kotlin\ndependencies {\n    implementation(\"com.svenjacobs.reveal:reveal-core:$REVEAL_VERSION\")\n}\n```\n\n#### Artifacts\n\n| Name                    | Description                                                                 |\n|-------------------------|-----------------------------------------------------------------------------|\n| `reveal-core`           | Contains core classes. You need this 🙂                                     |\n| `reveal-shapes`         | Additional shapes for explanatory items                                     |\n| `reveal-compat-android` | Compatibility utilities for Android targets with a mixed View/Compose setup |\n\n### Compose\n\nThere are two significant composables:\n\nFirst, there is `RevealCanvas`, which is responsible for rendering the effect. There should only be\none `RevealCanvas` instance in the Compose hierarchy and it should be at a top or the topmost\nposition of the tree in order to ensure that the effect is rendered \"full screen\" above all other\nelements.\n\nSecond, the `Reveal` composable is responsible for registration of and interaction with revealable\nitems. There can be many `Reveal` instances and they have a direct relation to the `RevealCanvas`\ninstance. Usually there should be at most one `Reveal` per \"screen\" of an application.\n\n```kotlin\n@Composable\nfun App() {\n    val revealCanvasState = rememberRevealCanvasState()\n\n    // Single instance that should be at the top of the Compose hierarchy\n    RevealCanvas(\n        modifier = Modifier.fillMaxSize(),\n        revealCanvasState = revealCanvasState,\n    ) {\n        MainScreen(revealCanvasState = revealCanvasState)\n    }\n}\n\n@Composable\nfun MainScreen(revealCanvasState: RevealCanvasState) {\n    val revealState = rememberRevealState()\n\n    // Usually one instance per screen\n    Reveal(\n        revealCanvasState = revealCanvasState,\n        revealState = revealState,\n        onRevealableClick = {},\n        onOverlayClick = {},\n    ) {\n        // Contents\n    }\n}\n```\n\nInside `Reveal` specify revealable items via the `revealable` modifier.\n\n```kotlin\nenum class Keys { HelloWorld }\n\nColumn {\n    Text(\n        modifier = Modifier.revealable(key = Keys.HelloWorld),\n        text = \"Hello world\",\n    )\n}\n```\n\nNow launch the reveal effect via `revealState.reveal(Keys.HelloWorld)`.\n\nNice, you just launched your first reveal effect. But what is missing is some explanatory item like\ntext or image next to the reveal area. So let's add one.\n\nExplanatory items are specified via `overlayContent` of the `Reveal` composable.\n\n```kotlin\nReveal(\n    overlayContent = { key -\u003e\n        when (key) {\n            Keys.HelloWorld -\u003e {\n                Surface(\n                    modifier = Modifier\n                        .align(horizontalArrangement = RevealOverlayArrangement.Horizontal.Start)\n                        .padding(8.dp),\n                    shape = RoundedCornerShape(4.dp),\n                    color = Color.White,\n                ) {\n                    Text(\"This is an explanation\")\n                }\n            }\n        }\n    }\n) {\n    // Contents\n}\n```\n\nThe scope of the overlay content composable provides `align()` modifiers to align the item either to\nthe start, top, end or bottom of the reveal area.\n\n`Reveal` provides two click listeners: `onRevealableClick` is called when the reveal area is clicked\nwith the key of the current revealable as the first argument. `onOverlayClick` is called when the\noverlay is clicked somewhere, also with the key argument. Use any of these click listeners to reveal\nthe next item, for example for some kind of tutorial, or to hide the effect via\n`revealState.hide()`.\n\nThat's it for now. For more details have a look at the [demo application](./demo-app) and the\nJavaDoc. The library is well documented 😉\n\n## Frequently Asked Questions\n\nSee [FAQ.md](FAQ.md)\n","funding_links":[],"categories":["Libraries","Multiplatform","Uncategorized","Kotlin"],"sub_categories":["🍎 Compose UI","Android samples","Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsvenjacobs%2Freveal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsvenjacobs%2Freveal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsvenjacobs%2Freveal/lists"}