NYC
skills/charleswiltgen/axiom/axiom-scenekit-ref

axiom-scenekit-ref

SKILL.md

SceneKit API Reference & Migration Mapping

Complete API reference for SceneKit with RealityKit equivalents for every major concept.

When to Use This Reference

Use this reference when:

  • Looking up SceneKit → RealityKit API equivalents during migration
  • Checking specific SceneKit class properties or methods
  • Planning which SceneKit features have direct RealityKit counterparts
  • Understanding architectural differences between scene graph and ECS

Part 1: SceneKit → RealityKit Concept Mapping

Core Architecture

SceneKit RealityKit Notes
SCNScene RealityViewContent / Entity (root) RealityKit scenes are entity hierarchies
SCNNode Entity Lightweight container in both
SCNView RealityView (SwiftUI) ARView for UIKit on iOS
SceneView (SwiftUI) RealityView SceneView deprecated iOS 26
SCNRenderer RealityRenderer Low-level Metal rendering
Node properties Components ECS separates data from hierarchy
SCNSceneRendererDelegate System / SceneEvents.Update Frame-level updates
.scn files .usdz / .usda files Convert with xcrun scntool

Geometry & Rendering

SceneKit RealityKit Notes
SCNGeometry MeshResource RealityKit generates from code or loads USD
SCNBox, SCNSphere, etc. MeshResource.generateBox(), .generateSphere() Similar built-in shapes
SCNMaterial SimpleMaterial, PhysicallyBasedMaterial PBR-first in RealityKit
SCNMaterial.lightingModel = .physicallyBased PhysicallyBasedMaterial Default in RealityKit
SCNMaterial.diffuse PhysicallyBasedMaterial.baseColor Different property name
SCNMaterial.metalness PhysicallyBasedMaterial.metallic Different property name
SCNMaterial.roughness PhysicallyBasedMaterial.roughness Same concept
SCNMaterial.normal PhysicallyBasedMaterial.normal Same concept
Shader modifiers ShaderGraphMaterial / CustomMaterial No direct port — must rewrite
SCNProgram (custom shaders) CustomMaterial with Metal functions Different API surface
SCNGeometrySource MeshResource.Contents Low-level mesh data

Transforms & Hierarchy

SceneKit RealityKit Notes
node.position entity.position Both SCNVector3 / SIMD3
node.eulerAngles entity.orientation (quaternion) RealityKit prefers quaternions
node.scale entity.scale Both SIMD3
node.transform entity.transform 4×4 matrix
node.worldTransform entity.transform(relativeTo: nil) World-space transform
node.addChildNode(_:) entity.addChild(_:) Same hierarchy concept
node.removeFromParentNode() entity.removeFromParent() Same concept
node.childNodes entity.children Children collection
node.parent entity.parent Parent reference
node.childNode(withName:recursively:) entity.findEntity(named:) Named lookup

Lighting

SceneKit RealityKit Notes
SCNLight (.omni) PointLightComponent Point light
SCNLight (.directional) DirectionalLightComponent Sun/directional light
SCNLight (.spot) SpotLightComponent Cone light
SCNLight (.area) No direct equivalent Use multiple point lights
SCNLight (.ambient) EnvironmentResource (IBL) Image-based lighting preferred
SCNLight (.probe) EnvironmentResource Environment probes
SCNLight (.IES) No direct equivalent Use light intensity profiles

Camera

SceneKit RealityKit Notes
SCNCamera PerspectiveCamera entity Entity with camera component
camera.fieldOfView PerspectiveCameraComponent.fieldOfViewInDegrees Same concept
camera.zNear / camera.zFar PerspectiveCameraComponent.near / .far Clipping planes
camera.wantsDepthOfField Post-processing effects Different mechanism
camera.motionBlurIntensity Post-processing effects Different mechanism
allowsCameraControl Custom gesture handling No built-in orbit camera

Physics

