visionOS: Räumliche Muster jenseits des Fensters
Die meisten Apps, die auf visionOS erscheinen, kommen über Apples Kompatibilitätspfad „Designed for iPad“ auf die Plattform: Das vorhandene iPad-Binary läuft als flaches Panel, das im dreidimensionalen Raum schwebt, und die Entwicklerin oder der Entwickler setzt ein Häkchen, statt eine visionOS-eigene Erfahrung zu bauen. Für die Benutzer ist dieser Weg in Ordnung — die App funktioniert —, aber er verkauft die Plattform unter Wert. Die native Oberfläche von visionOS bietet drei Darstellungsformen (Windows, Volumes und Immersive Spaces) sowie strukturelle UI-Primitive (Ornaments, Attachments), die es auf dem iPad in dieser Form nicht gibt.4 Apps, die davon Gebrauch machen, wirken nativ; Apps, die es nicht tun, wirken wie iPad-auf-Vision.
Dieser Beitrag geht das räumliche Vokabular anhand von Apples Dokumentation durch. Der Rahmen lautet „Was bietet die Plattform einer SwiftUI-App tatsächlich?“ und nicht „Einführung in visionOS“. Der Beitrag RealityKit und das räumliche Denkmodell aus derselben Reihe behandelt die 3D-Inhaltsebene; hier geht es um die SwiftUI-Oberfläche, die diese Ebene umschließt.
Kurzfassung
- visionOS-Apps setzen sich aus drei Szenentypen zusammen:
WindowGroup(Windows),WindowGroupmit.windowStyle(.volumetric)(Volumes) undImmersiveSpace(Immersive Spaces)1. - Ein Window ist eine 2D-Ebene, ein Volume ein begrenzter 3D-Bereich, ein Immersive Space umgibt die Benutzer. Für jeden gelten andere Regeln: Volumes haben nach dem Öffnen eine unveränderliche Größe, Immersive Spaces müssen ausdrücklich geöffnet und geschlossen werden, Windows verhalten sich am ehesten wie auf dem iPad.
- Immersion gibt es in drei Abstufungen:
.mixed(Inhalte existieren neben dem realen Raum),.full(der Raum wird durch eine virtuelle Umgebung ersetzt) und.progressive(der Mittelweg mit peripherer Verankerung)2. - Ornaments sind UI-Ebenen, die parallel zu einem Window und auf der z-Achse davor liegen. So setzt visionOS Symbolleisten und Tab-Leisten um3. Attachments betten SwiftUI-Views in 3D-Inhalte innerhalb einer RealityView ein — die Brücke zwischen flacher UI und räumlicher Geometrie.
- Das Antimuster „Panel-App“: Die iPad-Oberfläche wird als Window ausgeliefert, ohne dass Volume, Space oder Ornament übernommen werden. Die App lässt sich benutzen, doch der eigentliche Wert der Plattform bleibt ungenutzt.
Die drei Szenentypen
Der App-Body einer visionOS-App setzt sich aus Szenen dreier Klassen zusammen. Jede besitzt ein eigenes Denkmodell aufseiten der Benutzer.
Windows: die 2D-Ebene
WindowGroup erzeugt standardmäßig ein 2D-Window mit dem visionOS-Glasrahmen. Das System platziert das Window dort im Raum, wohin die Benutzer gerade blicken; verschoben und in der Größe verändert wird es über die üblichen Systemgesten. Aus SwiftUI-Sicht ist ein Window das visionOS-Pendant zum macOS-Fenster: eine flache Inhaltsfläche mit einem Glasmaterial, das räumliche Tiefe berücksichtigt.
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Das Standard-Window legt ein Glasmaterial um seinen Inhalt. Apps, die eine vollständig transparente Fläche wollen, greifen zu .windowStyle(.plain):
WindowGroup {
ContentView()
}
.windowStyle(.plain)
Windows im Plain-Stil verlieren den Glasrahmen des Systems. Verwenden Sie sie, wenn der Inhalt seinen eigenen visuellen Container mitbringt; ansonsten ist die Voreinstellung richtig.
Volumes: der begrenzte 3D-Bereich
Ein Volume ist ein dreidimensionaler Bereich für Inhalte mit räumlicher Tiefe — ein Modell, eine Szene mit mehreren Objekten, eine UI, die von einer dritten Achse profitiert. Auch die Volume-Szene ist eine WindowGroup, nur mit einem anderen Stil:
WindowGroup(id: "globe") {
GlobeView()
}
.windowStyle(.volumetric)
.defaultSize(width: 0.6, height: 0.6, depth: 0.6, in: .meters)
Der Modifier .defaultSize(width:height:depth:in:) legt die Ausdehnung des Volumes in realen Einheiten (Metern) fest. Standardmäßig stehen die Grenzen beim Öffnen fest: Die Benutzer können das Volume verschieben, aber nicht skalieren. Ab visionOS 2 gibt es über .windowResizability(.contentSize) und verwandte APIs einen Opt-in-Pfad für Apps, die skalierbare Volumes anbieten wollen; die feste Größe bleibt der übliche Fall. Daraus folgt: Wählen Sie die Standardgröße sorgfältig, denn die meisten Volumes sind nicht skalierbar, solange man sich nicht ausdrücklich dafür entscheidet.
Für Volumes eignen sich Apps, bei denen die räumliche Begrenzung Teil der Erfahrung ist: eine virtuelle Skulptur, um die man herumgeht, ein Maßband, das an einer echten Wand haftet, eine Trainingsszene mit in der Tiefe gestaffelten Zielen. Apps, die lediglich mehr Leinwand wollen, gewinnen durch ein Volume nichts — ein größeres Window ist dann die richtige Antwort.
Immersive Spaces: die Umgebung
Ein ImmersiveSpace ist eine Szene, die den Raum rund um die Benutzer einnimmt.5 Anders als ein Window oder ein Volume, die beide im Shared Space neben anderen Apps sichtbar bleiben, übernimmt ein Immersive Space die Umgebung und verhindert die gleichzeitige Nutzung der Fenster anderer Apps.
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
ImmersiveSpace(id: "training") {
TrainingScene()
}
.immersionStyle(selection: .constant(.mixed), in: .mixed, .progressive, .full)
}
}
Der Modifier .immersionStyle(...) bestimmt die Stufe der Erfahrung:
.mixed. Virtuelle Inhalte erscheinen neben dem realen Raum. Geeignet für Apps, bei denen die Benutzer von beiden Kontexten profitieren..progressive. Eine teilweise Immersion, die sich über die Digital Crown auf- und abregeln lässt. Die Benutzer behalten den Raum peripher im Blick, während die zentrale Ansicht virtuell ist..full. Der Raum wird durch eine virtuelle Umgebung ersetzt. Geeignet für vollständig immersive Erfahrungen — Meditation, Trainingssimulationen, Spiele.
Ein Immersive Space wird ausdrücklich geöffnet. Die App ruft @Environment(\.openImmersiveSpace) mit der id des Space auf; das System übernimmt die Übergangsanimation und schließt einen etwaigen kollidierenden Space:
@Environment(\.openImmersiveSpace) var openImmersiveSpace
@Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace
Button("Start Session") {
Task {
await openImmersiveSpace(id: "training")
}
}
Pro App kann immer nur ein Immersive Space aktiv sein. Der Wechsel zwischen Spaces — etwa von .mixed zu .full — verlangt, dass der alte Space ausdrücklich geschlossen und der neue geöffnet wird.
Ornaments: die UI-Ebenen rund um ein Window
Ornaments sind SwiftUI-Views, die am Rand eines Window andocken und auf der z-Achse leicht vor dessen Ebene liegen. So setzt visionOS Symbolleisten, Tab-Leisten und ergänzende Bedienelemente um. Das System selbst nutzt sie durchgängig: die Wiedergabesteuerung in TV, das Segmented Control in Music, die Symbolleiste in Mail.
ContentView()
.ornament(
attachmentAnchor: .scene(.bottom),
contentAlignment: .center
) {
HStack {
Button("Previous", systemImage: "backward.fill") { ... }
Button("Play", systemImage: "play.fill") { ... }
Button("Next", systemImage: "forward.fill") { ... }
}
.padding()
.glassBackgroundEffect()
}
Der Parameter attachmentAnchor: bestimmt, wo das Ornament relativ zum Window sitzt: .scene(.top), .scene(.bottom), .scene(.leading), .scene(.trailing). Für die optische Gestaltung sind die Entwickler selbst zuständig; .glassBackgroundEffect() erzeugt das visionOS-eigene Glasmaterial, das zum Rahmen des Window passt.
Ornaments lösen auf visionOS ein reales Problem: Bedienelemente innerhalb des Window machen den Inhalt eng, Bedienelemente in einem eigenen Window zwingen die Benutzer dazu, den Blick neu auszurichten. Ein Ornament schwebt im peripheren Sichtfeld, ist per Blick ansteuerbar und konkurriert dennoch nicht mit dem Hauptinhalt um die zentrale Ansicht.
RealityView-Attachments: SwiftUI im 3D-Raum
Wenn eine App SwiftUI-Views innerhalb einer 3D-Szene braucht — ein Label an einem 3D-Modell, eine Schaltfläche neben einem virtuellen Objekt, eine Messanzeige, die an einer realen Oberfläche haftet —, ist der Attachments-Mechanismus von RealityView die Brücke.
RealityView { content, attachments in
let model = ModelEntity(...)
content.add(model)
if let label = attachments.entity(for: "label") {
label.position = [0, 0.5, 0]
model.addChild(label)
}
} attachments: {
Attachment(id: "label") {
Text("Vintage Globe, 1872")
.padding()
.glassBackgroundEffect()
}
}
Die attachments:-Closure deklariert SwiftUI-Views mit stabilen Bezeichnern. Innerhalb der eigentlichen RealityView-Closure holt attachments.entity(for:) die View als 3D-Entity, die sich im Koordinatenraum der Szene positionieren lässt. Die View nimmt weiterhin am Aktualisierungszyklus von SwiftUI teil — Zustandsänderungen zeichnen sie neu —, während sie in der 3D-Szene als texturierte Ebene gerendert wird.
Für jede UI in der Szene ist dieser Mechanismus der richtige: ein Label, das einem bewegten Objekt folgt, eine Messanmerkung, eine kontextbezogene Schaltfläche. Am Schreiben der SwiftUI-View ändert sich nichts; die räumliche Positionierung passiert auf der RealityView-Ebene.
Das Antimuster „Panel-App“
Der häufigste Fehler beim Ausliefern auf visionOS ist die Panel-App: eine iPad-App, die über die „Designed for iPad“-Kompatibilität auf visionOS landet und als einzelnes Window erscheint — ohne Volume, ohne Immersive Space, ohne Ornaments. Die App funktioniert, aber sie verdient sich die Plattform nicht.
Drei Anzeichen für eine Panel-App:
Eine einzige Window-Szene. Kein .windowStyle(.volumetric), kein deklariertes ImmersiveSpace. Die App ist eine flache Fläche, mehr nicht.
Keine Ornaments übernommen. Die Tab-Leiste der App sitzt im Inhalt des Window statt außerhalb davon. Das Ergebnis wirkt bei gleicher Inhaltsdichte gedrängter als bei einer visionOS-eigenen App.
Keine rein räumlichen Funktionen. Die App nutzt die dritte Achse für gar nichts: keine 3D-Modelle in einem Volume, keine Umgebungsszene in einem Space, keine z-positionierte UI über Attachments. Sie tut dasselbe wie auf dem iPad, nur schwebend.
Panel-Apps sind kein Scheitern; für Inhaltsgattungen, die von Spatial Computing nicht profitieren — eine Chat-App, eine Notiz-App, ein Einstellungswerkzeug —, sind sie sogar der richtige Zug. Zum Fehler wird es, wenn eine Panel-App ausgeliefert wird und zugleich visionOS-native Autorität für sie beansprucht wird. Der Beitrag Apple-Plattformmatrix aus derselben Reihe argumentiert, dass die Aufnahme einer Plattform eine Produktentscheidung ist; für visionOS lautet sie: „Soll sich diese App die räumliche Oberfläche verdienen, oder genügt das Panel?“
Häufige Fehlgriffe
Drei Muster, die schlechte visionOS-UX erzeugen:
Volumes, die in Wahrheit 2D-Inhalte mit Tiefenpolsterung sind. Eine „3D“-UI, die ein Volume füllt, darin aber flache Ebenen rendert, verschwendet wertvollen Raum. Volumes sind für 3D-Inhalte da; flache Inhalte gehören in ein Window.
Ein Immersionsgrad, der gegen den Anwendungsfall arbeitet. Eine Meditations-App, die ausschließlich .full anbietet, reißt die Benutzer für kurze Einheiten aus ihrer Umgebung. Eine Trainings-App, die nur .mixed kennt, geht für konzentrierte Übungen nicht weit genug. Passen Sie den Immersionsgrad an die tatsächliche Nutzungssituation an.
Ornaments, die dem Inhalt Konkurrenz machen. Ornaments sind ihrem Wesen nach peripher. Ein Ornament, das zentrale Aufmerksamkeit fordert — blinkende Farben, animierte Bewegung —, verfehlt seinen Zweck. Setzen Sie Ornaments für ruhige Bedienelemente ein, die sich mit einem Blick erfassen lassen.
Was dieses Muster für visionOS-Apps bedeutet
Drei Erkenntnisse.
-
Wählen Sie den Szenentyp nach dem Denkmodell der Benutzer, nicht danach, was am einfachsten ist. Eine flache Liste von Objekten ist ein Window. Ein 3D-Modell, das begutachtet wird, ist ein Volume. Eine Umgebung, die die Benutzer umschließt, ist ein Immersive Space. Diese Typen in einer App zu mischen — ein Window, aus dem sich bei Bedarf ein Volume öffnet, ein Immersive Space, der über eine Schaltfläche im Window erreichbar ist — ist das visionOS-eigene Muster.
-
Nutzen Sie Ornaments für Symbolleisten und ergänzende UI. Über Ornaments teilt visionOS mit: „Diese UI ist ergänzend.“ Symbolleisten im Inhalt des Window wirken dagegen wie iPad-auf-Vision. Der Aufwand für die Umstellung ist klein, der optische Unterschied groß.
-
Setzen Sie Attachments für UI innerhalb der RealityView-Szene ein. Labels an 3D-Objekten, Schaltflächen neben virtuellen Inhalten, kontextbezogene Anzeigen. Die Brücke zwischen SwiftUI und 3D-Raum ist gebaut; der Fehler besteht darin, sie nicht zu nutzen und stattdessen bei selbstgebautem 3D-Textrendering zu landen.
Die vollständige Reihe zum Apple-Ökosystem: typisierte App Intents; MCP-Server; die Frage des Routings; Foundation Models; die Unterscheidung zwischen Laufzeit-LLM und Werkzeug-LLM; drei Oberflächen; das Muster der einen Wahrheitsquelle; zwei MCP-Server; Hooks für die Apple-Entwicklung; Live Activities; der watchOS-Laufzeitvertrag; SwiftUI von innen; RealityKits räumliches Denkmodell; Schemadisziplin in SwiftData; Liquid-Glass-Muster; Ausliefern über mehrere Plattformen; die Plattformmatrix; das Vision-Framework; Symbol Effects; Core-ML-Inferenz auf dem Gerät; die Writing-Tools-API; Swift Testing; das Privacy Manifest im Detail; Barrierefreiheit als Plattformfunktion; die Typografie von SF Pro; worüber ich bewusst nicht schreibe. Der Einstieg liegt bei der Reihe zum Apple-Ökosystem. Für den größeren Zusammenhang von iOS und KI-Agenten siehe den Leitfaden zur iOS-Agentenentwicklung.
FAQ
Worin unterscheiden sich ein Volume und ein Immersive Space?
Ein Volume ist ein begrenzter 3D-Bereich, der im Shared Space neben anderen Apps existiert. Man kann um ihn herumgehen, das System rahmt ihn ein, und die Fenster anderer Apps bleiben sichtbar. Ein Immersive Space umgibt die Benutzer, übernimmt die Umgebung und verhindert die gleichzeitige Nutzung anderer Apps. Volumes stehen für „dieses 3D-Objekt ansehen“, Spaces für „in dieser Umgebung sein“.
Kann ich mehrere Volumes gleichzeitig öffnen?
Ja. Mehrere WindowGroup-Szenen mit .volumetric können gleichzeitig geöffnet sein, jede mit eigener Größe und eigenem Inhalt. Das System platziert sie unabhängig voneinander im Raum.
Kann ich mehrere Immersive Spaces gleichzeitig öffnen?
Nein. Pro App kann immer nur ein Immersive Space aktiv sein. Für den Wechsel muss der aktuelle Space ausdrücklich über @Environment(\.dismissImmersiveSpace) geschlossen und der neue über @Environment(\.openImmersiveSpace) geöffnet werden.
Ist die Größe eines Volume wirklich unveränderlich?
Die Grenzen eines Volume stehen standardmäßig beim Öffnen fest. Die visionOS-HIG begründet das damit, dass Volumes bestimmte 3D-Inhalte mit bewusst gewählten Grenzen darstellen und beliebiges Skalieren durch die Benutzer den beabsichtigten Maßstab verzerren würde. Ab visionOS 2 gibt es ein Opt-in für skalierbare Volumes über .windowResizability(.contentSize) und verwandte APIs, sodass Apps, die veränderbare räumliche Container brauchen, diese anfordern können. Die meisten Volumes werden mit der festen Voreinstellung ausgeliefert, die die HIG für Inhalte mit konkretem Maßstab — eine virtuelle Skulptur, ein physisch maßstabsgetreues Modell — weiterhin empfiehlt.
Wie füge ich einem visionOS-Window eine Tab-Leiste hinzu?
Verwenden Sie eine TabView innerhalb des Window für Tabs im Inhalt (das Muster im iPad-Stil), oder ein Ornament mit eigenen Schaltflächenreihen für eine visionOS-eigene, periphere Tab-UI. Den Ornament-Weg gehen Apples eigene Apps (Music, Mail), und er fühlt sich für visionOS-Benutzer am nativsten an.
Können RealityView-Attachments mit Hand-Tracking zusammenarbeiten?
Ja. Einmal platziert, sind die Attachments 3D-Entitäten und nehmen am selben Gesten- und Hit-Testing-System teil wie andere RealityKit-Entitäten. Tipp-, Zieh- und Hover-Gesten lassen sich über die Standard-Gestenmodifier von SwiftUI an ihnen anbringen; der RealityKit-Beitrag aus derselben Reihe behandelt die Muster für die Hand-Tracking-Anbindung.
Referenzen
-
Apple Developer: Meet SwiftUI for spatial computing (WWDC 2023, Session 10109). Einführung von WindowGroup, volumetrischer WindowGroup und ImmersiveSpace als den drei visionOS-Szenentypen. ↩
-
Apple Developer Documentation:
ImmersionStyle. Die drei Immersionsgrade (.mixed,.progressive,.full) und die API des Modifiers.immersionStyle(selection:in:). ↩ -
Apple Developer Documentation:
ornament(visibility:attachmentAnchor:contentAlignment:ornament:). Der SwiftUI-View-Modifier, der einem Window eine Ornament-UI-Ebene am angegebenen Anker hinzufügt. ↩ -
Apple Developer: Go beyond the window with SwiftUI (WWDC 2023, Session 10111). Die Session zu Volumes, Immersive Spaces und den Mustern, mit denen man auf visionOS über flache Panel-UI hinauskommt. ↩
-
Apple Developer Documentation: Creating an immersive space in visionOS with SwiftUI. Der durchgängige Leitfaden zum Definieren und Öffnen immersiver Spaces. ↩