← Tous les articles

visionOS — les motifs spatiaux au-delà de la fenêtre

La plupart des apps qui arrivent sur visionOS empruntent le chemin de compatibilité « Designed for iPad » d’Apple : le binaire iPad existant s’exécute comme un panneau plat suspendu dans l’espace 3D, et le développeur coche une case au lieu de construire une expérience native visionOS. Le chemin ne pose pas de problème à l’utilisateur (l’app fonctionne), mais il brade la plateforme. La surface native de visionOS offre aux développeurs trois méthodes de présentation (fenêtres, volumes et espaces immersifs) ainsi que des primitives structurelles d’interface (ornements, attachements) dont le SDK iPad ne dispose pas4. Les apps qui les adoptent paraissent natives ; les autres se lisent comme de l’iPad transposé sur Vision.

Cet article parcourt le vocabulaire spatial en s’appuyant sur la documentation d’Apple. L’angle retenu est « ce que la plateforme offre réellement à une app SwiftUI » plutôt qu’une introduction à visionOS. L’article RealityKit et le modèle mental spatial de la série traite la couche de contenu 3D ; celui-ci traite la surface SwiftUI qui la contient.

En bref

  • Une app visionOS compose trois types de scènes : WindowGroup (fenêtres), WindowGroup avec .windowStyle(.volumetric) (volumes) et ImmersiveSpace (espaces immersifs)1.
  • Une fenêtre est un plan 2D ; un volume est une région 3D bornée ; un espace immersif entoure l’utilisateur. Chacun obéit à des règles différentes : la taille d’un volume est immuable après création, un espace immersif exige une ouverture et une fermeture explicites, une fenêtre est celle qui se rapproche le plus de l’iPad.
  • L’immersion se décline en trois styles : .mixed (le contenu coexiste avec la pièce), .full (la pièce est remplacée par un environnement virtuel), .progressive (entre-deux, avec un ancrage périphérique)2.
  • Les ornements sont des plans d’interface parallèles à une fenêtre et placés en avant sur l’axe z. C’est ainsi que visionOS traite les barres d’outils et les barres d’onglets3. Les attachements intègrent des vues SwiftUI à l’intérieur du contenu 3D d’une RealityView : le pont entre l’interface plate et la géométrie spatiale.
  • L’anti-motif de l’« app panneau » : livrer l’interface iPad sous forme de fenêtre, sans volume, sans espace ni ornement. L’utilisateur peut se servir de l’app, mais la vraie valeur de la plateforme reste inexploitée.

Les trois types de scènes

Le corps App d’une app visionOS compose ses scènes à partir de trois classes. Chacune correspond à un modèle mental distinct chez l’utilisateur.

Les fenêtres : le plan 2D

WindowGroup produit une fenêtre 2D dotée par défaut du cadre de verre visionOS. La fenêtre est positionnée dans l’espace (le système la place devant le regard de l’utilisateur) ; l’utilisateur la déplace ou la redimensionne par les gestes système standard. Du point de vue de SwiftUI, une fenêtre est l’équivalent visionOS d’une fenêtre macOS : une surface de contenu plate habillée d’un matériau de verre sensible à la profondeur.

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

Par défaut, la fenêtre entoure son contenu d’un matériau de verre. Les apps qui veulent une surface entièrement transparente utilisent .windowStyle(.plain) :

WindowGroup {
    ContentView()
}
.windowStyle(.plain)

Les fenêtres de style plain perdent le cadre de verre système. À réserver aux cas où le contenu fournit son propre conteneur visuel ; sinon, la valeur par défaut est la bonne.

Les volumes : la région 3D bornée

Un volume est une région 3D qui accueille du contenu sensible à la profondeur : un modèle, une scène à plusieurs objets, une interface qui gagne à disposer d’un troisième axe. La scène volumétrique est elle aussi un WindowGroup, avec un style différent :

WindowGroup(id: "globe") {
    GlobeView()
}
.windowStyle(.volumetric)
.defaultSize(width: 0.6, height: 0.6, depth: 0.6, in: .meters)

Le modificateur .defaultSize(width:height:depth:in:) précise les limites du volume en unités du monde réel (mètres). Par défaut, ces limites sont figées à l’ouverture : l’utilisateur peut déplacer le volume, mais pas le redimensionner. visionOS 2 et suivants ont ajouté une voie facultative via .windowResizability(.contentSize) et les API associées, pour les apps qui souhaitent des volumes redimensionnables par l’utilisateur ; la taille fixe par défaut reste le cas le plus courant. Conséquence : choisissez soigneusement la taille par défaut, car la plupart des volumes ne sont pas redimensionnables tant que le développeur ne l’a pas explicitement demandé.

