RealityKit y el modelo mental espacial
SwiftUI en visionOS te da una ventana en el espacio 3D. RealityKit te da el resto de la habitación. La diferencia es el modelo mental, y el modelo mental es la arquitectura.
Un desarrollador de SwiftUI que llega a visionOS por primera vez tiende a construir las mismas formas que construiría en iOS: un WindowGroup con vistas dentro. El resultado es un panel plano flotando en el espacio. El panel está bien para muchas aplicaciones. La habitación que rodea al panel es lo que visionOS añade, y la habitación es el territorio de RealityKit.
RealityKit no es SwiftUI en 3D. La arquitectura es diferente en forma, no solo en dimensión. SwiftUI es un árbol de vistas tipado por valor con un DSL basado en result-builder sobre un sistema de observación; el trabajo del framework es calcular el siguiente render a partir del estado actual. RealityKit es un sistema entidad-componente (ECS) con un grafo de escena enraizado en anclajes que vinculan entidades virtuales a puntos de referencia del mundo real; el trabajo del framework es mantener una escena 3D mientras el usuario y el mundo se mueven a su alrededor. El mismo proyecto Swift podría usar ambos al mismo tiempo, y la frontera entre ellos es donde ocurren la mayoría de los errores de diseño espacial.
Esta publicación recorre el modelo mental espacial. Cinco formas concretas en que el modelo difiere de una ventana SwiftUI, y la pregunta de enrutamiento sobre cuándo cada framework es la respuesta correcta.
TL;DR
- RealityKit es un sistema entidad-componente (ECS). Una entidad es un nodo; los componentes son datos tipados adjuntos al nodo; los sistemas ejecutan lógica sobre las entidades que tienen combinaciones específicas de componentes.
- Los anclajes vinculan entidades virtuales a puntos de referencia del mundo real. RealityKit expone los objetivos de anclaje a través de
AnchoringComponent.Target(.world,.head,.hand(_:location:),.plane(...),.image(...),.referenceObject(...)). En visionOS, ARKit suministra las estructuras de anclaje subyacentes (WorldAnchor,HandAnchor,ImageAnchor,ObjectAnchor,PlaneAnchor) que ARKit reporta a través de los flujos de actualización de anclajes. - Una escena 3D no es un árbol de vistas. El bucle de renderizado es continuo, el grafo de escena muta con el tiempo, y la capa de renderizado está dirigida por GPU (Metal por debajo) en lugar de basarse en diferencias.
RealityViewes el puente de SwiftUI. Coloca una escena de RealityKit dentro de un árbol de vistas SwiftUI; la frontera es unidireccional (SwiftUI aloja a RealityKit, no al revés).- La regla de enrutamiento: si el usuario quiere una ventana, lanza SwiftUI. Si el usuario quiere la habitación, lanza RealityKit. Las aplicaciones que necesitan ambas colocan un
RealityViewdentro de una ventana SwiftUI y aceptan que las dos mitades se coordinan explícitamente.
Cinco diferencias respecto a una ventana SwiftUI
La forma cambia en el momento en que colocas algo fuera del panel. Cinco diferencias importan.
1. Entidad-Componente-Sistema, no Vista-Body-Estado
Una vista SwiftUI es un tipo tipado por valor con una propiedad computada body y estado respaldado por property-wrappers.1 El framework vuelve a ejecutar el body cuando cambia el estado; la diferencia se alimenta al renderizador.
Una entidad RealityKit es un objeto tipado por referencia que se sitúa en un grafo de escena. Los componentes son structs tipados adjuntos a las entidades (ModelComponent, Transform, CollisionComponent, PhysicsBodyComponent, tipos Component personalizados que tú defines).2 Los sistemas son tipos que se conforman al protocolo System; el framework ejecuta cada sistema registrado una vez por frame, y System.update(context:) (típicamente mutating en un struct) es donde el sistema lee y escribe los componentes en las entidades que coinciden con su consulta.
import RealityKit
let cube = Entity()
cube.components.set(ModelComponent(
mesh: .generateBox(size: 0.1),
materials: [SimpleMaterial(color: .blue, isMetallic: false)]
))
cube.components.set(InputTargetComponent())
cube.components.set(CollisionComponent(shapes: [.generateBox(size: [0.1, 0.1, 0.1])]))
El cubo no tiene un body. El cubo tiene un conjunto de componentes. Añadir InputTargetComponent y CollisionComponent es lo que hace que el cubo responda a los gestos; quítalos y los gestos pasarán directamente a la entidad que esté detrás. Añadir PhysicsBodyComponent es lo que hace que el cubo caiga bajo la gravedad; quítalo y el cubo flotará. La composición de componentes determina el comportamiento de la entidad.
El cambio mental: en SwiftUI, describes lo que debería estar en pantalla como una función del estado. En RealityKit, describes lo que una entidad es (sus componentes) y dejas que los sistemas decidan qué le sucede.
2. Anclajes, no coordenadas
El sistema de coordenadas de una vista SwiftUI es la ventana. La posición 0,0 es la esquina superior izquierda; las posiciones están en puntos; el frame de la vista es su espacio. La ventana es el universo.
El sistema de coordenadas de una escena RealityKit depende de su anclaje. La capa de anclaje tiene dos caras. El AnchorEntity de RealityKit (controlado por un AnchoringComponent.Target) es a lo que adjuntas una entidad; las estructuras de anclaje de ARKit son los datos subyacentes que el sistema usa para mantener el objetivo sincronizado con el mundo real.3
Los objetivos de anclaje de RealityKit que utilizas dentro de un AnchorEntity o AnchoringComponent son:
.world(transform:): un punto en el espacio del mundo real definido por una transformación.head: bloqueado a la pose de cabeza del usuario; la entidad sigue la mirada del usuario.hand(_:location:): bloqueado a una articulación específica de la mano (palma, punta del dedo, muñeca, etc.).plane(...): bloqueado a una superficie horizontal o vertical detectada (mesa, pared, suelo).image(...)/.referenceImage(...): bloqueado a una imagen 2D reconocida en el entorno.referenceObject(...): bloqueado a un objeto 3D reconocido del mundo real
En visionOS, ARKit suministra los datos de anclaje subyacentes a través de las structs WorldAnchor, HandAnchor, ImageAnchor, ObjectAnchor y PlaneAnchor, entregadas mediante los proveedores de actualización de anclajes de ARKitSession. (El seguimiento corporal es exclusivo de iOS/iPadOS en la superficie de seguimiento corporal de Apple; visionOS no expone .body como objetivo de anclaje de RealityKit.)
El anclaje es lo que hace que la escena sea “real”. Un tablero de ajedrez virtual ubicado en un objetivo .plane correspondiente a la mesa del usuario permanece sobre la mesa cuando el usuario camina a su alrededor; un tablero de ajedrez ubicado en coordenadas fijas relativas a un objetivo .head sigue la cabeza del usuario y se siente como una alucinación.
El cambio mental: la posición no es un número. La posición es cuál es el anclaje y dónde está la entidad respecto al anclaje. Un objeto virtual sin un anclaje sensato es una alucinación; el anclaje es lo que le dice al usuario que el objeto pertenece a la habitación.
3. Bucle de renderizado continuo, no basado en diferencias
SwiftUI renderiza cuando cambia el estado. El framework decide cuándo se necesita un nuevo render y calcula el cambio mínimo del árbol. Entre renders, la pantalla es estática.
RealityKit ejecuta un bucle de simulación y renderizado basado en frames. El grafo de escena muta con el tiempo a medida que la física, los sistemas de animación y los manejadores de entrada actualizan las transformaciones de las entidades y los valores de los componentes, y el renderizador (respaldado por Metal) dibuja la escena activa en cada frame. La lógica por frame vive en System.update(context:); ese hook es la invitación del framework para mutar la escena en cada tick.4
El cambio mental: el tiempo es parte de la escena. Un body de vista SwiftUI que se ejecuta una sola vez está bien; una entidad RealityKit necesita considerar lo que sucede en el frame N+1, N+2, N+3. El método update(context:) en un System personalizado es donde escribes lógica por frame; el valor Component que mutas dentro de update es lo que el renderizador lee en la siguiente pasada.
4. RealityView es el puente, en una sola dirección
Las vistas SwiftUI componen otras vistas SwiftUI. Las entidades RealityKit componen otras entidades RealityKit. La frontera entre ambos es RealityView, un tipo de vista SwiftUI que aloja una escena de RealityKit.5
import SwiftUI
import RealityKit
struct ContentView: View {
var body: some View {
RealityView { content in
// Build the scene
let cube = Entity()
cube.components.set(ModelComponent(
mesh: .generateBox(size: 0.1),
materials: [SimpleMaterial(color: .blue, isMetallic: false)]
))
content.add(cube)
} update: { content in
// Mutate the scene in response to SwiftUI state changes
}
}
}
El closure make se ejecuta una vez cuando la vista aparece por primera vez. El closure update se ejecuta siempre que cambia el estado de SwiftUI del que depende la vista. Dentro de ambos closures, tienes acceso a la escena RealityKit a través del parámetro content; añades entidades, mutas transformaciones, registras sistemas.
La frontera es unidireccional. SwiftUI aloja a RealityKit. RealityKit no aloja a SwiftUI; no puedes poner una vista SwiftUI “dentro” de una entidad y esperar que se renderice como parte de la escena 3D del modo en que una subvista SwiftUI se renderiza dentro de un padre. La excepción son los attachments (en el parámetro attachments: de RealityView): declaras vistas SwiftUI con nombre, las recuperas como valores ViewAttachmentEntity, y las posicionas y escalas dentro de la escena 3D como cualquier otra entidad.5 Los attachments no son vistas SwiftUI incrustadas dentro de una entidad; son superficies SwiftUI 2D envueltas como entidades que el renderizador puede colocar en 3D. De forma predeterminada mantienen una orientación fija; si quieres que miren al portador, adjunta un BillboardComponent a la entidad de attachment.
5. Los gestos en 3D son diferentes
Los gestos de SwiftUI (.onTapGesture, DragGesture, etc.) operan en el espacio de pantalla. El sistema sabe dónde está el dedo respecto a la vista; el framework despacha basándose en hit-testing en 2D.
Los gestos de RealityKit operan en el espacio de la escena.6 El sistema sabe hacia dónde mira el usuario (el rayo de la mirada), dónde están las manos del usuario (articulaciones del seguimiento de manos), y con qué entidad la mirada + el toque se intersectan. El modelo de despacho es “el usuario miró esta entidad e hizo pinzar”; el equivalente a un toque.
Para que una entidad reciba gestos, necesita InputTargetComponent y un CollisionComponent que defina la geometría de hit-test. Sin InputTargetComponent, la entidad es invisible para el sistema de gestos; sin CollisionComponent, el sistema de gestos no tiene forma contra la cual hacer hit-test. Ambos deben estar presentes.
El cambio mental: los objetivos de gesto no son regiones de pantalla. Los objetivos de gesto son entidades 3D que han optado explícitamente por la entrada. El resto de la escena es “decoración a través de la cual el usuario puede mirar”.
Cuándo SwiftUI es suficiente
Una aplicación común de visionOS no necesita RealityKit. Tres patrones donde SwiftUI por sí solo es la respuesta correcta:
Aplicaciones con forma de ventana sin contenido espacial. Un temporizador de meditación, un cuaderno, un panel de configuración, una interfaz de chat. La aplicación es información que lees o con la que interactúas a través de affordances 2D. Ponerla en un WindowGroup y mantenerla plana es la decisión correcta. visionOS trata las ventanas SwiftUI como paneles de vidrio flotantes con cromo del sistema; el usuario obtiene una experiencia de lectura cómoda sin que tú escribas una línea de RealityKit.
Aplicaciones multi-ventana que componen paneles planos en el espacio. Un editor de código con ventanas separadas para el editor, la terminal y la documentación. El usuario quiere las ventanas dispuestas en el espacio 3D (a la izquierda, a la derecha, detrás), pero cada ventana es en sí misma una vista SwiftUI. La disposición 3D es trabajo del SO; los paneles son planos.
Visores de documentación, galerías de fotos, reproductores de video. Contenido que el usuario consume a través del panel. El panel es la superficie de renderizado; la tercera dimensión es solo la posición espacial del panel en la habitación.
La regla: si el contenido es 2D (texto, imágenes, video, controles), el framework correcto es SwiftUI. La tercera dimensión es donde se posiciona el panel, no lo que se renderiza dentro de él.
Cuándo se requiere RealityKit
Los casos donde SwiftUI no es suficiente:
Contenido 3D alrededor del cual el usuario puede caminar. Un objeto virtual sobre la mesa del usuario (un coche modelo, una escultura, un edificio). El objeto tiene volumen; el usuario puede moverse a su alrededor; el objeto debe ocluirse correctamente con la habitación. El framework correcto es RealityKit, anclado a un objetivo .plane.
UI espacial que responde a la habitación. Botones que flotan sobre un teclado del mundo real, anotaciones adjuntas a un objeto del mundo real, una cinta métrica virtual extendida a lo largo de una pared real. La posición de la UI está determinada por la geometría del mundo, no por el espacio de coordenadas de una ventana. Los anclajes de RealityKit hacen el vínculo; los attachments de SwiftUI dentro de un RealityView proveen las affordances 2D.
Simulación espacial continua. Una bandada de pájaros, una pelota rodando por el suelo, una simulación de fluidos, cualquier cosa donde el estado de la escena evolucione con el tiempo. El bucle de renderizado continuo es la herramienta correcta; el renderizador basado en diferencias de SwiftUI perdería frames o consumiría batería.
Interacciones con seguimiento de manos. Pellizcar para agarrar, escalar con dos manos, dibujar en el aire. El modelo de entrada requiere el HandTrackingProvider de ARKit (con actualizaciones de HandAnchor) más un objetivo de anclaje .hand(_:location:); SwiftUI no expone esa superficie.
AR con seguimiento corporal. Reflejar la pose del usuario sobre un personaje virtual, rastrear el cuerpo del usuario para una aplicación de fitness, reconocer objetos del mundo real. La captura y la inferencia ocurren en ARKit (el compañero de bajo nivel de RealityKit); RealityKit renderiza el resultado.
La regla: si el contenido es 3D y vive en la habitación (volumétrico, anclado, simulado o impulsado por las manos), el framework correcto es RealityKit. SwiftUI es el cromo que lo rodea.
El patrón de composición
La mayoría de las aplicaciones visionOS no triviales terminan usando ambos. El patrón que se lanza bien:
- El cromo de la aplicación (configuración, navegación, listas, formularios, paneles inspectores) vive en ventanas SwiftUI.
- La escena espacial (el contenido volumétrico que el usuario manipula) vive en un
RealityViewdentro de su propia ventana o volumen. - Los dos se comunican a través del estado de SwiftUI. Un botón en un panel SwiftUI alterna un booleano
@State; el closureupdate:delRealityViewlee el booleano y muta la entidad en la escena. - Los cambios de estado del lado de RealityKit que necesitan emerger a SwiftUI pasan a través de callbacks que el closure
make:delRealityViewregistra (subscribe(to:)en el publicador de eventos de la escena).7
struct GalleryView: View {
@State private var selectedSculpture: SculptureID?
var body: some View {
HStack {
// SwiftUI side: list of sculptures
List(allSculptures) { sculpture in
Button(sculpture.name) {
selectedSculpture = sculpture.id
}
}
.frame(width: 300)
// RealityKit side: 3D rendering of the selected sculpture
RealityView { content in
// Build initial scene
} update: { content in
guard let id = selectedSculpture else {
content.entities.removeAll()
return
}
// Mutate scene to show the selected sculpture
presentSculpture(id, in: content)
}
}
}
}
La división es honesta sobre qué framework posee qué trabajo. SwiftUI posee la lista, los botones, el diseño, el estado. RealityKit posee el renderizado 3D, las entidades, la simulación continua. El estado cruza la frontera como un único valor @State; ningún framework se mete en el otro.
Lo que construiría diferente en mi stack
Tres patrones que se vuelven fáciles de reconocer una vez que has lanzado una escena espacial:
Anclaje primero, entidad después. Al diseñar una función, decide el anclaje antes que la geometría. Un instrumento virtual anclado a la mano del usuario es un producto distinto del mismo instrumento anclado a un objetivo .plane sobre la mesa. El anclaje decide la relación del usuario con el objeto; la geometría es detalle de implementación.
Componentes, no subclases. Es tentador subclasificar Entity para construir tipos de dominio como ChessPiece: Entity. El patrón de composición vence a la herencia siempre: una pieza de ajedrez es una Entity con un ChessPieceComponent (datos personalizados: color, tipo, posición), un ModelComponent (la malla 3D), un InputTargetComponent y un CollisionComponent. Los nuevos comportamientos son nuevos componentes, no nuevas subclases.
Sistemas para lógica transversal. Cuando diez entidades necesitan el mismo comportamiento (gravedad, respuesta de colisión, atenuación de audio, estado de gestos), escribe un System que opere sobre los componentes relevantes. El sistema se ejecuta una vez por frame a través de todas las entidades coincidentes. La alternativa (poner la lógica en cada entidad) produce el bug de n-veces-por-n-frames que el patrón ECS se inventó para evitar.
Cuándo RealityView es la respuesta incorrecta
Algunos casos en los que recurrir a RealityView es la decisión equivocada:
Una sola imagen 3D, sin interacción. Un logo o render de producto 3D estático. Usa una vista SwiftUI Model3D en su lugar.8 Model3D es la ruta económica para “carga un USDZ y muéstralo”; RealityView es para escenas que construyes y mutas.
Aplicaciones iOS con superposiciones AR sencillas. El ARView de ARKit (la superficie más antigua) o la integración de ARView en el lado iOS de RealityKit suele ser la decisión correcta cuando la experiencia AR es una función dentro de una aplicación iOS más grande. RealityView es nativo de Swift y SwiftUI y vive bien dentro de SwiftUI; los flujos de trabajo más antiguos de ARView son a veces más simples cuando el resto de la aplicación es UIKit.
Dibujo 2D sobre un panel. Una pizarra, una herramienta de anotación de fotos, un editor de formas planas. La herramienta correcta es Canvas (la superficie de dibujo respaldada por Metal de SwiftUI) o MetalView. RealityView es excesivo si no estás construyendo en el espacio 3D.
Lo que el patrón significa para las aplicaciones que se lanzan en visionOS 2+
Tres conclusiones.
-
RealityKit y SwiftUI se componen; no se colapsan. Usa SwiftUI para el cromo con forma de ventana y las affordances 2D; usa RealityKit para el contenido 3D con forma de habitación. La frontera es
RealityView, y la frontera es unidireccional. -
El modelo mental es ECS más anclajes. Una entidad es aquello de lo que está compuesta. Un anclaje decide cómo la entidad se relaciona con el espacio real del usuario. El par (componentes, anclaje) es la unidad de diseño.
-
El bucle de renderizado es continuo. El tiempo es parte de la escena. La lógica por frame va en
System.update(context:); la lógica por cambio de estado va enRealityView.update:. Mezclar las dos capas (escribir lógica por frame en el body de SwiftUI, escribir lógica dirigida por estado enSystem.update) es el error de arquitectura más común.
El cluster completo de Apple Ecosystem: App Intents tipados para Apple Intelligence; servidores MCP para agentes cross-LLM; la pregunta de enrutamiento entre ellos; Foundation Models para LLM en el dispositivo y el protocolo Tool; Live Activities para la máquina de estados de la pantalla de bloqueo de iOS; el contrato del runtime de watchOS en Apple Watch; internals de SwiftUI para el sustrato del framework; patrones de Liquid Glass para la capa visual; lanzamiento multi-plataforma para el alcance entre dispositivos. El hub está en la Serie Apple Ecosystem. Para un contexto más amplio sobre iOS con agentes de IA, consulta la guía de iOS Agent Development.
Preguntas frecuentes
¿Es RealityKit un reemplazo de SwiftUI en visionOS?
No. RealityKit y SwiftUI se componen. SwiftUI maneja ventanas 2D, controles y cromo; RealityKit maneja escenas 3D ancladas a puntos de referencia del mundo real. La mayoría de las aplicaciones visionOS no triviales usan ambos, con RealityView como el puente que coloca una escena de RealityKit dentro de un árbol de vistas SwiftUI.
¿Cuándo debería usar RealityView frente a Model3D?
Usa Model3D para mostrar un único activo 3D estático (un archivo USDZ, un render de un solo producto). Usa RealityView para construir o mutar una escena 3D a lo largo del tiempo (múltiples entidades, física, gestos, seguimiento de manos, contenido anclado). Model3D es la ruta económica; RealityView es la superficie ECS completa.
¿Cuál es la diferencia entre una Entity y un Component en RealityKit?
Una entidad es un nodo en el grafo de escena. Un componente son datos tipados adjuntos al nodo. ModelComponent le da a la entidad una malla; InputTargetComponent la hace elegible para gestos; CollisionComponent define la geometría de hit-test; PhysicsBodyComponent la hace responder a la gravedad. Los tipos Component personalizados que tú defines contienen datos de dominio. El comportamiento es composición sobre herencia: el comportamiento de una entidad es la suma de sus componentes.
¿Qué son los anclajes y por qué importan?
Los anclajes vinculan contenido virtual a puntos de referencia del mundo real: la cabeza del usuario, la mano, una superficie detectada, una imagen reconocida, un objeto reconocido o un punto persistente del mundo. El anclaje decide la relación del usuario con la entidad. Un objeto virtual sobre un objetivo .plane (la mesa) permanece quieto cuando el usuario camina alrededor; un objeto virtual sobre un objetivo .head sigue la cabeza del usuario. Elegir el anclaje correcto es la primera decisión de diseño en una función espacial.
¿Puede RealityKit ejecutarse en iOS, no solo en visionOS?
Sí. RealityKit se lanza en iOS, iPadOS, macOS y visionOS. Las experiencias AR impulsadas por ARKit usan la superficie iOS de RealityKit. La superficie de visionOS añade tipos de anclaje específicos del espacio (cabeza, mano, mundo) que iOS no expone; el patrón ECS central es compartido.
Referencias
-
Análisis del autor en What SwiftUI Is Made Of, 30 de abril de 2026, que cubre el árbol de vistas tipado por valor, el DSL basado en result-builder y el sistema de observación. ↩
-
Apple Developer, “RealityKit” y “RealityKit Systems”. La arquitectura Entity / Component / System y los tipos de componentes estándar (ModelComponent, Transform, CollisionComponent, PhysicsBodyComponent, InputTargetComponent). ↩
-
Apple Developer, “AnchorEntity”, “AnchoringComponent”, “Scene content anchors”, y “Anchor” de ARKit. Los objetivos de anclaje de RealityKit (
.world,.head,.hand(_:location:),.plane,.image,.referenceObject) y las structs de anclaje de ARKit que suministran los datos subyacentes en visionOS (WorldAnchor,HandAnchor,ImageAnchor,ObjectAnchor,PlaneAnchor). ↩ -
Apple Developer, “RealityKit Systems” y la sesión de WWDC 2024 “Build a great visionOS app”. La simulación y el renderizado de RealityKit dirigidos por frames, además del hook por frame
System.update(context:). ↩ -
Apple Developer, “RealityView”, “RealityViewAttachments”, y “BillboardComponent”. El puente de SwiftUI hacia RealityKit, el patrón de recuperación de
ViewAttachmentEntity, y el comportamiento opcional de billboard cuando un attachment 2D debe mirar al portador. ↩↩ -
Apple Developer, “Adding 3D content to your app” y “InputTargetComponent”. El despacho de gestos en escenas espaciales; el rol de
InputTargetComponentyCollisionComponentcomo el par de opt-in para entrada. ↩ -
Apple Developer, “Scene” y el publicador de eventos basado en Combine
subscribe(to:on:_:)que permite que los cambios de estado del lado de RealityKit emerjan de vuelta a SwiftUI a través de callbacks registrados en el closuremake:. ↩ -
Apple Developer, “Model3D”. La vista SwiftUI para mostrar un activo de modelo; la ruta económica antes de recurrir a la superficie ECS completa de RealityKit. ↩