/scenekit
Maintain and extend existing SceneKit 3D scenes and visualizations. Use when working with SCNView, SCNScene, SCNNode scene graphs, SceneKit geometry/materials/lights/cameras, SCNAction animation, SCNPhysicsBody physics, SCNParticleSystem effects, .scn/.dae/.abc SceneKit assets,
$ npx -y skills add dpearson2699/swift-ios-skills --skill scenekit --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/scenekit
Context preview
The summary Claude sees to decide when to auto-load this skill.
Maintain and extend existing SceneKit 3D scenes and visualizations. Use when working with SCNView, SCNScene, SCNNode scene graphs, SceneKit geometry/materials/lights/cameras, SCNAction animation, SCNPhysicsBody physics, SCNParticleSystem effects, .scn/.dae/.abc SceneKit assets,
SKILL.md
scenekit.SKILL.mdname: scenekit
description: "Maintain and extend existing SceneKit 3D scenes and visualizations. Use when working with SCNView, SCNScene, SCNNode scene graphs, SceneKit geometry/materials/lights/cameras, SCNAction animation, SCNPhysicsBody physics, SCNParticleSystem effects, .scn/.dae/.abc SceneKit assets, shader modifiers, or SwiftUI SceneView. SceneKit is soft-deprecated and in maintenance mode; route new apps, significant updates, USD/USDZ pipelines, and migration planning toward RealityKit."
SceneKit
Maintain existing SceneKit scenes only. Apple deprecated SceneKit at WWDC 2025 and limits it to maintenance; route new projects, major modernization, and USD/USDZ pipelines to RealityKit. Existing apps continue to work.
Contents
- [Scene Setup](#scene-setup)
- [Nodes and Geometry](#nodes-and-geometry)
- [Materials](#materials)
- [Lighting](#lighting)
- [Cameras](#cameras)
- [Animation](#animation)
- [Physics](#physics)
- [Particle Systems](#particle-systems)
- [Loading Models](#loading-models)
- [SwiftUI Integration](#swiftui-integration)
- [Common Mistakes](#common-mistakes)
- [Review Checklist](#review-checklist)
- [References](#references)
Scene Setup
SCNView in UIKit
import SceneKit
let sceneView = SCNView(frame: view.bounds)
sceneView.scene = SCNScene()
sceneView.allowsCameraControl = true
sceneView.autoenablesDefaultLighting = true
sceneView.backgroundColor = .black
view.addSubview(sceneView)
`allowsCameraControl` adds built-in orbit, pan, and zoom gestures. Typically disabled in production where custom camera control is needed.
Creating an SCNScene
let scene = SCNScene() // Empty
guard let scene = SCNScene(named: "art.scnassets/ship.scn") // .scn in .scnassets
else { fatalError("Missing scene asset") }
let url = Bundle.main.url(forResource: "ship", withExtension: "dae")!
let scene = try SCNScene(url: url, options: [.checkConsistency: true])Nodes and Geometry
Every scene has a `rootNode`. All content exists as descendant nodes. Nodes define position, orientation, and scale in their parent's coordinate system. SceneKit uses a right-handed coordinate system: +X right, +Y up, +Z toward the camera.
let parentNode = SCNNode()
scene.rootNode.addChildNode(parentNode)
let childNode = SCNNode()
childNode.position = SCNVector3(0, 1, 0) // 1 unit above parent
parentNode.addChildNode(childNode)
Transforms
node.position = SCNVector3(x: 0, y: 2, z: -5)
node.eulerAngles = SCNVector3(x: 0, y: .pi / 4, z: 0) // 45-degree Y rotation
node.scale = SCNVector3(2, 2, 2)
node.simdPosition = SIMD3<Float>(0, 2, -5) // Prefer simd for performance
Built-in Primitives
`SCNBox`, `SCNSphere`, `SCNCylinder`, `SCNCone`, `SCNTorus`, `SCNCapsule`, `SCNTube`, `SCNPlane`, `SCNFloor`, `SCNText`, `SCNShape` (extruded Bezier path).
let node = SCNNode(geometry: SCNSphere(radius: 0.5))
Finding Nodes
let maxNode = scene.rootNode.childNode(withName: "Max", recursively: true)
let enemies = scene.rootNode.childNodes { node, _ in
node.name?.hasPrefix("enemy") == true
}Materials
`SCNMaterial` defines surface appearance. Use `firstMaterial` for single-material geometries or the `materials` array for multi-material.
Color and Texture
let material = SCNMaterial()
material.diffuse.contents = UIColor.systemBlue // Solid color
material.diffuse.contents = UIImage(named: "brick") // Texture
material.normal.contents = UIImage(named: "brick_normal")
sphere.firstMaterial = material
Physically Based Rendering (PBR)
let pbr = SCNMaterial()
pbr.lightingModel = .physicallyBased
pbr.diffuse.contents = UIImage(named: "albedo")
pbr.metalness.contents = 0.8 // Scalar or texture
pbr.roughness.contents = 0.2 // Scalar or texture
pbr.normal.contents = UIImage(named: "normal")
pbr.ambientOcclusion.contents = UIImage(named: "ao")
Lighting Models
`.physicallyBased` (metalness/roughness), `.blinn` (default), `.phong`, `.lambert` (diffuse-only), `.constant` (unlit), `.shadowOnly`.
Each material property is an `SCNMaterialProperty` accepting `UIColor`, `UIImage`, `CGFloat` scalar, `SKTexture`, `CALayer`, or `AVPlayer`.
Transparency
material.transparency = 0.5
material.transparencyMode = .dualLayer
material.isDoubleSided = true
Lighting
Attach an `SCNLight` to a node. The light's direction follows the node's negative Z-axis.
Light Types
// Ambient: uniform, no direction
let ambient = SCNLight()
ambient.type = .ambient
ambient.color = UIColor(white: 0.3, alpha: 1)
// Directional: parallel rays (sunlight)
let directional = SCNLight()
directional.type = .directional
directional.castsShadow = true
// Omni: point light, all directions
let omni = SCNLight()
omni.type = .omni
omni.attenuationEndDistance = 20
// Spot: cone-shaped
let spot = SCNLight()
spot.type = .spot
spot.spotInnerAngle = 20
spot.spotOuterAngle = 60
Attach to a node:
let lightNode = SCNNode()
lightNode.light = directional
lightNode.eulerAngles = SCNVector3(-Float.pi / 3, 0, 0)
lightNode.position = SCNVector3(0, 10, 10)
scene.rootNode.addChildNode(lightNode)
Shadows
light.castsShadow = true
light.shadowMapSize = CGSize(width: 2048, height: 2048)
light.shadowSampleCount = 8
light.shadowRadius = 3.0
light.shadowColor = UIColor(white: 0, alpha: 0.5)
Category Bit Masks
light.categoryBitMask = 1 << 1 // Category 2
node.categoryBitMask = 1 << 1 // Only lit by category-2 lights
SceneKit renders a maximum of 8 lights per node. Use `attenuationEndDistance` on point/spot lights so SceneKit skips them for distant nodes.
Cameras
Attach an `SCNCamera` to a node to define a viewpoint.
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(0, 5, 15)
cameraNode.look(at: SCNVector3Zero)
scene.rootN
Read more
name: scenekit description: "Maintain and extend existing SceneKit 3D scenes and visualizations. Use when working with SCNView, SCNScene, SCNNode scene graphs, SceneKit geometry/materials/lights/cameras, SCNAction animation, SCNPhysicsBody physics, SCNParticleSystem effects, .scn/.dae/.abc SceneKit assets, shader modifiers, or SwiftUI SceneView. SceneKit is soft-deprecated and in maintenance mode; route new apps, significant updates, USD/USDZ pipelines, and migration planning toward RealityKit."
SceneKit
Maintain existing SceneKit scenes only. Apple deprecated SceneKit at WWDC 2025 and limits it to maintenance; route new projects, major modernization, and USD/USDZ pipelines to RealityKit. Existing apps continue to work.
Contents
- [Scene Setup](#scene-setup)
- [Nodes and Geometry](#nodes-and-geometry)
- [Materials](#materials)
- [Lighting](#lighting)
- [Cameras](#cameras)
- [Animation](#animation)
- [Physics](#physics)
- [Particle Systems](#particle-systems)
- [Loading Models](#loading-models)
- [SwiftUI Integration](#swiftui-integration)
- [Common Mistakes](#common-mistakes)
- [Review Checklist](#review-checklist)
- [References](#references)
Scene Setup
SCNView in UIKit
import SceneKit let sceneView = SCNView(frame: view.bounds) sceneView.scene = SCNScene() sceneView.allowsCameraControl = true sceneView.autoenablesDefaultLighting = true sceneView.backgroundColor = .black view.addSubview(sceneView)
`allowsCameraControl` adds built-in orbit, pan, and zoom gestures. Typically disabled in production where custom camera control is needed.
Creating an SCNScene
let scene = SCNScene() // Empty
guard let scene = SCNScene(named: "art.scnassets/ship.scn") // .scn in .scnassets
else { fatalError("Missing scene asset") }
let url = Bundle.main.url(forResource: "ship", withExtension: "dae")!
let scene = try SCNScene(url: url, options: [.checkConsistency: true])Nodes and Geometry
Every scene has a `rootNode`. All content exists as descendant nodes. Nodes define position, orientation, and scale in their parent's coordinate system. SceneKit uses a right-handed coordinate system: +X right, +Y up, +Z toward the camera.
let parentNode = SCNNode() scene.rootNode.addChildNode(parentNode) let childNode = SCNNode() childNode.position = SCNVector3(0, 1, 0) // 1 unit above parent parentNode.addChildNode(childNode)
Transforms
node.position = SCNVector3(x: 0, y: 2, z: -5) node.eulerAngles = SCNVector3(x: 0, y: .pi / 4, z: 0) // 45-degree Y rotation node.scale = SCNVector3(2, 2, 2) node.simdPosition = SIMD3<Float>(0, 2, -5) // Prefer simd for performance
Built-in Primitives
`SCNBox`, `SCNSphere`, `SCNCylinder`, `SCNCone`, `SCNTorus`, `SCNCapsule`, `SCNTube`, `SCNPlane`, `SCNFloor`, `SCNText`, `SCNShape` (extruded Bezier path).
let node = SCNNode(geometry: SCNSphere(radius: 0.5))
Finding Nodes
let maxNode = scene.rootNode.childNode(withName: "Max", recursively: true)
let enemies = scene.rootNode.childNodes { node, _ in
node.name?.hasPrefix("enemy") == true
}Materials
`SCNMaterial` defines surface appearance. Use `firstMaterial` for single-material geometries or the `materials` array for multi-material.
Color and Texture
let material = SCNMaterial() material.diffuse.contents = UIColor.systemBlue // Solid color material.diffuse.contents = UIImage(named: "brick") // Texture material.normal.contents = UIImage(named: "brick_normal") sphere.firstMaterial = material
Physically Based Rendering (PBR)
let pbr = SCNMaterial() pbr.lightingModel = .physicallyBased pbr.diffuse.contents = UIImage(named: "albedo") pbr.metalness.contents = 0.8 // Scalar or texture pbr.roughness.contents = 0.2 // Scalar or texture pbr.normal.contents = UIImage(named: "normal") pbr.ambientOcclusion.contents = UIImage(named: "ao")
Lighting Models
`.physicallyBased` (metalness/roughness), `.blinn` (default), `.phong`, `.lambert` (diffuse-only), `.constant` (unlit), `.shadowOnly`.
Each material property is an `SCNMaterialProperty` accepting `UIColor`, `UIImage`, `CGFloat` scalar, `SKTexture`, `CALayer`, or `AVPlayer`.
Transparency
material.transparency = 0.5 material.transparencyMode = .dualLayer material.isDoubleSided = true
Lighting
Attach an `SCNLight` to a node. The light's direction follows the node's negative Z-axis.
Light Types
// Ambient: uniform, no direction let ambient = SCNLight() ambient.type = .ambient ambient.color = UIColor(white: 0.3, alpha: 1) // Directional: parallel rays (sunlight) let directional = SCNLight() directional.type = .directional directional.castsShadow = true // Omni: point light, all directions let omni = SCNLight() omni.type = .omni omni.attenuationEndDistance = 20 // Spot: cone-shaped let spot = SCNLight() spot.type = .spot spot.spotInnerAngle = 20 spot.spotOuterAngle = 60
Attach to a node:
let lightNode = SCNNode() lightNode.light = directional lightNode.eulerAngles = SCNVector3(-Float.pi / 3, 0, 0) lightNode.position = SCNVector3(0, 10, 10) scene.rootNode.addChildNode(lightNode)
Shadows
light.castsShadow = true light.shadowMapSize = CGSize(width: 2048, height: 2048) light.shadowSampleCount = 8 light.shadowRadius = 3.0 light.shadowColor = UIColor(white: 0, alpha: 0.5)
Category Bit Masks
light.categoryBitMask = 1 << 1 // Category 2 node.categoryBitMask = 1 << 1 // Only lit by category-2 lights
SceneKit renders a maximum of 8 lights per node. Use `attenuationEndDistance` on point/spot lights so SceneKit skips them for distant nodes.
Cameras
Attach an `SCNCamera` to a node to define a viewpoint.
let cameraNode = SCNNode() cameraNode.camera = SCNCamera() cameraNode.position = SCNVector3(0, 5, 15) cameraNode.look(at: SCNVector3Zero) scene.rootN
86 agent skills optimized for iOS 26+ development with Swift 6.3 and modern Apple frameworks.
Repo: dpearson2699/swift-ios-skills
Other skills on swift-ios-skills.
- /accessorysetupkit
Discover and configure Bluetooth and Wi-Fi accessories using AccessorySetupKit. Use when presenting a privacy-preserving accessory picker, defining discovery descriptors for BLE or Wi-Fi devices, handling accessory session events, migrating from CoreBluetooth permission-based
Open skill - /activitykit
Implement, review, or improve Live Activities and Dynamic Island experiences in iOS apps using ActivityKit. Use when building real-time updating widgets for the Lock Screen and Dynamic Island — delivery tracking, sports scores, ride-sharing status, workout timers, media
Open skill - /adattributionkit
Measure ad effectiveness with privacy-preserving attribution using AdAttributionKit. Use when registering ad impressions, handling attribution postbacks, updating conversion values, implementing re-engagement attribution, configuring publisher or advertiser apps, or replacing
Open skill - /alarmkit
Implement AlarmKit alarms and countdown timers for iOS and iPadOS with Lock Screen, Dynamic Island, StandBy, and paired Apple Watch system UI. Covers AlarmManager scheduling, AlarmAttributes and AlarmPresentation, system Stop and AlarmButton secondary actions, authorization,
Open skill - /app-clips
Build iOS App Clips with invocation URLs, App Clip Codes, NFC, QR codes, Safari banners, Maps, Messages, target setup, App Store Connect experiences, size/capability constraints, NSUserActivity routing, SKOverlay promotion, App Group/keychain handoff, ephemeral notifications,
Open skill - /app-intents
Implement App Intents for Siri, Shortcuts, Spotlight, widgets, Control Center, and Apple Intelligence on iOS. Covers AppIntent actions, AppEntity and EntityQuery models, AppShortcutsProvider phrases, IndexedEntity Spotlight indexing, WidgetConfigurationIntent, SnippetIntent, and
Open skill

