Post

Replies

Boosts

Views

Activity

SpriteKit Continued Support
Hi! Question Could you provide some reassurance on the continued support for SpriteKit in the coming years? Trigger The deprecation of SceneKit at WWDC 2025 made me nervous. Context I use SpriteKit because: It can render any video AVFoundation can handle, which third-party engines don't do for several reasons including patents. This allows me to prototype UI that controls video with a game-like feel. It can render text and emojis through AttributedString, and text is hard. Thanks to a clear and well-exposed update loop, it can be integrated with libraries such as Core Image or Box2D. Example with Box2D here. It can draw dynamic shapes and paths with SKShapeNode, and visualize and respond to all the processing done at specific times during a frame. SKView is very handy to generate textures from nodes, and SKRenderer can be used to render a SpriteKit scene to video or sequence of images. This is possible thanks to multiple frameworks working together, including AVAssetWriter and IOSurface. Example of SpriteKit offline rendering here. Apple Alternatives When Apple announced the deprecation of SceneKit, I learned RealityKit in order to move my SpriteKit-based projects to RealityKit. RealityKit is interesting, but for 2D and 2.5D workflows I found several areas where SpriteKit remains significantly more practical: I had to lock physics to the XY plane, which could stress the engine and introduce unwanted overlap. Overlapping entities on a 2D plane was hard: ModelSortGroup did not provide the simple flexibility that SpriteKit zPosition provides. AFAIK there is no dynamic path/shape drawing in RealityKit. So drawing lines, visualizing physics and joints, rendering graph connections in the scene is not as easy as it is with SpriteKit shape nodes. SpriteKit is lighter and less power-hungry. Let me know if you need any more context or detail. Thank you!
1
2
170
1w
SpriteKit & Box2D
Hi, I integrated SpriteKit with Box2D version 3, and they work amazingly well together. I shared videos, code, and implementation notes on the project page: SpriteKit Box2D Context SpriteKit built-in physics engine is based on Box2D, likely from an older 2.x generation. This project uses Box2D 3.x directly. Box2D 3.0 was first released in 2024 as a major rewrite with a new C API. It brings improved collision handling, better performance, better stability for demanding simulations, and features that are not exposed through SpriteKit’s SKPhysicsWorld. Box2D 3 is also designed with determinism in mind. SpriteKit's physics implementation is nice to use, but it is not deterministic. See the Determinism section of my SKRenderer Demo for more information about determinism in SpriteKit. Swift & C Because Box2D 3 is written in C, this sample app also shows how to mix Swift and C in the same Xcode project. I wrote a tutorial on how to mix Swift with C in an Xcode project. I hope this is useful to anyone experimenting with SpriteKit physics or external C libraries. Let me know if you have questions or ideas.
0
0
188
1w
SpriteKit's Continued Support
Hi, Can Apple provide some reassurance on the continued support for SpriteKit in the coming years? At WWDC 2025, Apple deprecated SceneKit, which was alarming for a SpriteKit fan and user. I'm aware Apple doesn't comment on future plans. However, committing to a specific framework for larger projects is a significant investment in time (and money). Developers need to know whether to continue investing in proprietary technology that could be deprecated at any time. Some reassurance regarding SpriteKit's future would go a long way. I have moved my project from SpriteKit to RealityKit. RealityKit is certainly interesting, but I'd gladly switch back to SpriteKit. SpriteKit has things going for it that no other Apple framework provides: Live drawing of shapes, paths, text, video, and images at 120 FPS across all Apple devices. RealityKit offers no procedural drawing API equivalent to shape nodes. Particles and physics fields are very easy and fun to play with. The rigid body engine has a good feel. By comparison, RealityKit sleeps too aggressively, and doesn't have spring joints. SpriteKit is lightweight and runs well on older devices. In an ideal world, I'd also love to see SpriteKit improved: A deterministic physics engine Metal shader support Soft shadows for lights One can dream. Thank you!
1
4
581
May ’26
Xcode 26.4 Editor Tab Bar is low density
Hi, On a 1920 points wide monitor, running maximized, Xcode 26.4 can't show more than 10 editor tabs at a time. Under the same conditions, Xcode 26.2 adapts tab widths to file names and fits 12-14 tabs. That's 2-4 more files I can see and access at a glance, without extra interaction. How can I get that level of information density back in the Xcode 26.4 editor tab bar? Screenshots Xcode 26.4 (10 tabs) Xcode 26.2 (12 tabs) Xcode 26.2 (14 tabs)
1
0
106
Mar ’26
Xcode 26.3 - Revert to variable editor tab width
Hi, In Xcode 26.2, editor tabs adapt their width to the number of pinned tabs: In Xcode 26.3, editor tabs have a minimal width, after which the row of tabs becomes horizontally scrollable: Notice how less tabs are visible at a time on Xcode 26.3 (second image). Yet, there is enough horizontal space to accommodate more, as shown on Xcode 26.2 (first image). This is a UX regression. How can I revert back to 26.2 tab sizing behavior? Thank you.
1
0
119
Mar ’26
SpriteKit framerate drop on iOS 26.0
Hello, I have noticed a performance drop on SpriteKit-based projects running on iOS 26.0 (23A341). Below is a SpriteKit scene used to test framerate on different devices: import SpriteKit import SwiftUI class BareboneScene: SKScene { override func didMove(to view: SKView) { size = view.bounds.size anchorPoint = CGPoint(x: 0.5, y: 0.5) backgroundColor = .darkGray let roundedSquare = SKShapeNode(rectOf: CGSize(width: 150, height: 75), cornerRadius: 12) roundedSquare.fillColor = .systemRed roundedSquare.strokeColor = .black roundedSquare.lineWidth = 3 addChild(roundedSquare) let action = SKAction.rotate(byAngle: .pi, duration: 1) roundedSquare.run(.repeatForever(action)) } } struct BareboneSceneView: View { var body: some View { SpriteView( scene: BareboneScene(), debugOptions: [.showsFPS] ) .ignoresSafeArea() } } #Preview { BareboneSceneView() } The scene is very simple, yet framerate drops to ~40 fps as shown by the Metal HUD. Tested on: iPhone 13, iOS 26.0: framerate drops to 40 fps. Sometimes it runs at near 60fps. But if the screen is touched repeatedly, the framerate drops to 40-50 fps again. iPhone 11 Pro, iOS 26.0: ~40fps. iPad 9th Gen, iOS 18.6.2: 60fps, no issues. See screenshots attached. These numbers were observed by me and members of our beloved SpriteKit Discord server. Thank you for your attention.
15
6
3.6k
Mar ’26
Draw An Outline Around a Model Entity
Hi, Is there a resource or sample code about how to draw an outline around a mesh in RealityKit? Typically, this is useful for visualizing a selection, like in Reality Composer Pro. How to achieve such effect? A shader material? A post-process effect in ARView or RealityRenderer? Methods such as duplicating the entity mesh, scaling it, and using material.faceCulling = .front did not look good in my experiments. Thank you.
1
0
744
Feb ’26
ARView ignores multi-touch events
Hi, How to enable multitouch on ARView? Touch functions (touchesBegan, touchesMoved, ...) seem to only handle one touch at a time. In order to handle multiple touches at a time with ARView, I have to either: Use SwiftUI .simultaneousGesture on top of an ARView representable Position a UIView on top of ARView to capture touches and do hit testing by passing a reference to ARView Expected behavior: ARView should capture all touches via touchesBegan/Moved/Ended/Cancelled. Here is what I tried, on iOS 26.1 and macOS 26.1: ARView Multitouch The setup below is a minimal ARView presented by SwiftUI, with touch events handled inside ARView. Multitouch doesn't work with this setup. Note that multitouch wouldn't work either if the ARView is presented with a UIViewController instead of SwiftUI. import RealityKit import SwiftUI struct ARViewMultiTouchView: View { var body: some View { ZStack { ARViewMultiTouchRepresentable() .ignoresSafeArea() } } } #Preview { ARViewMultiTouchView() } // MARK: Representable ARView struct ARViewMultiTouchRepresentable: UIViewRepresentable { func makeUIView(context: Context) -> ARView { let arView = ARViewMultiTouch(frame: .zero) let anchor = AnchorEntity() arView.scene.addAnchor(anchor) let boxWidth: Float = 0.4 let boxMaterial = SimpleMaterial(color: .red, isMetallic: false) let box = ModelEntity(mesh: .generateBox(size: boxWidth), materials: [boxMaterial]) box.name = "Box" box.components.set(CollisionComponent(shapes: [.generateBox(width: boxWidth, height: boxWidth, depth: boxWidth)])) anchor.addChild(box) return arView } func updateUIView(_ uiView: ARView, context: Context) { } } // MARK: ARView class ARViewMultiTouch: ARView { required init(frame: CGRect) { super.init(frame: frame) /// Enable multi-touch isMultipleTouchEnabled = true cameraMode = .nonAR automaticallyConfigureSession = false environment.background = .color(.gray) /// Disable gesture recognizers to not conflict with touch events /// But it doesn't fix the issue gestureRecognizers?.forEach { $0.isEnabled = false } } required dynamic init?(coder decoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { for touch in touches { /// # Problem /// This should print for every new touch, up to 5 simultaneously on an iPhone (multi-touch) /// But it only fires for one touch at a time (single-touch) print("Touch began at: \(touch.location(in: self))") } } } Multitouch with an Overlay This setup works, but it doesn't seem right. There must be a solution to make ARView handle multi touch directly, right? import SwiftUI import RealityKit struct MultiTouchOverlayView: View { var body: some View { ZStack { MultiTouchOverlayRepresentable() .ignoresSafeArea() Text("Multi touch with overlay view") .font(.system(size: 24, weight: .medium)) .foregroundStyle(.white) .offset(CGSize(width: 0, height: -150)) } } } #Preview { MultiTouchOverlayView() } // MARK: Representable Container struct MultiTouchOverlayRepresentable: UIViewRepresentable { func makeUIView(context: Context) -> UIView { /// The view that SwiftUI will present let container = UIView() /// ARView let arView = ARView(frame: container.bounds) arView.autoresizingMask = [.flexibleWidth, .flexibleHeight] arView.cameraMode = .nonAR arView.automaticallyConfigureSession = false arView.environment.background = .color(.gray) let anchor = AnchorEntity() arView.scene.addAnchor(anchor) let boxWidth: Float = 0.4 let boxMaterial = SimpleMaterial(color: .red, isMetallic: false) let box = ModelEntity(mesh: .generateBox(size: boxWidth), materials: [boxMaterial]) box.name = "Box" box.components.set(CollisionComponent(shapes: [.generateBox(width: boxWidth, height: boxWidth, depth: boxWidth)])) anchor.addChild(box) /// The view that will capture touches let touchOverlay = TouchOverlayView(frame: container.bounds) touchOverlay.autoresizingMask = [.flexibleWidth, .flexibleHeight] touchOverlay.backgroundColor = .clear /// Pass an arView reference to the overlay for hit testing touchOverlay.arView = arView /// Add views to the container. /// ARView goes in first, at the bottom. container.addSubview(arView) /// TouchOverlay goes in last, on top. container.addSubview(touchOverlay) return container } func updateUIView(_ uiView: UIView, context: Context) { } } // MARK: Touch Overlay View /// A UIView to handle multi-touch on top of ARView class TouchOverlayView: UIView { weak var arView: ARView? override init(frame: CGRect) { super.init(frame: frame) isMultipleTouchEnabled = true isUserInteractionEnabled = true } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { let totalTouches = event?.allTouches?.count ?? touches.count print("--- Touches Began --- (New: \(touches.count), Total: \(totalTouches))") for touch in touches { let location = touch.location(in: self) /// Hit testing. /// ARView and Touch View must be of the same size if let arView = arView { let entity = arView.entity(at: location) if let entity = entity { print("Touched entity: \(entity.name)") } else { print("Touched: none") } } } } override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { let totalTouches = event?.allTouches?.count ?? touches.count print("--- Touches Cancelled --- (Cancelled: \(touches.count), Total: \(totalTouches))") } }
2
0
586
Jan ’26
SpriteKit Offline Rendering with SKRenderer
Hi! I'd like to share a technical sample app, SKRenderer Demo. This app demonstrates: Setting up SKRenderer Recording SpriteKit scenes to image sequences Recording SpriteKit scenes to video using IOSurface and AVFoundation Applying Core Image filters Exploring SpriteKit's simulation timing and physics determinism Use Case Record SpriteKit simulations as video or images for sharing and creating content. I explored several approaches, including the excellent view.texture(from:crop:) for live recording from SKView. The SKRenderer approach assumes recording happens asynchronously: you capture user interactions as commands during live interaction, then replay those commands through an offline render pass to generate the final output. I hope this helps others working on replay systems, simulation capture, or SpriteKit projects in general!
0
0
514
Jan ’26
SpriteKit/RealityKit + SwiftUI Performance Regression on iOS 26
Hi, Toggling a SwiftUI menu in iOS 26 significantly reduces the framerate of an underlying SKView or ARView. Below are test cases for SpriteKit and RealityKit. I ran these tests on iOS 26.1 Beta using an iPhone 13 (A15 chip). Results were similar on iOS 26.0.1. Both scenes consist of circles and balls bouncing on the ground. The restitution of the physics bodies is set for near-perfect elasticity, so they keep bouncing indefinitely. In both SKView and ARView, the framerate drops significantly whenever the SwiftUI menu is toggled. The menu itself is simple and uses standard SwiftUI animations and styling. SpriteKit import SpriteKit import SwiftUI class SKRestitutionScene: SKScene { override func didMove(to view: SKView) { view.contentMode = .center size = view.bounds.size scaleMode = .resizeFill backgroundColor = .darkGray anchorPoint = CGPoint(x: 0.5, y: 0.5) let groundWidth: CGFloat = 300 let ground = SKSpriteNode(color: .gray, size: CGSize(width: groundWidth, height: 10)) ground.physicsBody = SKPhysicsBody(rectangleOf: ground.size) ground.physicsBody?.isDynamic = false addChild(ground) let circleCount = 5 let spacing: CGFloat = 60 let totalWidth = CGFloat(circleCount - 1) * spacing let startX = -totalWidth / 2 for i in 0..<circleCount { let circle = SKShapeNode(circleOfRadius: 18) circle.fillColor = .systemOrange circle.lineWidth = 0 circle.physicsBody = SKPhysicsBody(circleOfRadius: 18) circle.physicsBody?.restitution = 1 circle.physicsBody?.linearDamping = 0 let x = startX + CGFloat(i) * spacing circle.position = CGPoint(x: x, y: 150) addChild(circle) } } override func willMove(from view: SKView) { self.removeAllChildren() } } struct SKRestitutionView: View { var body: some View { ZStack { SpriteView(scene: SKRestitutionScene(), preferredFramesPerSecond: 120) .ignoresSafeArea() VStack { Spacer() Menu { Button("Edit", systemImage: "pencil") {} Button("Share", systemImage: "square.and.arrow.up") {} Button("Delete", systemImage: "trash") {} } label: { Text("Menu") } .buttonStyle(.glass) } .padding() } } } #Preview { SKRestitutionView() } RealityKit import RealityKit import SwiftUI struct ARViewPhysicsRestitution: UIViewRepresentable { let arView = ARView() func makeUIView(context: Context) -> some ARView { arView.contentMode = .center arView.cameraMode = .nonAR arView.automaticallyConfigureSession = false arView.environment.background = .color(.gray) // MARK: Root let anchor = AnchorEntity() arView.scene.addAnchor(anchor) // MARK: Camera let camera = Entity() camera.components.set(PerspectiveCameraComponent()) camera.position = [0, 1, 4] camera.look(at: .zero, from: camera.position, relativeTo: nil) anchor.addChild(camera) // MARK: Ground let groundWidth: Float = 3.0 let ground = Entity() let groundMesh = MeshResource.generateBox(width: groundWidth, height: 0.1, depth: groundWidth) let groundModel = ModelComponent(mesh: groundMesh, materials: [SimpleMaterial(color: .white, roughness: 1, isMetallic: false)]) ground.components.set(groundModel) let groundShape = ShapeResource.generateBox(width: groundWidth, height: 0.1, depth: groundWidth) let groundCollision = CollisionComponent(shapes: [groundShape]) ground.components.set(groundCollision) let groundPhysicsBody = PhysicsBodyComponent( material: PhysicsMaterialResource.generate(friction: 0, restitution: 0.97), mode: .static ) ground.components.set(groundPhysicsBody) anchor.addChild(ground) // MARK: Balls let ballCount = 5 let spacing: Float = 0.4 let totalWidth = Float(ballCount - 1) * spacing let startX = -totalWidth / 2 let radius: Float = 0.12 let ballMesh = MeshResource.generateSphere(radius: radius) let ballMaterial = SimpleMaterial(color: .systemOrange, roughness: 1, isMetallic: false) let ballShape = ShapeResource.generateSphere(radius: radius) for i in 0..<ballCount { let ball = Entity() let ballModel = ModelComponent(mesh: ballMesh, materials: [ballMaterial]) ball.components.set(ballModel) let ballCollision = CollisionComponent(shapes: [ballShape]) ball.components.set(ballCollision) var ballPhysicsBody = PhysicsBodyComponent( material: PhysicsMaterialResource.generate(friction: 0, restitution: 0.97), /// 0.97 for near perfect elasticity mode: .dynamic ) ballPhysicsBody.linearDamping = 0 ballPhysicsBody.angularDamping = 0 ball.components.set(ballPhysicsBody) let shadow = GroundingShadowComponent(castsShadow: true) ball.components.set(shadow) let x = startX + Float(i) * spacing ball.position = [x, 1, 0] anchor.addChild(ball) } return arView } func updateUIView(_ uiView: UIViewType, context: Context) { } } struct PhysicsRestitutionView: View { var body: some View { ZStack { ARViewPhysicsRestitution() .ignoresSafeArea() .background(.black) VStack { Spacer() Menu { Button("Edit", systemImage: "pencil") {} Button("Share", systemImage: "square.and.arrow.up") {} Button("Delete", systemImage: "trash") {} } label: { Text("Menu") } .buttonStyle(.glass) } .padding() } } } #Preview { PhysicsRestitutionView() }
2
0
342
Oct ’25
ARView [.showStatistics] doesn't work on Xcode Canvas
Hi, I can't see RealityKit statistics on Xcode Canvas using: arView.debugOptions = [.showStatistics] The statistics only show on a physical device, not Xcode live canvas with #Preview. Testing in Xcode 26.0.1 (17A400) on Tahoe 26.0.1 (25A362). Use case: I'm using RealityKit as a non-AR 3D engine. Xcode Canvas is useful for live iterations. Is this expected behavior? How can I see FPS on Xcode canvas? SKView for example shows all debug options on both Xcode Canvas and physical devices.
0
0
573
Oct ’25
SpriteKit Continued Support
Hi! Question Could you provide some reassurance on the continued support for SpriteKit in the coming years? Trigger The deprecation of SceneKit at WWDC 2025 made me nervous. Context I use SpriteKit because: It can render any video AVFoundation can handle, which third-party engines don't do for several reasons including patents. This allows me to prototype UI that controls video with a game-like feel. It can render text and emojis through AttributedString, and text is hard. Thanks to a clear and well-exposed update loop, it can be integrated with libraries such as Core Image or Box2D. Example with Box2D here. It can draw dynamic shapes and paths with SKShapeNode, and visualize and respond to all the processing done at specific times during a frame. SKView is very handy to generate textures from nodes, and SKRenderer can be used to render a SpriteKit scene to video or sequence of images. This is possible thanks to multiple frameworks working together, including AVAssetWriter and IOSurface. Example of SpriteKit offline rendering here. Apple Alternatives When Apple announced the deprecation of SceneKit, I learned RealityKit in order to move my SpriteKit-based projects to RealityKit. RealityKit is interesting, but for 2D and 2.5D workflows I found several areas where SpriteKit remains significantly more practical: I had to lock physics to the XY plane, which could stress the engine and introduce unwanted overlap. Overlapping entities on a 2D plane was hard: ModelSortGroup did not provide the simple flexibility that SpriteKit zPosition provides. AFAIK there is no dynamic path/shape drawing in RealityKit. So drawing lines, visualizing physics and joints, rendering graph connections in the scene is not as easy as it is with SpriteKit shape nodes. SpriteKit is lighter and less power-hungry. Let me know if you need any more context or detail. Thank you!
Replies
1
Boosts
2
Views
170
Activity
1w
SpriteKit & Box2D
Hi, I integrated SpriteKit with Box2D version 3, and they work amazingly well together. I shared videos, code, and implementation notes on the project page: SpriteKit Box2D Context SpriteKit built-in physics engine is based on Box2D, likely from an older 2.x generation. This project uses Box2D 3.x directly. Box2D 3.0 was first released in 2024 as a major rewrite with a new C API. It brings improved collision handling, better performance, better stability for demanding simulations, and features that are not exposed through SpriteKit’s SKPhysicsWorld. Box2D 3 is also designed with determinism in mind. SpriteKit's physics implementation is nice to use, but it is not deterministic. See the Determinism section of my SKRenderer Demo for more information about determinism in SpriteKit. Swift & C Because Box2D 3 is written in C, this sample app also shows how to mix Swift and C in the same Xcode project. I wrote a tutorial on how to mix Swift with C in an Xcode project. I hope this is useful to anyone experimenting with SpriteKit physics or external C libraries. Let me know if you have questions or ideas.
Replies
0
Boosts
0
Views
188
Activity
1w
SpriteKit's Continued Support
Hi, Can Apple provide some reassurance on the continued support for SpriteKit in the coming years? At WWDC 2025, Apple deprecated SceneKit, which was alarming for a SpriteKit fan and user. I'm aware Apple doesn't comment on future plans. However, committing to a specific framework for larger projects is a significant investment in time (and money). Developers need to know whether to continue investing in proprietary technology that could be deprecated at any time. Some reassurance regarding SpriteKit's future would go a long way. I have moved my project from SpriteKit to RealityKit. RealityKit is certainly interesting, but I'd gladly switch back to SpriteKit. SpriteKit has things going for it that no other Apple framework provides: Live drawing of shapes, paths, text, video, and images at 120 FPS across all Apple devices. RealityKit offers no procedural drawing API equivalent to shape nodes. Particles and physics fields are very easy and fun to play with. The rigid body engine has a good feel. By comparison, RealityKit sleeps too aggressively, and doesn't have spring joints. SpriteKit is lightweight and runs well on older devices. In an ideal world, I'd also love to see SpriteKit improved: A deterministic physics engine Metal shader support Soft shadows for lights One can dream. Thank you!
Replies
1
Boosts
4
Views
581
Activity
May ’26
Xcode 26.4 Editor Tab Bar is low density
Hi, On a 1920 points wide monitor, running maximized, Xcode 26.4 can't show more than 10 editor tabs at a time. Under the same conditions, Xcode 26.2 adapts tab widths to file names and fits 12-14 tabs. That's 2-4 more files I can see and access at a glance, without extra interaction. How can I get that level of information density back in the Xcode 26.4 editor tab bar? Screenshots Xcode 26.4 (10 tabs) Xcode 26.2 (12 tabs) Xcode 26.2 (14 tabs)
Replies
1
Boosts
0
Views
106
Activity
Mar ’26
Xcode 26.3 - Revert to variable editor tab width
Hi, In Xcode 26.2, editor tabs adapt their width to the number of pinned tabs: In Xcode 26.3, editor tabs have a minimal width, after which the row of tabs becomes horizontally scrollable: Notice how less tabs are visible at a time on Xcode 26.3 (second image). Yet, there is enough horizontal space to accommodate more, as shown on Xcode 26.2 (first image). This is a UX regression. How can I revert back to 26.2 tab sizing behavior? Thank you.
Replies
1
Boosts
0
Views
119
Activity
Mar ’26
SpriteKit framerate drop on iOS 26.0
Hello, I have noticed a performance drop on SpriteKit-based projects running on iOS 26.0 (23A341). Below is a SpriteKit scene used to test framerate on different devices: import SpriteKit import SwiftUI class BareboneScene: SKScene { override func didMove(to view: SKView) { size = view.bounds.size anchorPoint = CGPoint(x: 0.5, y: 0.5) backgroundColor = .darkGray let roundedSquare = SKShapeNode(rectOf: CGSize(width: 150, height: 75), cornerRadius: 12) roundedSquare.fillColor = .systemRed roundedSquare.strokeColor = .black roundedSquare.lineWidth = 3 addChild(roundedSquare) let action = SKAction.rotate(byAngle: .pi, duration: 1) roundedSquare.run(.repeatForever(action)) } } struct BareboneSceneView: View { var body: some View { SpriteView( scene: BareboneScene(), debugOptions: [.showsFPS] ) .ignoresSafeArea() } } #Preview { BareboneSceneView() } The scene is very simple, yet framerate drops to ~40 fps as shown by the Metal HUD. Tested on: iPhone 13, iOS 26.0: framerate drops to 40 fps. Sometimes it runs at near 60fps. But if the screen is touched repeatedly, the framerate drops to 40-50 fps again. iPhone 11 Pro, iOS 26.0: ~40fps. iPad 9th Gen, iOS 18.6.2: 60fps, no issues. See screenshots attached. These numbers were observed by me and members of our beloved SpriteKit Discord server. Thank you for your attention.
Replies
15
Boosts
6
Views
3.6k
Activity
Mar ’26
Draw An Outline Around a Model Entity
Hi, Is there a resource or sample code about how to draw an outline around a mesh in RealityKit? Typically, this is useful for visualizing a selection, like in Reality Composer Pro. How to achieve such effect? A shader material? A post-process effect in ARView or RealityRenderer? Methods such as duplicating the entity mesh, scaling it, and using material.faceCulling = .front did not look good in my experiments. Thank you.
Replies
1
Boosts
0
Views
744
Activity
Feb ’26
ARView ignores multi-touch events
Hi, How to enable multitouch on ARView? Touch functions (touchesBegan, touchesMoved, ...) seem to only handle one touch at a time. In order to handle multiple touches at a time with ARView, I have to either: Use SwiftUI .simultaneousGesture on top of an ARView representable Position a UIView on top of ARView to capture touches and do hit testing by passing a reference to ARView Expected behavior: ARView should capture all touches via touchesBegan/Moved/Ended/Cancelled. Here is what I tried, on iOS 26.1 and macOS 26.1: ARView Multitouch The setup below is a minimal ARView presented by SwiftUI, with touch events handled inside ARView. Multitouch doesn't work with this setup. Note that multitouch wouldn't work either if the ARView is presented with a UIViewController instead of SwiftUI. import RealityKit import SwiftUI struct ARViewMultiTouchView: View { var body: some View { ZStack { ARViewMultiTouchRepresentable() .ignoresSafeArea() } } } #Preview { ARViewMultiTouchView() } // MARK: Representable ARView struct ARViewMultiTouchRepresentable: UIViewRepresentable { func makeUIView(context: Context) -> ARView { let arView = ARViewMultiTouch(frame: .zero) let anchor = AnchorEntity() arView.scene.addAnchor(anchor) let boxWidth: Float = 0.4 let boxMaterial = SimpleMaterial(color: .red, isMetallic: false) let box = ModelEntity(mesh: .generateBox(size: boxWidth), materials: [boxMaterial]) box.name = "Box" box.components.set(CollisionComponent(shapes: [.generateBox(width: boxWidth, height: boxWidth, depth: boxWidth)])) anchor.addChild(box) return arView } func updateUIView(_ uiView: ARView, context: Context) { } } // MARK: ARView class ARViewMultiTouch: ARView { required init(frame: CGRect) { super.init(frame: frame) /// Enable multi-touch isMultipleTouchEnabled = true cameraMode = .nonAR automaticallyConfigureSession = false environment.background = .color(.gray) /// Disable gesture recognizers to not conflict with touch events /// But it doesn't fix the issue gestureRecognizers?.forEach { $0.isEnabled = false } } required dynamic init?(coder decoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { for touch in touches { /// # Problem /// This should print for every new touch, up to 5 simultaneously on an iPhone (multi-touch) /// But it only fires for one touch at a time (single-touch) print("Touch began at: \(touch.location(in: self))") } } } Multitouch with an Overlay This setup works, but it doesn't seem right. There must be a solution to make ARView handle multi touch directly, right? import SwiftUI import RealityKit struct MultiTouchOverlayView: View { var body: some View { ZStack { MultiTouchOverlayRepresentable() .ignoresSafeArea() Text("Multi touch with overlay view") .font(.system(size: 24, weight: .medium)) .foregroundStyle(.white) .offset(CGSize(width: 0, height: -150)) } } } #Preview { MultiTouchOverlayView() } // MARK: Representable Container struct MultiTouchOverlayRepresentable: UIViewRepresentable { func makeUIView(context: Context) -> UIView { /// The view that SwiftUI will present let container = UIView() /// ARView let arView = ARView(frame: container.bounds) arView.autoresizingMask = [.flexibleWidth, .flexibleHeight] arView.cameraMode = .nonAR arView.automaticallyConfigureSession = false arView.environment.background = .color(.gray) let anchor = AnchorEntity() arView.scene.addAnchor(anchor) let boxWidth: Float = 0.4 let boxMaterial = SimpleMaterial(color: .red, isMetallic: false) let box = ModelEntity(mesh: .generateBox(size: boxWidth), materials: [boxMaterial]) box.name = "Box" box.components.set(CollisionComponent(shapes: [.generateBox(width: boxWidth, height: boxWidth, depth: boxWidth)])) anchor.addChild(box) /// The view that will capture touches let touchOverlay = TouchOverlayView(frame: container.bounds) touchOverlay.autoresizingMask = [.flexibleWidth, .flexibleHeight] touchOverlay.backgroundColor = .clear /// Pass an arView reference to the overlay for hit testing touchOverlay.arView = arView /// Add views to the container. /// ARView goes in first, at the bottom. container.addSubview(arView) /// TouchOverlay goes in last, on top. container.addSubview(touchOverlay) return container } func updateUIView(_ uiView: UIView, context: Context) { } } // MARK: Touch Overlay View /// A UIView to handle multi-touch on top of ARView class TouchOverlayView: UIView { weak var arView: ARView? override init(frame: CGRect) { super.init(frame: frame) isMultipleTouchEnabled = true isUserInteractionEnabled = true } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { let totalTouches = event?.allTouches?.count ?? touches.count print("--- Touches Began --- (New: \(touches.count), Total: \(totalTouches))") for touch in touches { let location = touch.location(in: self) /// Hit testing. /// ARView and Touch View must be of the same size if let arView = arView { let entity = arView.entity(at: location) if let entity = entity { print("Touched entity: \(entity.name)") } else { print("Touched: none") } } } } override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { let totalTouches = event?.allTouches?.count ?? touches.count print("--- Touches Cancelled --- (Cancelled: \(touches.count), Total: \(totalTouches))") } }
Replies
2
Boosts
0
Views
586
Activity
Jan ’26
SpriteKit Offline Rendering with SKRenderer
Hi! I'd like to share a technical sample app, SKRenderer Demo. This app demonstrates: Setting up SKRenderer Recording SpriteKit scenes to image sequences Recording SpriteKit scenes to video using IOSurface and AVFoundation Applying Core Image filters Exploring SpriteKit's simulation timing and physics determinism Use Case Record SpriteKit simulations as video or images for sharing and creating content. I explored several approaches, including the excellent view.texture(from:crop:) for live recording from SKView. The SKRenderer approach assumes recording happens asynchronously: you capture user interactions as commands during live interaction, then replay those commands through an offline render pass to generate the final output. I hope this helps others working on replay systems, simulation capture, or SpriteKit projects in general!
Replies
0
Boosts
0
Views
514
Activity
Jan ’26
SpriteKit/RealityKit + SwiftUI Performance Regression on iOS 26
Hi, Toggling a SwiftUI menu in iOS 26 significantly reduces the framerate of an underlying SKView or ARView. Below are test cases for SpriteKit and RealityKit. I ran these tests on iOS 26.1 Beta using an iPhone 13 (A15 chip). Results were similar on iOS 26.0.1. Both scenes consist of circles and balls bouncing on the ground. The restitution of the physics bodies is set for near-perfect elasticity, so they keep bouncing indefinitely. In both SKView and ARView, the framerate drops significantly whenever the SwiftUI menu is toggled. The menu itself is simple and uses standard SwiftUI animations and styling. SpriteKit import SpriteKit import SwiftUI class SKRestitutionScene: SKScene { override func didMove(to view: SKView) { view.contentMode = .center size = view.bounds.size scaleMode = .resizeFill backgroundColor = .darkGray anchorPoint = CGPoint(x: 0.5, y: 0.5) let groundWidth: CGFloat = 300 let ground = SKSpriteNode(color: .gray, size: CGSize(width: groundWidth, height: 10)) ground.physicsBody = SKPhysicsBody(rectangleOf: ground.size) ground.physicsBody?.isDynamic = false addChild(ground) let circleCount = 5 let spacing: CGFloat = 60 let totalWidth = CGFloat(circleCount - 1) * spacing let startX = -totalWidth / 2 for i in 0..<circleCount { let circle = SKShapeNode(circleOfRadius: 18) circle.fillColor = .systemOrange circle.lineWidth = 0 circle.physicsBody = SKPhysicsBody(circleOfRadius: 18) circle.physicsBody?.restitution = 1 circle.physicsBody?.linearDamping = 0 let x = startX + CGFloat(i) * spacing circle.position = CGPoint(x: x, y: 150) addChild(circle) } } override func willMove(from view: SKView) { self.removeAllChildren() } } struct SKRestitutionView: View { var body: some View { ZStack { SpriteView(scene: SKRestitutionScene(), preferredFramesPerSecond: 120) .ignoresSafeArea() VStack { Spacer() Menu { Button("Edit", systemImage: "pencil") {} Button("Share", systemImage: "square.and.arrow.up") {} Button("Delete", systemImage: "trash") {} } label: { Text("Menu") } .buttonStyle(.glass) } .padding() } } } #Preview { SKRestitutionView() } RealityKit import RealityKit import SwiftUI struct ARViewPhysicsRestitution: UIViewRepresentable { let arView = ARView() func makeUIView(context: Context) -> some ARView { arView.contentMode = .center arView.cameraMode = .nonAR arView.automaticallyConfigureSession = false arView.environment.background = .color(.gray) // MARK: Root let anchor = AnchorEntity() arView.scene.addAnchor(anchor) // MARK: Camera let camera = Entity() camera.components.set(PerspectiveCameraComponent()) camera.position = [0, 1, 4] camera.look(at: .zero, from: camera.position, relativeTo: nil) anchor.addChild(camera) // MARK: Ground let groundWidth: Float = 3.0 let ground = Entity() let groundMesh = MeshResource.generateBox(width: groundWidth, height: 0.1, depth: groundWidth) let groundModel = ModelComponent(mesh: groundMesh, materials: [SimpleMaterial(color: .white, roughness: 1, isMetallic: false)]) ground.components.set(groundModel) let groundShape = ShapeResource.generateBox(width: groundWidth, height: 0.1, depth: groundWidth) let groundCollision = CollisionComponent(shapes: [groundShape]) ground.components.set(groundCollision) let groundPhysicsBody = PhysicsBodyComponent( material: PhysicsMaterialResource.generate(friction: 0, restitution: 0.97), mode: .static ) ground.components.set(groundPhysicsBody) anchor.addChild(ground) // MARK: Balls let ballCount = 5 let spacing: Float = 0.4 let totalWidth = Float(ballCount - 1) * spacing let startX = -totalWidth / 2 let radius: Float = 0.12 let ballMesh = MeshResource.generateSphere(radius: radius) let ballMaterial = SimpleMaterial(color: .systemOrange, roughness: 1, isMetallic: false) let ballShape = ShapeResource.generateSphere(radius: radius) for i in 0..<ballCount { let ball = Entity() let ballModel = ModelComponent(mesh: ballMesh, materials: [ballMaterial]) ball.components.set(ballModel) let ballCollision = CollisionComponent(shapes: [ballShape]) ball.components.set(ballCollision) var ballPhysicsBody = PhysicsBodyComponent( material: PhysicsMaterialResource.generate(friction: 0, restitution: 0.97), /// 0.97 for near perfect elasticity mode: .dynamic ) ballPhysicsBody.linearDamping = 0 ballPhysicsBody.angularDamping = 0 ball.components.set(ballPhysicsBody) let shadow = GroundingShadowComponent(castsShadow: true) ball.components.set(shadow) let x = startX + Float(i) * spacing ball.position = [x, 1, 0] anchor.addChild(ball) } return arView } func updateUIView(_ uiView: UIViewType, context: Context) { } } struct PhysicsRestitutionView: View { var body: some View { ZStack { ARViewPhysicsRestitution() .ignoresSafeArea() .background(.black) VStack { Spacer() Menu { Button("Edit", systemImage: "pencil") {} Button("Share", systemImage: "square.and.arrow.up") {} Button("Delete", systemImage: "trash") {} } label: { Text("Menu") } .buttonStyle(.glass) } .padding() } } } #Preview { PhysicsRestitutionView() }
Replies
2
Boosts
0
Views
342
Activity
Oct ’25
ARView [.showStatistics] doesn't work on Xcode Canvas
Hi, I can't see RealityKit statistics on Xcode Canvas using: arView.debugOptions = [.showStatistics] The statistics only show on a physical device, not Xcode live canvas with #Preview. Testing in Xcode 26.0.1 (17A400) on Tahoe 26.0.1 (25A362). Use case: I'm using RealityKit as a non-AR 3D engine. Xcode Canvas is useful for live iterations. Is this expected behavior? How can I see FPS on Xcode canvas? SKView for example shows all debug options on both Xcode Canvas and physical devices.
Replies
0
Boosts
0
Views
573
Activity
Oct ’25
RealityView show debug options
Hi! Using ARView in UIKit or through a UIViewRepresentable in SwiftUI, we can do: arView.debugOptions = [.showPhysics, .showStatistics] What is the equivalent in RealityView?
Replies
0
Boosts
0
Views
294
Activity
Oct ’25