visionOS supports fully photo-realistic, spatially-aware 360° immersive environments with true depth, parallax, spatial audio, and motion ā going far beyond static panoramas. Developers can now surface these environments on both native visionOS apps and the spatial web.
⢠visionOS 3 extends immersive environments to the spatial web, allowing web pages to trigger full immersion via new WebXR/spatial APIs
⢠New design guidance codifies the 81° primary FOV, the 1-meter camera height standard, and the 40 px/degree sharpness target
⢠Motion and spatial audio attachment to individual mesh layers is now a first-class workflow in RealityKit, replacing manual anchor hacks
⢠System environments (Haleakala, Moon, Jupiter, etc.) demonstrate a layered-mesh parallax model that third-party environments can now replicate with documented APIs
⢠True parallax and depth separation (not just a skybox) means users perceive genuine 3D space, raising the bar for presence and immersion in your app
⢠Environments can be tailored per app purpose ā media viewing, productivity, creative tools ā with controllable lighting, audio anchors, and animated scene elements
⢠Spatial web support means a web-based experience can launch a full immersive environment without requiring a native app install
Loads a custom USDZ environment mesh and panoramic sky texture into a RealityKit ImmersiveSpace, demonstrates per-layer spatial audio attachment and environment-driven IBL lighting.
import SwiftUIimport RealityKit+import AVFoundationā// Pre-visionOS 3 approach: basic ImmersiveSpace with a single sky sphere,ā// no layered parallax mesh separation, manual audio setup via AVAudioEngineā+// MARK: - App Entry@maināstruct OldImmersiveApp: App {+struct ImmersiveEnvApp: App {var body: some Scene {ā WindowGroup { OldContentView() }ā ImmersiveSpace(id: "OldEnv") { OldEnvironmentView() }+ WindowGroup {+ ContentView()+ }+ ImmersiveSpace(id: "NatureEnvironment") {+ NatureEnvironmentView()+ }+ .immersionStyle(selection: .constant(.full), in: .full)}}āstruct OldContentView: View {ā @Environment(\.openImmersiveSpace) private var open+// MARK: - Launcher+struct ContentView: View {+ @Environment(\.openImmersiveSpace) private var openImmersiveSpace+ @Environment(\.dismissImmersiveSpace) private var dismissImmersiveSpace+ @State private var isImmersed = false+var body: some View {ā Button("Enter") { Task { await open(id: "OldEnv") } }+ Button(isImmersed ? "Exit Environment" : "Enter Environment") {+ Task {+ if isImmersed {+ await dismissImmersiveSpace()+ } else {+ await openImmersiveSpace(id: "NatureEnvironment")+ }+ isImmersed.toggle()+ }+ }+ .padding()}}āstruct OldEnvironmentView: View {+// MARK: - Immersive Environment+struct NatureEnvironmentView: View {var body: some View {RealityView { content inā // Single sphere ā no depth layers, no parallaxā let sphere = makeLegacySkySphere()ā content.add(sphere)ā // Audio: had to wire AVAudioEngine manually outside RealityKit+ // 1. Sky sphere ā panoramic equirectangular texture (14400x7200 px ideal)+ let skySphere = makeSkySphere()+ content.add(skySphere)++ // 2. Foreground terrain mesh with parallax separation+ if let terrain = try? await Entity(named: "TerrainMesh", in: .main) {+ terrain.position = SIMD3(0, -1.0, 0)+ content.add(terrain)+ }++ // 3. Spatial audio source anchored to a waterfall entity+ let audioAnchor = AnchorEntity(world: SIMD3(x: -3, y: 0.5, z: -6))+ let audioSource = makeSpatialAudioSource()+ audioAnchor.addChild(audioSource)+ content.add(audioAnchor)}ā // No built-in IBL binding ā developers set lighting viaā // ImageBasedLightComponent directly on a separate entity+ // IBL from the same equirectangular panorama drives scene lighting+ .environment(\.physicallyBasedLighting, .imageBasedLight(resource: "PanoramaIBL"))}}āprivate func makeLegacySkySphere() -> Entity {+// MARK: - Helpers+private func makeSkySphere() -> Entity {+ // Large inverted sphere ā viewer sits at center (1 m off ground)let mesh = MeshResource.generateSphere(radius: 1000)ā var mat = UnlitMaterial()ā // Texture loaded synchronously ā no async streaming supportā if let tex = try? TextureResource.load(named: "OldPanorama") {ā mat.color = .init(texture: .init(tex))+ var material = UnlitMaterial()+ if let tex = try? TextureResource.load(named: "EnvironmentPanorama") {+ material.color = .init(texture: .init(tex))}ā let entity = ModelEntity(mesh: mesh, materials: [mat])+ let entity = ModelEntity(mesh: mesh, materials: [material])+ // Invert normals so texture is visible from insideentity.scale = SIMD3(-1, 1, 1)+ entity.position = SIMD3(0, 0, 0)return entity+}++private func makeSpatialAudioSource() -> Entity {+ let entity = Entity()+ var spatialAudio = SpatialAudioComponent()+ spatialAudio.gain = -6 // dB, subtle ambient level+ spatialAudio.directivity = .beam(focus: 0.5)+ entity.components.set(spatialAudio)++ // Attach a looping ambient audio resource+ if let resource = try? AudioFileResource.load(+ named: "WaterfallLoop",+ configuration: .init(shouldLoop: true)+ ) {+ entity.playAudio(resource)+ }+ return entity}
Liquid Glass is Apple's new material and visual design language introduced in iOS 27, bringing translucent, refractive glass-like surfaces to system and custom UI elements. It replaces the frosted vibrancy aesthetic with a more dynamic, depth-aware material that responds to content beneath it.
PaperKit is Apple's full-featured canvas framework ā previously internal-only ā now publicly available in iOS/macOS/visionOS 27. It powers the drawing and markup experience in Notes, Preview, and Freeform, giving developers access to a complete pencil, shapes, images, and text canvas with a rich data model.
Xcode 27 introduces a fully customizable toolbar and theme system, untitled scratch projects, coding agent integration directly in the editor, and the new Device Hub for evaluating apps across simulators and physical devices side-by-side.
In-depth guide
RealityKit & USDKit in iOS 27 āA 360° panorama must be at least 14,400Ć7,200 px (40 px/degree) to appear sharp at full immersion; UV seams and texture transfers must be validated with extreme gamma checks; environment meshes not visible in the primary panorama must be filled with secondary photography or CG renders or users will see gaps when turning around
Apple Vision Pro only; requires a device with R1 chip for low-latency environment rendering; spatial web environments require Safari on visionOS
iOS 27 introduces new SwiftUI drag and drop APIs including reorderable, reorderContainer, dragContainer, and configuration modifiers that enable reordering within and across collections, multi-item drag, and fine-grained control over how data is transferred during drag and drop operations.