SceneKit RealityKit Notes
SCNPhysicsBody PhysicsBodyComponent Component-based
.dynamic .dynamic Same mode
.static .static Same mode
.kinematic .kinematic Same mode
SCNPhysicsShape CollisionComponent / ShapeResource Separate from body in RealityKit
categoryBitMask CollisionGroup Named groups vs raw bitmasks
collisionBitMask CollisionFilter Filter-based
contactTestBitMask CollisionEvents.Began subscription Event-based contacts
SCNPhysicsContactDelegate scene.subscribe(to: CollisionEvents.Began.self) Combine-style events
SCNPhysicsField PhysicsBodyComponent forces Apply forces directly
SCNPhysicsJoint PhysicsJoint Similar joint types

Animation

SceneKit RealityKit Notes
SCNAction entity.move(to:relativeTo:duration:) Transform animation
SCNAction.sequence Animation chaining Less declarative in RealityKit
SCNAction.group Parallel animations Apply to different entities
SCNAction.repeatForever AnimationPlaybackController repeat Different API
SCNTransaction (implicit) No direct equivalent Explicit animations only
CAAnimation bridge entity.playAnimation() Load from USD
SCNAnimationPlayer AnimationPlaybackController Playback control
Morph targets Blend shapes in USD Load via USD files

Interaction

SceneKit RealityKit Notes
hitTest(_:options:) RealityViewContent.entities(at:) Different API
Gesture recognizers on SCNView ManipulationComponent Built-in drag/rotate/scale
allowsCameraControl Custom implementation No built-in orbit

AR Integration

SceneKit RealityKit Notes
ARSCNView RealityView + AnchorEntity Legacy → modern
ARSCNViewDelegate AnchorEntity auto-tracking Event-driven
renderer(_:didAdd:for:) AnchorEntity(.plane) Declarative anchoring
ARWorldTrackingConfiguration SpatialTrackingSession iOS 18+

Part 2: Scene Graph API

SCNScene

// Loading
let scene = SCNScene(named: "scene.usdz")!
let scene = try SCNScene(url: url, options: [
    .checkConsistency: true,
    .convertToYUp: true
])

// Properties
scene.rootNode                    // Root of node hierarchy
scene.background.contents        // Skybox (UIImage, UIColor, MDLSkyCubeTexture)
scene.lightingEnvironment.contents // IBL environment map
scene.fogStartDistance            // Fog near
scene.fogEndDistance              // Fog far
scene.fogColor                   // Fog color
scene.isPaused                   // Pause simulation

SCNNode

// Creation
let node = SCNNode()
let node = SCNNode(geometry: SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0))

// Transform
node.position = SCNVector3(x, y, z)
node.eulerAngles = SCNVector3(pitch, yaw, roll)
node.scale = SCNVector3(1, 1, 1)
node.simdPosition = SIMD3<Float>(x, y, z)  // SIMD variants available
node.pivot = SCNMatrix4MakeTranslation(0, -0.5, 0) // Offset pivot point

// Visibility
node.isHidden = false
node.opacity = 1.0
node.castsShadow = true
node.renderingOrder = 0   // Lower = rendered first

// Hierarchy
node.addChildNode(child)
node.removeFromParentNode()
node.childNodes
node.childNode(withName: "name", recursively: true)
node.enumerateChildNodes { child, stop in }

Part 3: Materials

Lighting Models

Model Description Use Case
.physicallyBased PBR metallic-roughness Realistic rendering (recommended)
.blinn Blinn-Phong specular Simple shiny surfaces
.phong Phong specular Classic specular highlight
.lambert Diffuse only, no specular Matte surfaces
.constant Unlit, flat color UI elements, debug visualization
.shadowOnly Invisible, receives shadows AR ground plane

Material Properties

let mat = SCNMaterial()
mat.lightingModel = .physicallyBased

// Textures or scalar values
mat.diffuse.contents = UIImage(named: "albedo")    // Base color
mat.metalness.contents = 0.0                        // 0 = dielectric, 1 = metal
mat.roughness.contents = 0.5                        // 0 = mirror, 1 = rough
mat.normal.contents = UIImage(named: "normal")      // Normal map
mat.ambientOcclusion.contents = UIImage(named: "ao") // AO map
mat.emission.contents = UIColor.blue                // Glow
mat.displacement.contents = UIImage(named: "height") // Height map

