Reality Composer Pro 3 introduces a node-based visual scripting system called Script Graph that lets developers and designers build interactive RealityKit games and experiences without writing code. Logic is expressed as event-driven graphs with reusable Prototyped Subgraphs, Custom Events, and live on-device preview via visionOS.
⢠Enables rapid prototyping of spatial interactions (drag, pinch, physics, animations) in a visual canvas ā iterate without rebuilding Xcode projects
⢠Prototyped Subgraphs and Custom Node Libraries allow reusable logic modules that keep complex scenes maintainable
⢠Live Preview streams the running scene directly to Vision Pro hardware so feel and timing can be validated instantly in the real environment
Shows how to load a Reality Composer Pro scene that contains a Script-Graph-driven draggable entity, attach it to a RealityView, and override a public Script Graph variable (dragSpeed) at runtime from Swift ā the bridge between no-code Script Graphs and Swift app code.
import SwiftUI
import RealityKit
// MARK: - Model
// The Script Graph lives inside SquirrelGame.reality (built in Reality Composer Pro 3).
// The Nut entity has a ScriptingComponent whose public variable
// "dragSpeed" (Float) controls drag responsiveness.
@MainActor
final class SquirrelGameModel: ObservableObject {
var rootEntity: Entity?
func loadScene() async throws {
// Load the .reality bundle produced by Reality Composer Pro 3
let scene = try await Entity(named: "SquirrelGame", in: Bundle.main)
rootEntity = scene
// Override the public Script Graph variable on the Nut entity
applyDragSpeed(1.15, entityNamed: "Nut")
}
/// Write a value into a Script Graph public variable via ScriptingComponent.
func applyDragSpeed(_ speed: Float, entityNamed name: String) {
guard let nut = rootEntity?.findEntity(named: name) else { return }
// ScriptingComponent stores overrides for Script Graph public variables.
if var scripting = nut.components[ScriptingComponent.self] {
scripting.variables["dragSpeed"] = .float(speed)
nut.components[ScriptingComponent.self] = scripting
}
}
}
// MARK: - View
struct SquirrelGameView: View {
@StateObject private var model = SquirrelGameModel()
@State private var dragSpeed: Float = 1.15
var body: some View {
VStack {
RealityView { content in
do {
try await model.loadScene()
if let root = model.rootEntity {
content.add(root)
}
} catch {
print("Failed to load SquirrelGame scene: \(error)")
}
} update: { _ in
// Push the current slider value into the Script Graph variable
model.applyDragSpeed(dragSpeed, entityNamed: "Nut")
}
.frame(width: 600, height: 400)
// Runtime control of a Script Graph public variable from Swift UI
VStack(alignment: .leading) {
Text("Drag Speed: \(dragSpeed, specifier: "%.2f")").bold()
Slider(value: $dragSpeed, in: 0.5...2.5, step: 0.05)
.padding(.horizontal)
}
.padding()
}
}
}
#Preview {
SquirrelGameView()
}Live Preview on Device is listed as 'available later this year' in the WWDC session ā it may not be present in the initial visionOS 2 / Xcode 17 seed. Script Graphs are a Reality Composer Pro authoring tool, not a runtime Swift API; the Swift side is limited to loading and configuring the resulting .usda/.reality bundles. Public Script Graph variables become Scripting Component overrides per-entity, not per-asset.
Full Live Preview on Device feature requires Apple Vision Pro; Script Graph authoring runs on macOS with Reality Composer Pro 3. Physics and custom events require visionOS-capable hardware.
More iOS 27 APIs land every week.
Get notified when new capabilities are published ā no noise, just signal.