Les bons candidats au volume sont les apps où la borne spatiale fait partie de l’expérience : une sculpture virtuelle autour de laquelle on marche, un mètre ruban épinglé à un vrai mur, une scène d’entraînement avec des cibles échelonnées en profondeur. Les apps qui veulent seulement une toile plus large ne gagnent rien à passer au volume ; une fenêtre plus grande est la bonne réponse.

Les espaces immersifs : l’enveloppement

Un ImmersiveSpace est une scène qui occupe l’environnement autour de l’utilisateur5. Contrairement à une fenêtre ou à un volume — tous deux visibles aux côtés des autres apps dans l’espace partagé —, un espace immersif prend possession de l’environnement et empêche l’usage simultané des fenêtres des autres apps.

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }

        ImmersiveSpace(id: "training") {
            TrainingScene()
        }
        .immersionStyle(selection: .constant(.mixed), in: .mixed, .progressive, .full)
    }
}

Le modificateur .immersionStyle(...) choisit le degré d’expérience :

  • .mixed. Le contenu virtuel apparaît aux côtés de la pièce réelle. À utiliser lorsque l’utilisateur tire parti des deux contextes.
  • .progressive. Une immersion partielle que la Digital Crown permet de doser. L’utilisateur conserve la perception périphérique de la pièce pendant que la vue centrale devient virtuelle.
  • .full. La pièce est remplacée par un environnement virtuel. Réservé aux expériences pleinement immersives : méditation, simulations d’entraînement, jeu.

L’ouverture d’un espace immersif est explicite. L’app appelle @Environment(\.openImmersiveSpace) avec l’id de l’espace ; le système prend en charge l’animation de transition et la fermeture de tout espace en conflit :

@Environment(\.openImmersiveSpace) var openImmersiveSpace
@Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace

Button("Start Session") {
    Task {
        await openImmersiveSpace(id: "training")
    }
}

Un seul espace immersif peut être actif à la fois par app. Passer d’un espace à un autre (de .mixed à .full, par exemple) impose de fermer explicitement l’ancien avant d’ouvrir le nouveau.

Les ornements : les plans d’interface autour d’une fenêtre

Les ornements sont des vues SwiftUI accrochées au bord d’une fenêtre, positionnées légèrement en avant du plan de celle-ci sur l’axe z. C’est ainsi que visionOS traite les barres d’outils, les barres d’onglets et les contrôles annexes. Le système les emploie partout : les commandes de lecture dans TV, le contrôle segmenté dans Musique, la barre d’outils dans 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()
    }

Le paramètre attachmentAnchor: indique où se place l’ornement par rapport à la fenêtre : .scene(.top), .scene(.bottom), .scene(.leading), .scene(.trailing). Le traitement visuel de l’ornement incombe au développeur ; .glassBackgroundEffect() produit le matériau de verre natif de visionOS, assorti au cadre de la fenêtre.

Les ornements résolvent un vrai problème sur visionOS : placer les contrôles dans la fenêtre encombre le contenu ; les placer dans une fenêtre séparée oblige l’utilisateur à réorienter son regard. Un ornement flotte dans la vision périphérique, reste ciblable par le regard, mais ne dispute pas la vue centrale au contenu principal.

Les attachements de RealityView : SwiftUI dans l’espace 3D

Lorsqu’une app a besoin de vues SwiftUI à l’intérieur d’une scène 3D — une étiquette sur un modèle, un bouton flottant près d’un objet virtuel, un relevé de mesure épinglé à une surface réelle —, le pont est le mécanisme d’attachements de RealityView.

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()
    }
}

La closure attachments: déclare des vues SwiftUI munies d’identifiants stables. À l’intérieur de la closure principale de RealityView, attachments.entity(for:) récupère la vue sous forme d’Entity 3D positionnable dans l’espace de coordonnées de la scène. La vue participe au cycle de mise à jour de SwiftUI (un changement d’état la redessine) tout en étant rendue comme un plan texturé dans la scène 3D.

Le mécanisme convient à toute interface intégrée au monde : une étiquette qui suit un objet en mouvement, une annotation de mesure, un bouton contextuel. L’écriture de la vue SwiftUI ne change pas ; le positionnement 3D se joue au niveau de la RealityView.

L’anti-motif de l’« app panneau »