// Options
mat.isDoubleSided = false        // Render both sides
mat.writesToDepthBuffer = true
mat.readsFromDepthBuffer = true
mat.blendMode = .alpha           // .add, .subtract, .multiply, .screen
mat.transparencyMode = .aOne     // .rgbZero for pre-multiplied alpha

Part 4: Physics

Body Types and Properties

// Dynamic body with custom shape
let shape = SCNPhysicsShape(geometry: SCNSphere(radius: 0.5), options: nil)
let body = SCNPhysicsBody(type: .dynamic, shape: shape)
body.mass = 1.0
body.friction = 0.5
body.restitution = 0.3       // Bounciness
body.damping = 0.1            // Linear damping
body.angularDamping = 0.1     // Angular damping
body.isAffectedByGravity = true
body.allowsResting = true     // Sleep optimization
node.physicsBody = body

// Compound shapes
let compound = SCNPhysicsShape(shapes: [shape1, shape2],
    transforms: [transform1, transform2])

// Concave (static only)
let concave = SCNPhysicsShape(geometry: mesh, options: [
    .type: SCNPhysicsShape.ShapeType.concavePolyhedron
])

Joint Types

Joint Description
SCNPhysicsHingeJoint Single-axis rotation (door)
SCNPhysicsBallSocketJoint Free rotation around point (pendulum)
SCNPhysicsSliderJoint Linear movement along axis (drawer)
SCNPhysicsConeTwistJoint Limited rotation (ragdoll limb)

Part 5: Animation API

SCNAction Catalog

Category Actions
Movement move(by:duration:), move(to:duration:)
Rotation rotate(by:around:duration:), rotateTo(x:y:z:duration:)
Scale scale(by:duration:), scale(to:duration:)
Fade fadeIn(duration:), fadeOut(duration:), fadeOpacity(to:duration:)
Visibility hide(), unhide()
Audio playAudio(source:waitForCompletion:)
Custom run { node in }, customAction(duration:action:)
Composition sequence([]), group([]), repeat(_:count:), repeatForever(_:)
Control wait(duration:), removeFromParentNode()

Timing Functions

action.timingMode = .linear        // Default
action.timingMode = .easeIn        // Slow start
action.timingMode = .easeOut       // Slow end
action.timingMode = .easeInEaseOut // Slow start and end
action.timingFunction = { t in     // Custom curve
    return t * t  // Quadratic ease-in
}

Part 6: Constraints

Constraint Purpose
SCNLookAtConstraint Node always faces target
SCNBillboardConstraint Node always faces camera
SCNDistanceConstraint Maintains min/max distance
SCNReplicatorConstraint Copies transform of target
SCNAccelerationConstraint Smooths transform changes
SCNSliderConstraint Locks to axis
SCNIKConstraint Inverse kinematics chain
let lookAt = SCNLookAtConstraint(target: targetNode)
lookAt.isGimbalLockEnabled = true  // Prevent roll
lookAt.influenceFactor = 0.8       // Partial constraint
node.constraints = [lookAt]

In RealityKit: No direct constraint system. Implement with System update logic or entity.look(at:from:relativeTo:).


Part 7: Scene Configuration

SCNView Configuration

Property Default Description
antialiasingMode .multisampling4X MSAA level
preferredFramesPerSecond 60 Target frame rate
allowsCameraControl false Built-in orbit/pan/zoom
autoenablesDefaultLighting false Add default light if none
showsStatistics false FPS/node/draw count overlay
isTemporalAntialiasingEnabled false TAA smoothing
isJitteringEnabled false Temporal jitter for TAA
debugOptions [] .showPhysicsShapes, .showBoundingBoxes, .renderAsWireframe

Resources

WWDC: 2014-609, 2014-610, 2017-604, 2019-612

Docs: /scenekit, /scenekit/scnscene, /scenekit/scnnode, /scenekit/scnmaterial, /scenekit/scnphysicsbody, /scenekit/scnaction

Skills: axiom-scenekit, axiom-realitykit, axiom-realitykit-ref

Weekly Installs
28
First Seen
Feb 5, 2026
Installed on
opencode26
claude-code25
gemini-cli23
github-copilot21
codex21
kimi-cli20