https://github.com/sorunokoe/swiftui-compose-skill
AI coding skill for Compose Multiplatform ↔ SwiftUI bidirectional interop. UIViewControllerRepresentable, coordinator pattern, state sharing.
https://github.com/sorunokoe/swiftui-compose-skill
ai-skill compose-multiplatform ios kotlin-multiplatform swiftui uiviewcontrollerrepresentable
Last synced: 18 days ago
JSON representation
AI coding skill for Compose Multiplatform ↔ SwiftUI bidirectional interop. UIViewControllerRepresentable, coordinator pattern, state sharing.
- Host: GitHub
- URL: https://github.com/sorunokoe/swiftui-compose-skill
- Owner: sorunokoe
- License: mit
- Created: 2026-04-28T12:57:15.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-04-28T15:20:23.000Z (about 2 months ago)
- Last Synced: 2026-04-28T15:23:52.394Z (about 2 months ago)
- Topics: ai-skill, compose-multiplatform, ios, kotlin-multiplatform, swiftui, uiviewcontrollerrepresentable
- Size: 23.4 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ ┃
┃ ◆ swiftui · compose AI Coding Skill ┃
┃ ───────────────────────────────────────────── ┃
┃ ┃
┃ Compose ◄────────────────────────────► SwiftUI ┃
┃ ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
[](LICENSE)
[](https://www.jetbrains.com/compose-multiplatform/)
[](https://swift.org)
[](https://www.jetbrains.com/compose-multiplatform/)
[](https://github.com/sorunokoe/skills-evolution)
[](https://claude.ai)
[](https://openai.com/codex)
[](https://github.com/features/copilot)
[](https://cursor.com)
[](https://gemini.google.com)
[](https://github.com/sorunokoe/swiftui-compose-skill/pulls?q=is%3Apr+is%3Amerged)
**An AI coding skill for bidirectional interop between
Compose Multiplatform and SwiftUI.**
[What it covers](#what-this-skill-covers) · [Files](#files) · [Core principle](#core-principle) · [Quick start](#quick-start) · [Key rules](#key-rules-summary) · [Docs](#official-documentation) · [Automated maintenance](#automated-maintenance)
---
## What This Skill Covers
| | |
|---|---|
| **Compose in SwiftUI** | `ComposeUIViewController` + `UIViewControllerRepresentable` wiring |
| **State bridging** | `makeCoordinator()`, push and bidirectional patterns, Kotlin `mutableStateOf` |
| **SwiftUI in Compose** | `UIKitView`, `UIKitViewController`, `UIHostingController` |
| **UIKit embedding** | Maps, text fields, camera, pickers via `UIKitView` |
| **Teardown** | `dismantleUIViewController`, `AsyncStream.onTermination` |
| **Touch routing** | `UIKitInteropProperties` cooperative vs non-cooperative gestures |
> 🔗 Bridging KMP data and logic into Swift? See the companion [**swift-kmp**](https://github.com/sorunokoe/swift-kmp-skill) skill.
---
## Core Principle
> **Create the Compose `UIViewController` once, then update state through methods —
> never recreate it.**
```
❌ Anti-pattern: .id(someState) on a Compose view
→ tears down and recreates UIViewController on every state change
→ visual glitches, wasted memory, Compose lifecycle restart
✅ Correct: makeCoordinator() holds the UIViewController reference (created once)
updateUIViewController() calls context.coordinator.update*(newState)
```
Apple's documentation confirms the intended lifecycle:
> *"SwiftUI calls `makeCoordinator()` before calling `makeUIViewController(context:)`.
> The system provides your coordinator either directly or as part of a context structure
> when calling the other methods of your representable instance."*
---
## Files
| File | Load when | Tokens |
|------|-----------|--------|
| [`SKILL.md`](SKILL.md) | **Always first** — anti-patterns, quick reference, review checklist | ~1.5k |
| [`references/compose-in-swiftui.md`](references/compose-in-swiftui.md) | Embedding Compose in SwiftUI; coordinator wiring; `ComposeUIViewController` Kotlin setup | ~2k |
| [`references/swiftui-in-compose.md`](references/swiftui-in-compose.md) | Embedding SwiftUI/UIKit inside Compose; `UIKitViewController`; `UIKitView` | ~2k |
| [`references/state-sharing.md`](references/state-sharing.md) | Bidirectional state; all 3 patterns; `StateFlow` → `AsyncStream`; `dismantleUIViewController` | ~2.5k |
> **Token budget:** `SKILL.md` (~1.5k tokens) covers anti-patterns and routing. Load one reference only when you need the detailed API for that topic.
---
## Quick Start
### 1. Install
```bash
# Clone into the canonical skill location:
git clone https://github.com/sorunokoe/swiftui-compose-skill.git \
/path/to/your-project/.github/skills/swiftui-compose
# Optional: detach from upstream git history
rm -rf /path/to/your-project/.github/skills/swiftui-compose/.git
```
> **Why `.github/skills/swiftui-compose/`?** This is the path GitHub Copilot, Cursor, and
> [skills-evolution](https://github.com/sorunokoe/skills-evolution) discover skills from.
### 2. Use with GitHub Copilot
```
@swiftui-compose Help me embed a Compose map screen in my SwiftUI app with filter state
```
### 3. Use with Claude / any AI agent
```
Load swiftui-compose/SKILL.md, then swiftui-compose/references/state-sharing.md.
I need to embed a Kotlin Compose map screen in SwiftUI. The SwiftUI side has
@State var filters: [MapFilter] that need to flow into Compose when they change.
Compose calls back via onMarkerClick. Implement the full coordinator pattern.
```
---
---
## Key Rules (summary)
- ❌ **`.id(someState)` on a Compose view** — recreates the entire lifecycle
- ❌ **Calling the `build:` closure inside `updateUIViewController`** — creates a new Compose lifecycle on every update
- ❌ **Storing a `@State` copy of the Kotlin holder** — use `makeCoordinator()` for a stable reference
- ✅ **`CADisableMinimumFrameDurationOnPhone = YES` in `Info.plist`** — required for Compose on iOS
- ✅ **`context.coordinator.update*(…)` in `updateUIViewController`** — correct way to push SwiftUI state to Compose
- ✅ **`dismantleUIViewController` implemented** when coordinator owns subscriptions or tasks
Full rules and review checklist in [`SKILL.md`](SKILL.md).
---
## The Three State Patterns
| When | Pattern |
|------|---------|
| Compose owns all state; SwiftUI just positions | **Unidirectional** — simple `UIViewControllerRepresentable`, empty `updateUIViewController` |
| SwiftUI state needs to flow into Compose | **Push** — `makeCoordinator()` + `context.coordinator.update*()` in `updateUIViewController` |
| State flows both ways + Compose fires Swift callbacks | **Bidirectional** — coordinator holds holder, callbacks provided at build time |
Full patterns with code in [`references/state-sharing.md`](references/state-sharing.md).
---
## Official Documentation
| Topic | Link |
|-------|------|
| Compose Multiplatform ↔ SwiftUI | [kotlinlang.org →](https://kotlinlang.org/docs/multiplatform/compose-swiftui-integration.html) |
| Compose Multiplatform ↔ UIKit | [kotlinlang.org →](https://kotlinlang.org/docs/multiplatform/compose-uikit-integration.html) |
| Apple `UIViewControllerRepresentable` | [developer.apple.com →](https://developer.apple.com/documentation/swiftui/uiviewcontrollerrepresentable) |
| Apple `makeCoordinator()` | [developer.apple.com →](https://developer.apple.com/documentation/swiftui/uiviewcontrollerrepresentable/makecoordinator()-9vwm8) |
| Apple `dismantleUIViewController` | [developer.apple.com →](https://developer.apple.com/documentation/swiftui/uiviewcontrollerrepresentable/dismantleuiviewcontroller(_:coordinator:)) |
| Apple `UIHostingController` | [developer.apple.com →](https://developer.apple.com/documentation/swiftui/uihostingcontroller) |
| Compose Multiplatform interop examples | [github.com/JetBrains →](https://github.com/JetBrains/compose-multiplatform/tree/master/examples/interop) |
---
## Requirements
| | Version |
|---|---|
| Compose Multiplatform | 1.8+ (iOS **stable** since 1.8.0, May 2025) |
| Kotlin | 2.1+ |
| Swift | 5.9+ |
| iOS | 15.0+ |
> Compose Multiplatform iOS is **stable** as of version 1.8.0 (May 2025). CMP 1.8+ requires Kotlin 2.1+.
---
## Related Skills
> 🔗 **Bridging Kotlin data and logic into your Swift feature modules?**
> Check out [**swift-kmp**](https://github.com/sorunokoe/swift-kmp-skill) — the companion skill covering the bridge layer architecture, interactors, `SkieSwiftFlow` → `AsyncStream` wrapping, type mapping, and `KotlinThrowable` containment.
---
## Automated Maintenance
This skill is governed by [**skills-evolution**](https://github.com/sorunokoe/skills-evolution) — AI skill governance that keeps guidance files accurate and up to date automatically.
### gh-aw (recommended)
```bash
# PR review — AI feedback on every PR touching SKILL.md or references/**
gh aw add sorunokoe/skills-evolution/workflows/oss-skill-pr-check.md@latest
# Monthly update — version checks, AI content patches, opens PR
gh aw add sorunokoe/skills-evolution/workflows/oss-skill-update.md@latest
gh aw compile
```
### GitHub Actions
Monthly skill health workflow
[`.github/workflows/skill-health.yml`](.github/workflows/skill-health.yml) — runs monthly and on demand:
- **Structural audit** — broken local links, missing frontmatter fields
- **AI content update** — checks `SKILL.md` + `references/*.md` against the latest `compose-multiplatform` release; proposes conservative patches via GitHub Models
```yaml
# .github/workflows/skill-health.yml
name: Skill Health
on:
schedule:
- cron: "0 3 1 * *"
workflow_dispatch:
permissions:
contents: write
pull-requests: write
models: read
jobs:
health:
uses: sorunokoe/skills-evolution/.github/workflows/oss-skill-health.yml@latest
with:
enable_ai_skill_update: true
secrets:
token: ${{ secrets.GITHUB_TOKEN }}
```
---
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for how to improve patterns or add new reference files.
## License
[MIT](LICENSE)