L’erreur de livraison la plus fréquente sur visionOS, c’est l’app panneau : une app iPad qui atterrit sur visionOS par la compatibilité « Designed for iPad » et se livre comme une fenêtre unique, sans volume, sans espace immersif et sans ornements. L’app fonctionne, mais elle ne mérite pas la plateforme.

Trois signaux trahissent une app panneau :

Une seule scène, de type fenêtre. Pas de .windowStyle(.volumetric), aucun ImmersiveSpace déclaré. L’app est une surface plate, un point c’est tout.

Aucun ornement adopté. La barre d’onglets vit à l’intérieur du contenu de la fenêtre plutôt qu’à l’extérieur. Le résultat est plus encombré qu’une app native visionOS à densité de contenu équivalente.

Aucune fonctionnalité proprement spatiale. L’app n’exploite le troisième axe pour rien : ni modèle 3D dans un volume, ni scène environnementale dans un espace, ni interface positionnée sur l’axe z via des attachements. Elle fait exactement ce qu’elle faisait sur iPad, en flottant.

Les apps panneaux ne sont pas des échecs : c’est le bon choix pour les catégories de contenu qui ne tirent rien de l’informatique spatiale — une app de messagerie, une app de notes, un utilitaire de réglages. Le vrai travers, c’est de livrer une app panneau et de revendiquer pour elle une autorité native visionOS. L’article La matrice des plateformes Apple de la série défend l’idée que l’inclusion d’une plateforme est une décision produit ; pour visionOS, la décision s’énonce ainsi : « cette app doit-elle mériter la surface spatiale, ou le panneau suffit-il ? »

Les échecs courants

Trois motifs produisent une UX visionOS médiocre :

Des volumes qui ne contiennent en réalité que du contenu 2D, simplement espacé en profondeur. Une interface « 3D » qui remplit un volume mais n’y affiche que des plans plats gaspille l’espace disponible. Les volumes sont faits pour le contenu 3D ; le contenu plat a sa place dans une fenêtre.

Un style d’immersion en désaccord avec l’usage. Une app de méditation livrée uniquement en .full arrache l’utilisateur à son environnement pour des séances courtes. Une app d’entraînement livrée uniquement en .mixed ne va pas assez loin pour des exercices demandant une concentration totale. Accordez le style d’immersion à la séance réelle de l’utilisateur.

Des ornements qui concurrencent le contenu. Les ornements sont périphériques par conception. Un ornement qui exige l’attention centrale — couleur clignotante, mouvement animé — trahit sa raison d’être. Réservez-les à des contrôles stables, saisissables d’un coup d’œil.

Ce que ce motif signifie pour les apps visionOS

Trois enseignements.

  1. Choisissez le type de scène d’après le modèle mental de l’utilisateur, pas d’après la facilité. Une liste plate d’éléments, c’est une fenêtre. Un modèle 3D que l’utilisateur inspecte, c’est un volume. Un environnement enveloppant, c’est un espace immersif. Les mêler dans une seule app — une fenêtre avec un volume ouvert à la demande, un espace immersif accessible depuis un bouton de la fenêtre — voilà le motif natif de visionOS.

  2. Adoptez les ornements pour les barres d’outils et l’interface annexe. Les ornements sont la manière dont visionOS signale « cette interface est secondaire » ; loger les barres d’outils dans le contenu de la fenêtre se lit comme de l’iPad transposé sur Vision. L’intégration est légère, la différence visuelle considérable.

  3. Utilisez les attachements pour l’interface intégrée au monde dans RealityView. Étiquettes sur objets 3D, boutons près du contenu virtuel, relevés contextuels. Le pont entre SwiftUI et l’espace 3D est déjà résolu ; le travers consiste à ne pas s’en servir et à finir avec du texte 3D bricolé à la main.

La série Écosystème Apple au complet : les App Intents typés ; les serveurs MCP ; la question du routage ; Foundation Models ; la distinction entre LLM d’exécution et d’outillage ; les trois surfaces ; le motif de la source unique de vérité ; Deux serveurs MCP ; les points d’accroche pour le développement Apple ; les Live Activities ; l’environnement d’exécution watchOS ; les rouages internes de SwiftUI ; le modèle mental spatial de RealityKit ; la discipline de schéma SwiftData ; les motifs Liquid Glass ; la livraison multiplateforme ; la matrice des plateformes ; le framework Vision ; les Symbol Effects ; l’inférence Core ML sur l’appareil ; l’API Writing Tools ; Swift Testing ; le Privacy Manifest en profondeur ; l’accessibilité comme plateforme ; la typographie SF Pro ; ce que je refuse d’écrire. Le sommaire se trouve dans la série Écosystème Apple. Pour un contexte plus large sur iOS et les agents IA, consultez le guide Développement iOS avec des agents.

