swiftship/internal/skills/data/always-visionos/components/SKILL.md
visionOS UI components: glass backgrounds, hover effects, ornaments, 3D content views. Use when working on visionOS component patterns, spatial UI, or Vision Pro interactions. Triggers: Button, glass, hover, ornament, RealityView, Model3D, component.
npx skillsauth add abdullah4ai/apple-developer-toolkit componentsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
visionOS windows use system glass material by default. The glass auto-adapts brightness based on the physical environment. Custom opaque backgrounds destroy this adaptive behavior.
BANNED on visionOS:
.background(AppTheme.Colors.background)).foregroundStyle(AppTheme.Colors.primary) on body text) — use white/system text on glass.glassBackgroundEffect() on list row backgrounds — creates glass-on-glass, text becomes invisible.scrollContentBackground(.hidden) on Lists — removes contrast needed for text visibilityREQUIRED on visionOS:
.glassBackgroundEffect() for custom container backgrounds (sidebars, cards, panels).primary, .secondary, .tertiary)// CORRECT — glass container, system text
VStack {
Text("Settings")
.font(AppTheme.Fonts.title)
.foregroundStyle(.primary) // system vibrancy — auto-adapts
Text("Configure your preferences")
.font(AppTheme.Fonts.body)
.foregroundStyle(.secondary) // dimmer vibrancy level
}
.padding(AppTheme.Spacing.lg)
.glassBackgroundEffect()
// BANNED — opaque colored background
VStack { content }
.background(AppTheme.Colors.background) // NO — destroys glass
.foregroundStyle(AppTheme.Colors.primary) // NO — colored body text
AppTheme colors are ONLY for:
.borderedProminent button tint (accent color)AppTheme colors must NEVER be used for:
.glassBackgroundEffect()).foregroundStyle(.primary) / .secondary / .tertiary)ALL interactive elements MUST have .hoverEffect() for eye tracking feedback:
Button("Play") {
play()
}
.hoverEffect()
// Custom hover effect
Button { } label: {
Image(systemName: "star")
.font(AppTheme.Fonts.title)
}
.hoverEffect(.highlight)
// Bordered prominent (primary action — accent color tint is appropriate here)
Button("Start", systemImage: "play.fill") {
start()
}
.buttonStyle(.borderedProminent)
.buttonBorderShape(.capsule)
.hoverEffect()
// Bordered (secondary action)
Button("Settings", systemImage: "gear") {
openSettings()
}
.buttonStyle(.bordered)
.buttonBorderShape(.roundedRectangle)
.hoverEffect()
BUTTON HIERARCHY:
| Level | Style | Use Case |
|-------|-------|----------|
| Primary action | .borderedProminent | Start, Play, Confirm |
| Secondary | .bordered | Settings, More Info |
| Tertiary | .borderless | Dismiss, Cancel |
Ornaments attach supplementary controls to windows:
.ornament(attachmentAnchor: .scene(.bottom)) {
HStack(spacing: 20) {
Button("Previous", systemImage: "backward.fill") {
previous()
}
Button("Play", systemImage: "play.fill") {
play()
}
Button("Next", systemImage: "forward.fill") {
next()
}
}
.padding()
.glassBackgroundEffect()
}
For interactive 3D content:
import RealityKit
RealityView { content in
if let entity = try? await Entity(named: "Scene", in: realityKitContentBundle) {
content.add(entity)
}
}
For simple 3D model display (no interaction):
import RealityKit
Model3D(named: "Globe") { model in
model
.resizable()
.scaledToFit()
} placeholder: {
ProgressView()
}
visionOS List views have built-in glass-compatible styling. Do NOT add custom glass backgrounds to list rows — this creates glass-on-glass rendering where text becomes invisible.
// CORRECT — let the system handle list row backgrounds
List {
Section("General") {
NavigationLink("Profile") { ProfileView() }
Toggle("Notifications", isOn: $notifications)
}
}
.listStyle(.insetGrouped)
// BANNED — glass on list rows causes invisible text
List {
ForEach(items) { item in
ItemRow(item: item)
.listRowBackground( // NO
RoundedRectangle(cornerRadius: 12)
.fill(.clear)
.glassBackgroundEffect() // glass-on-glass = invisible text
)
}
}
.scrollContentBackground(.hidden) // NO — removes default list contrast
Key rules for Lists on visionOS:
.listStyle(.insetGrouped) — it provides proper visionOS styling.scrollContentBackground(.hidden) — it removes the contrast needed for text visibility.glassBackgroundEffect() to .listRowBackground() — glass-on-glass makes text invisible.listRowBackground() with custom glass shapes — the system handles row backgroundsContentUnavailableView(
"No Results",
systemImage: "magnifyingglass",
description: Text("Try a different search term")
)
UIScreen.main.bounds — use GeometryReader or window sizing.glassBackgroundEffect() for custom container backgrounds (sidebars, cards, panels) — but NEVER on list rows.scrollContentBackground(.hidden) or .listRowBackground() with glass — creates invisible text.listStyle(.insetGrouped) for Lists — system handles row styling.hoverEffect() for eye tracking.primary, .secondary, .tertiary) for text — not AppTheme color tokens.buttonBorderShape() for spatial-appropriate button shapes.borderedProminent per visible areatesting
Use for 3D games: racing, 3D sports, board games, marble maze, tower defense, bowling. SceneKit + SceneView architecture, 3D scene hierarchy, physics, game loop, primitives, materials, cameras, particles, audio.
documentation
Game UI patterns: SwiftUI HUD overlays on SpriteKit, menus (main/pause/game-over), virtual joystick/d-pad, score displays, health bars, tutorial onboarding.
tools
Download free game sprites/textures/3D models and generate procedural assets. Covers nw_download_asset tool, texture factories, sprite atlas organization, 3D model loading, and programmatic asset creation.
testing
Use for 2D games: arcade, puzzle, sports, ping pong, platformer, shooter, 2D racing. SpriteKit + SpriteView architecture, scene hierarchy, physics, game loop, audio, particles, game feel.