{
  "markdown": "<p align=\"center\">\n  <img src=\"assets/logo.svg\" height=\"180\" alt=\"Swift FocusEngine Pro\" />\n</p>\n\n<h3 align=\"center\">Agent skill for focus management across all Apple platforms</h3>\n\n<p align=\"center\">\n  <img src=\"https://img.shields.io/badge/tvOS-15+-000000?logo=apple\" />\n  <img src=\"https://img.shields.io/badge/iOS-15+-000000?logo=apple\" />\n  <img src=\"https://img.shields.io/badge/watchOS-8+-000000?logo=apple\" />\n  <img src=\"https://img.shields.io/badge/visionOS-1+-000000?logo=apple\" />\n  <img src=\"https://img.shields.io/badge/macOS-12+-000000?logo=apple\" />\n  <img src=\"https://img.shields.io/badge/Swift-5.9+-F05138?logo=swift&logoColor=white\" />\n  <img src=\"https://img.shields.io/badge/License-MIT-blue\" />\n  <img src=\"https://img.shields.io/badge/version-1.8.1-brightgreen\" />\n</p>\n\n<p align=\"center\">\n  <a href=\"https://skills.sh/mhaviv/Swift-FocusEngine-Agent-Skill\">\n    <img src=\"https://img.shields.io/badge/skills.sh-Listed-6C47FF?logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHRleHQgeD0iNCIgeT0iMTgiIGZvbnQtc2l6ZT0iMTYiIGZpbGw9IndoaXRlIj7wn5ugPC90ZXh0Pjwvc3ZnPg==&logoColor=white\" />\n  </a>\n  <a href=\"https://github.com/twostraws/Swift-Agent-Skills\">\n    <img src=\"https://img.shields.io/badge/Swift_Agent_Skills-Listed-F05138?logo=swift&logoColor=white\" />\n  </a>\n  <a href=\"https://www.awesomeskills.dev/en/skill/mhaviv-swift-focusengine-agent-skill\">\n    <img src=\"https://img.shields.io/badge/awesomeskills.dev-Listed-10B981\" />\n  </a>\n  <a href=\"https://github.com/mhaviv/Swift-FocusEngine-Agent-Skill/stargazers\">\n    <img src=\"https://img.shields.io/github/stars/mhaviv/Swift-FocusEngine-Agent-Skill?style=flat&logo=github&label=Stars\" />\n  </a>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://x.com/michael_haviv\">\n    <img src=\"https://img.shields.io/badge/Contact-@michael__haviv-1DA1F2?logo=x&logoColor=white\" />\n  </a>\n  <a href=\"https://www.linkedin.com/in/michaelhaviv/\">\n    <img src=\"https://img.shields.io/badge/LinkedIn-Michael_Haviv-0A66C2?logo=linkedin&logoColor=white\" />\n  </a>\n</p>\n\n---\n\nSwift FocusEngine Pro is a free, open-source agent skill that helps AI coding assistants write correct focus management code for **tvOS**, **iOS/iPadOS**, **watchOS**, **visionOS**, and **macOS**. It covers SwiftUI, UIKit, AppKit, and RealityKit — targeting the mistakes LLMs actually make with Apple's focus engine.\n\nBuilt from real-world experience shipping production tvOS apps, Apple developer documentation, WWDC sessions (2017-2025), and community best practices from Airbnb, Showmax, and others.\n\nWorks with [Claude Code](https://claude.ai/code), [Codex](https://openai.com/codex), [Cursor](https://cursor.sh), [GitHub Copilot](https://github.com/features/copilot), [Gemini CLI](https://github.com/google-gemini/gemini-cli), and any tool supporting the [Agent Skills](https://agentskills.io) format.\n\n## Table of Contents\n\n- [Who This Is For](#who-this-is-for)\n- [Why Use an Agent Skill for Focus?](#why-use-an-agent-skill-for-focus)\n- [Installing](#installing)\n- [Using](#using)\n- [What It Covers](#what-it-covers)\n- [Anti-Patterns It Catches](#anti-patterns-it-catches)\n- [FAQ](#faq)\n- [Sources](#sources)\n- [Complementary Skills](#complementary-skills)\n- [Changelog](#changelog)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Who This Is For\n\n- **tvOS developers** — building apps where every interaction depends on the focus engine working correctly\n- **iOS/iPadOS developers** — adding keyboard, game controller, or external display support with focus groups\n- **visionOS developers** — navigating the differences between gaze, hover, and focus in spatial computing\n- **macOS developers** — building keyboard-navigable apps with key view loops, focus rings, and menu commands\n\n## Why Use an Agent Skill for Focus?\n\nFocus management on Apple platforms is one of the hardest things to get right — and one of the hardest things to debug when it breaks.\n\nThe focus engine is geometric, not hierarchical. It doesn't follow your view tree. When a user swipes right and focus jumps two rows away instead of to the next item, there's no error, no crash, no log — it just looks broken. The item wasn't perfectly vertically aligned, so the engine picked a different candidate. You'll spend hours in `UIFocusDebugger` before you figure out why.\n\nApple's documentation covers the APIs but not the real-world edge cases: what happens when you reload data and focus resets to the top, why `.disabled()` silently removes views from the focus chain on tvOS, why `.focusSection()` is the difference between a usable scroll view and chaos, or why `onHover` doesn't fire from eye gaze on visionOS.\n\nLLMs generate focus code that compiles and looks reasonable — but breaks in ways you only discover on a real device with a Siri Remote in your hand. This skill is built from my experience getting focus to actually work in a complex, production tvOS app. Every anti-pattern in here is something I hit, debugged, and fixed.\n\n## Installing\n\n### Claude Code\n\n```bash\n# Global (all projects)\nnpx skills add https://github.com/mhaviv/Swift-FocusEngine-Agent-Skill --skill swift-focusengine-pro -g -y\n\n# Project-level only\nnpx skills add https://github.com/mhaviv/Swift-FocusEngine-Agent-Skill --skill swift-focusengine-pro -y\n```\n\n### Codex\n\n```bash\nnpx skills add https://github.com/mhaviv/Swift-FocusEngine-Agent-Skill --skill swift-focusengine-pro --agent codex\n```\n\n### Cursor\n\n```bash\nnpx skills add https://github.com/mhaviv/Swift-FocusEngine-Agent-Skill --skill swift-focusengine-pro --agent cursor\n```\n\n### GitHub Copilot\n\n```bash\nnpx skills add https://github.com/mhaviv/Swift-FocusEngine-Agent-Skill --skill swift-focusengine-pro --agent github-copilot\n```\n\n### Gemini CLI\n\n```bash\nnpx skills add https://github.com/mhaviv/Swift-FocusEngine-Agent-Skill --skill swift-focusengine-pro --agent gemini\n```\n\n### Other Agents\n\nAny agent that supports the [Agent Skills](https://agentskills.io) format can use this skill. See [agentskills.io](https://agentskills.io) for instructions on adding skills to your agent.\n\n<details>\n<summary>Don't have Node installed?</summary>\n\n```bash\nbrew install node\n```\n\nOr download from [nodejs.org](https://nodejs.org).\n</details>\n\n### Updating\n\nSkills are installed as local copies — they don't auto-update. To pull the latest version:\n\n```bash\n# Update all installed skills\nnpx skills update -g -y\n\n# Or reinstall this skill specifically\nnpx skills add https://github.com/mhaviv/Swift-FocusEngine-Agent-Skill --skill swift-focusengine-pro -g -y\n```\n\n⭐ **Star and Watch** this repo to get notified of new releases.\n\n## Using\n\n### Claude Code\n```\n/swift-focusengine-pro Review this view for tvOS focus issues\n```\n\n### Codex\n```\n$swift-focusengine-pro Check my SwiftUI code for focus anti-patterns\n```\n\n### Cursor\n```\n/swift-focusengine-pro Review this view for tvOS focus issues\n```\n\n### GitHub Copilot\n```\n/swift-focusengine-pro Review this view for tvOS focus issues\n```\n\n### Gemini CLI\n```\nUse the swift-focusengine-pro skill to review my focus handling code\n```\n\n### Any Agent\n> Use the Swift FocusEngine Pro skill to audit my project for focus management problems\n\n### Example Prompts\n\n- *\"Why isn't the first item focused when my view appears?\"*\n- *\"Focus is jumping to a completely different row when I swipe right — the items aren't perfectly aligned vertically\"*\n- *\"How do I keep focus position after my data reloads?\"*\n- *\"I added .disabled() to a button but now focus skips over the entire section\"*\n- *\"What's the difference between gaze and focus on visionOS?\"*\n- *\"My Digital Crown rotation stopped working after I reordered my view modifiers\"*\n- *\"How do I make menu bar commands respond to whichever document window is focused?\"*\n\n## What It Covers\n\n### 5,000+ lines of focus expertise across 14 reference files\n\n| Reference | Platform | Coverage |\n|-----------|----------|----------|\n| **anti-patterns.md** | All | 30 critical mistakes: 17 original tvOS + 6 production tvOS + 7 macOS-specific |\n| **swiftui-focus.md** | tvOS | @FocusState, focusSection, prefersDefaultFocus, AutoFocusManager pattern |\n| **uikit-focus.md** | tvOS | UIFocusEnvironment, UIFocusGuide, shouldUpdateFocus, didUpdateFocus |\n| **ios-focus.md** | iOS/iPadOS | SwiftUI + UIKit: focus groups, focusGroupIdentifier, UIFocusHaloEffect, keyboard nav, focusedValue, game controller, Stage Manager |\n| **watchos-focus.md** | watchOS | SwiftUI: Digital Crown routing, sequential focus, Crown conflicts, .digitalCrownAccessory |\n| **visionos-focus.md** | visionOS | SwiftUI + UIKit + RealityKit: gaze vs hover vs focus, HoverEffect, HoverEffectComponent |\n| **focus-styling.md** | All | ButtonStyle + isFocused, FocusBorder, CABasicAnimation, CardButtonStyle, macOS focus ring styling |\n| **focus-restoration.md** | All | Data reload handling, safe reload pattern, row offset tracking |\n| **layout-patterns.md** | tvOS | Table-of-collections, sidebar+content, tab bar, hero+catalog |\n| **macos-focus.md** | macOS | AppKit + SwiftUI: key view loop, focus ring, NSView focus APIs, focusedValue for menus, Mac Catalyst, Full Keyboard Access |\n| **realitykit-focus.md** | visionOS | RealityKit entity hover, collision shapes, gestures, shader effects, mixed hierarchies |\n| **async-focus.md** | All | @MainActor coordination, focus after data load, NavigationStack pop, Task cancellation |\n| **accessibility-focus.md** | All | @AccessibilityFocusState, VoiceOver + focus, Full Keyboard Access, Switch Control, Reduce Motion |\n| **debugging.md** | All | UIFocusDebugger, _whyIsThisViewNotFocusable, launch arguments, macOS first responder debugging |\n\n## Anti-Patterns It Catches\n\n### Blocking (must fix before ship)\n\n1. **`.disabled()` removes views from the focus chain on tvOS** — gate the action inside the closure instead (`.allowsHitTesting(false)` is unreliable)\n2. **Missing `.focusSection()` on horizontal ScrollViews** — causes cross-row focus jumping in vertical layouts\n3. **Adding `.focusable()` to Buttons or NavigationLinks** — creates double-focus artifacts\n4. **Mixing SwiftUI and UIKit focus in the same hierarchy** — focus environment conflicts\n5. **Calling `reloadData()` during animations** — focus resets to the top of the screen\n6. **Using `frame.width` in focus transform calculations** — dimensions change when focused\n7. **`setNeedsFocusUpdate()` called from wrong environment** — silently fails with no error\n8. **Setting `isUserInteractionEnabled = false` on headers/labels** — removes them and their children from focus chain\n9. **`remembersLastFocusedIndexPath` + offscreen `reloadData()`** — remembered index may no longer exist\n10. **Using `UIView.animate` for CALayer properties** — animations won't work, use `CABasicAnimation`\n\n### Warning (should fix)\n\n11. **Non-optional `@FocusState` with `focused(_:equals:)`** — can't represent \"nothing focused\" state\n12. **Missing `prepareForReuse()` cleanup for focus state** — stale focus styling on reused cells\n13. **`prefersDefaultFocus` inside ScrollView** — may not work as expected, use `defaultFocus` instead\n14. **LazyVStack/LazyVGrid performance on Apple TV HD** — A8 chip can't handle lazy layout recalculation during fast scrolling\n\n### tvOS production patterns\n\n15. **`LazyVStack` deallocates offscreen rows** — rapid upward swipe causes focus to jump to tab bar, skipping content\n16. **Missing `.focusSection()` on vertical ScrollView** — focus escapes upward to tab bar/nav bar\n17. **Allocating objects in `didUpdateFocus`/`shouldUpdateFocus`** — per-frame garbage causes micro-stutters\n\n### macOS-specific\n\n18. **Not overriding `acceptsFirstResponder` on custom NSView** — view is invisible to Tab navigation\n19. **Incomplete key view loop** — Tab stops working after reaching the last view\n20. **Calling `becomeFirstResponder()` directly** — bypasses resign/become handshake, use `window.makeFirstResponder`\n21. **NSPanel stealing focus** — inspector panels take focus from document window, use `becomesKeyOnlyIfNeeded`\n22. **Not restoring focus after sheet/alert** — focus lost to window instead of returning to original view\n23. **`.focusable()` on NSViewRepresentable** — creates double focus layer conflicting with AppKit\n24. **Menu items not checking for nil focusedValue** — crashes when no window is key\n\n## FAQ\n\n<details>\n<summary><strong>How do I set initial focus on a specific view in tvOS?</strong></summary>\n\nIn SwiftUI, use `defaultFocus(_:_:)` or `prefersDefaultFocus`. In UIKit, override `preferredFocusEnvironments` on the parent view controller. See [swiftui-focus.md](references/swiftui-focus.md) and [uikit-focus.md](references/uikit-focus.md).\n</details>\n\n<details>\n<summary><strong>Focus resets after reloadData — how do I keep focus position?</strong></summary>\n\nUse `remembersLastFocusedIndexPath` or the safe reload pattern that locks focus before reloading. See [focus-restoration.md](references/focus-restoration.md).\n</details>\n\n<details>\n<summary><strong>Focus jumps to the wrong row when I swipe right</strong></summary>\n\nThe focus engine is geometric, not hierarchical. Add `.focusSection()` to horizontal ScrollViews to keep focus within rows. See [anti-patterns.md](references/anti-patterns.md) (pattern #2).\n</details>\n\n<details>\n<summary><strong>How do I programmatically move focus?</strong></summary>\n\nYou cannot directly set focus. Override `preferredFocusEnvironments` to return the target, then call `setNeedsFocusUpdate()` + `updateFocusIfNeeded()` on the correct focus environment. See [uikit-focus.md](references/uikit-focus.md).\n</details>\n\n<details>\n<summary><strong>UIFocusGuide not working</strong></summary>\n\nCommon causes: guide not added to the view hierarchy, `preferredFocusEnvironments` not set on the guide, or incorrect sizing/positioning. Focus guides bridge empty space between focusable views. See [uikit-focus.md](references/uikit-focus.md).\n</details>\n\n<details>\n<summary><strong>What does focusSection() actually do?</strong></summary>\n\nIt creates a focus group that the engine treats as a contiguous region, preventing focus from skipping over the section to items in other rows. Essential for horizontal ScrollViews in vertical layouts. See [swiftui-focus.md](references/swiftui-focus.md).\n</details>\n\n<details>\n<summary><strong>How do I debug focus issues on tvOS?</strong></summary>\n\nUse `UIFocusDebugger.checkFocusability(for:)` in the debugger, `_whyIsThisViewNotFocusable` on any UIView, and the `UIFocusLoggingEnabled` launch argument. See [debugging.md](references/debugging.md).\n</details>\n\n<details>\n<summary><strong>Why does .disabled() break focus on Apple TV?</strong></summary>\n\nOn tvOS, `.disabled()` removes the view entirely from the focus chain. `.allowsHitTesting(false)` is commonly recommended but is unreliable — it may map to `isUserInteractionEnabled = false` under the hood. The most reliable approach is to gate the action inside the button closure instead of disabling the view. For lists/sidebars, use the dual `@FocusState` + `.disabled()` gating pattern (anti-pattern #25). See [anti-patterns.md](references/anti-patterns.md) (patterns #1 and #25).\n</details>\n\n<details>\n<summary><strong>@FocusState not dismissing keyboard on iOS</strong></summary>\n\nSetting `@FocusState` to `nil` should dismiss the keyboard, but it can fail inside sheets or NavigationStack. See [ios-focus.md](references/ios-focus.md) for workarounds.\n</details>\n\n<details>\n<summary><strong>How do I move focus between TextFields with the keyboard next button?</strong></summary>\n\nUse `@FocusState` with an enum representing each field, then set the next case in `onSubmit`. See [ios-focus.md](references/ios-focus.md).\n</details>\n\n<details>\n<summary><strong>How does keyboard focus navigation work on iPad?</strong></summary>\n\niOS 15+ added UIFocusSystem support for hardware keyboards. Opt in with `UIFocusHaloEffect`, `focusGroupIdentifier`, and `focusEffect`. See [ios-focus.md](references/ios-focus.md).\n</details>\n\n<details>\n<summary><strong>How does focus work across multiple windows on iPad with Stage Manager?</strong></summary>\n\nEach window scene has its own focus state. Use `focusedSceneValue` to propagate focus information across scenes. See [ios-focus.md](references/ios-focus.md) (Stage Manager section).\n</details>\n\n<details>\n<summary><strong>How do I use focusedSceneValue for multi-window iPad apps?</strong></summary>\n\nDefine a `FocusedValueKey`, set values with `.focusedSceneValue()`, and read them with `@FocusedValue` in your menu bar or toolbar commands. See [ios-focus.md](references/ios-focus.md).\n</details>\n\n<details>\n<summary><strong>Digital Crown rotation stops working after reordering view modifiers</strong></summary>\n\nThe `.digitalCrownRotation()` modifier is order-sensitive. It must be applied in the correct position relative to other modifiers. See [watchos-focus.md](references/watchos-focus.md).\n</details>\n\n<details>\n<summary><strong>How do I handle nested scrolling conflicts with Digital Crown?</strong></summary>\n\nWhen a ScrollView contains a Digital Crown control, the Crown drives both scrolling and the control. Use explicit `@FocusState` to determine which element owns the Crown. See [watchos-focus.md](references/watchos-focus.md).\n</details>\n\n<details>\n<summary><strong>What's the difference between hover and focus on visionOS?</strong></summary>\n\nvisionOS uses eye tracking for hover (`.hoverEffect()`) and indirect input for focus. They are separate systems. Gaze creates hover highlights, but tap gestures are needed for activation. See [visionos-focus.md](references/visionos-focus.md).\n</details>\n\n<details>\n<summary><strong>How do I customize hover effects in visionOS?</strong></summary>\n\nUse `HoverEffectComponent` on RealityKit entities with styles: default, spotlight, shader, or highlight. For SwiftUI views, use `.hoverEffect(.highlight)` or `.hoverEffect(.lift)`. See [realitykit-focus.md](references/realitykit-focus.md).\n</details>\n\n<details>\n<summary><strong>How does focus work in Mac Catalyst apps?</strong></summary>\n\nMac Catalyst inherits iPad's `UIFocusSystem` — `UIFocusHaloEffect` renders as a macOS focus ring, and `focusGroupIdentifier` maps to Tab navigation groups. If your iPad app doesn't support keyboard focus, neither will the Catalyst version. See [macos-focus.md](references/macos-focus.md) (Mac Catalyst section).\n</details>\n\n<details>\n<summary><strong>How do I handle keyboard focus in a macOS SwiftUI app?</strong></summary>\n\nUse `@FocusState` (same as iOS) and `.focusable()` for custom views. macOS focus is always active — no hardware keyboard requirement. For menu bar integration, use `focusedValue` / `focusedSceneValue`. See [macos-focus.md](references/macos-focus.md).\n</details>\n\n<details>\n<summary><strong>Focus works in simulator but not on device (or vice versa)</strong></summary>\n\nThe focus engine behaves differently between Xcode Simulator and physical hardware, especially for tvOS remote gestures and visionOS eye tracking. Always test focus on real devices. See [debugging.md](references/debugging.md).\n</details>\n\n## Sources\n\nBuilt from:\n- Apple Developer Documentation (UIFocusEnvironment, UIFocusGuide, FocusState, focusSection, HoverEffect)\n- WWDC17: Focus Interaction in tvOS 11\n- WWDC21: Direct and reflect focus in SwiftUI + Focus on iPad keyboard navigation\n- WWDC23: The SwiftUI cookbook for focus\n- WWDC24: Create custom hover effects in visionOS\n- WWDC25: Design hover interactions for visionOS\n- Production tvOS apps with complex focus requirements\n- Community guides (Airbnb, Showmax, Fatbobman, Big Nerd Ranch)\n\n## Complementary Skills\n\nSwift FocusEngine Pro pairs well with these skills:\n\n- [SwiftUI Pro](https://github.com/twostraws/SwiftUI-Agent-Skill) by Paul Hudson — SwiftUI best practices and patterns\n- [Swift Concurrency Pro](https://github.com/twostraws/Swift-Concurrency-Agent-Skill) by Paul Hudson — async/await, actors, Sendable\n- [Swift Concurrency](https://github.com/AvdLee/Swift-Concurrency-Agent-Skill) by Antoine van der Lee — Swift 6 migration, data race prevention\n- [Xcode Build Optimization](https://github.com/AvdLee/Xcode-Build-Optimization-Agent-Skill) by Antoine van der Lee — build benchmarking and optimization\n\nSee the [Swift Agent Skills](https://github.com/twostraws/Swift-Agent-Skills) directory for more.\n\n## Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md) for release history.\n\n## Contributing\n\nContributions are welcome! Focus on:\n\n- **Edge cases** — non-obvious focus behaviors that catch developers off guard\n- **New platform APIs** — additions from the latest OS releases (iOS/tvOS/macOS/visionOS/watchOS 26 and newer)\n- **Real-world patterns** — battle-tested solutions from production apps\n- **Anti-patterns** — mistakes LLMs commonly generate\n\nKeep reference files focused and under 300 lines each. Don't repeat things LLMs already know — focus on what they get wrong. All contributions must be MIT licensed.\n\nPlease read the [Code of Conduct](CODE_OF_CONDUCT.md) before contributing.\n\n## License\n\nSwift FocusEngine Pro was created by [Michael Haviv](https://github.com/mhaviv) and is licensed under the [MIT License](LICENSE).\n",
  "bytes": 21159,
  "sha": "eadda9b5f44683c352c2315f39d5e358cb28ce44bab022b3e2846a9aeaf8948e",
  "repo_slug": "mhaviv/swift-focusengine-agent-skill",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/plg_mhaviv_swift_focusengine_agent_skill_swi_9032160b/readme"
}