FAQ

Quelle différence entre un volume et un espace immersif ?

Un volume est une région 3D bornée qui vit dans l’espace partagé, aux côtés des autres apps. L’utilisateur peut en faire le tour, le système l’encadre, et les fenêtres des autres apps restent visibles. Un espace immersif entoure l’utilisateur, prend possession de l’environnement et interdit l’usage simultané des autres apps. Le volume sert à « regarder cet objet 3D » ; l’espace, à « être dans cet environnement ».

Puis-je ouvrir plusieurs volumes en même temps ?

Oui. Plusieurs scènes WindowGroup en .volumetric peuvent être ouvertes simultanément, chacune avec sa taille et son contenu. Le système les positionne indépendamment dans l’espace.

Puis-je ouvrir plusieurs espaces immersifs en même temps ?

Non. Un seul espace immersif peut être actif à la fois par app. Passer d’un espace à un autre exige de fermer explicitement l’espace en cours avant d’ouvrir le nouveau, via @Environment(\.openImmersiveSpace) et @Environment(\.dismissImmersiveSpace).

La taille d’un volume est-elle vraiment immuable ?

Les limites d’un volume sont figées à l’ouverture par défaut ; le principe retenu par les HIG de visionOS est qu’un volume représente un contenu 3D précis, aux bornes intentionnelles, et qu’un redimensionnement arbitraire par l’utilisateur en fausserait l’échelle voulue. visionOS 2 et suivants ont ajouté une option pour le développeur, via .windowResizability(.contentSize) et les API associées, afin que les apps ayant besoin de conteneurs spatiaux redimensionnables puissent la demander. La plupart des volumes sont livrés avec la valeur fixe par défaut, que les HIG continuent de recommander pour tout contenu à échelle précise : sculpture virtuelle, maquette aux dimensions physiques.

Comment ajouter une barre d’onglets à une fenêtre visionOS ?

Utilisez une TabView à l’intérieur de la fenêtre pour des onglets intégrés au contenu (le motif façon iPad), ou un ornement avec des rangées de boutons personnalisées pour une interface d’onglets périphérique native visionOS. C’est la voie de l’ornement que suivent les apps d’Apple elles-mêmes (Musique, Mail) et celle qui paraît la plus naturelle aux utilisateurs de visionOS.

Les attachements de RealityView peuvent-ils interagir avec le suivi des mains ?

Oui. Une fois positionnés, les attachements sont des entités 3D à part entière et participent au même système de gestes et de test d’intersection (hit-testing) que les autres entités RealityKit. Les gestes de tap, de glissement et de survol s’y attachent par les modificateurs de gestes standard de SwiftUI ; l’article RealityKit de la série couvre les motifs d’intégration du suivi des mains.

Références


  1. Apple Developer : Meet SwiftUI for spatial computing (WWDC 2023, session 10109). Présentation de WindowGroup, du WindowGroup volumétrique et d’ImmersiveSpace comme les trois types de scènes visionOS. 

  2. Documentation Apple Developer : ImmersionStyle. Les trois styles d’immersion (.mixed, .progressive, .full) et l’API du modificateur .immersionStyle(selection:in:)

  3. Documentation Apple Developer : ornament(visibility:attachmentAnchor:contentAlignment:ornament:). Le modificateur de vue SwiftUI qui ajoute un plan d’interface ornemental à une fenêtre, avec l’ancrage indiqué. 

  4. Apple Developer : Go beyond the window with SwiftUI (WWDC 2023, session 10111). La session qui couvre les volumes, les espaces immersifs et les motifs permettant de dépasser l’interface en panneau plat sur visionOS. 

  5. Documentation Apple Developer : Creating an immersive space in visionOS with SwiftUI. Le guide de bout en bout pour définir et ouvrir des espaces immersifs. 

Articles connexes

RealityKit Et Le Modèle Mental Spatial

RealityKit est un système entité-composant-système, pas SwiftUI en 3D. Les ancres placent les entités dans l'espace réel…

20 min de lecture

RealityKit et Reality Composer Pro 3 en 2026

La WWDC26 a fait mûrir le pipeline spatial d'Apple : éclairage et tissu dans RealityKit, Reality Composer Pro 3 autonome…

19 min de lecture

Installer et mettre à jour Codex CLI : Mac, Linux, Windows

Toutes les façons d'installer, de mettre à jour, d'épingler et de désinstaller la CLI OpenAI Codex -- script d'installat…

22 min de lecture