One Logo Pool Ball
RealityFoundation · IOS API REFERENCE

PortalComponent

struct · iOS 18.0+ · SDK 27.1

struct PortalComponent

A component that turns mesh surfaces into portals to a different world. A RealityKit portal defines a way to look into a different, immersive world. You define an entity as a portal when it also has a ``ModelComponent`` that contains a mesh part with ``PortalMaterial``. To create a portal, set its ``targetEntity`` property to an entity with a ``WorldComponent``. Entities under that world only render within the portal. ### Quick start On iOS 27, macOS 27, tvOS 27, visionOS 27, and later, ``makePortal(surfaceStyle:boundaryStyle:boundaryMode:)`` creates a configured portal entity and its target world entity in a single call: ```swift let portal = PortalComponent.makePortal( surfaceStyle: .init(width: 0.5, height: 0.5), boundaryStyle: .infinitePlane(), boundaryMode: .clippingAndCrossing ) content.add(portal.worldEntity) content.add(portal.portalEntity) ``` To configure existing entities, use ``configure(world:portalEntity:surfaceStyle:boundaryStyle:boundaryMode:)``. ### Manual construction On earlier OS releases, or when you need direct control over the portal's mesh, material, or boundary geometry, set the components yourself: ```swift let world = Entity() world.components.set(WorldComponent()) let portal = Entity() portal.components.set( ModelComponent( mesh: .generatePlane(width: 0.5, height: 0.5, cornerRadius: 0.1), materials: [PortalMaterial()] ) ) portal.components.set(PortalComponent(target: world)) content.add(world) content.add(portal) ``` ### Clipping and Crossing You can enable clipping by configuring ``clippingMode-swift.property`` to something other than ``ClippingMode-swift.enum/disabled``. For example, you can use ``ClippingMode-swift.enum/plane(_:)`` to clip portal content to an infinite half-space, or ``ClippingMode-swift.enum/volume(_:)`` to clip to a box-bounded region of space. Clipping prevents portal world content from rendering beyond the portal boundary and causing depth confusion. Entities inside the portal world with a ``PortalCrossingComponent`` can freely cross in and out of the portal boundary in any of the following platforms: - iOS 18 and later - macOS 15 and later - visionOS 2 and later You can enable the crossing feature by configuring ``crossingMode-swift.property`` to something other than ``CrossingMode-swift.enum/disabled``. Such as ``CrossingMode-swift.enum/plane(_:)`` for an infinite-plane crossing, or ``CrossingMode-swift.enum/volume(_:)`` for a box-bounded crossing. ```swift let world = Entity() world.components.set(WorldComponent()) // Create an entity that doesn't cross beyond the portal bounds. let notCrossing = Entity() // Create an entity that crosses beyond the portal bounds. let willCross = Entity() willCross.components.set(PortalCrossingComponent()) world.addChild(notCrossing) world.addChild(willCross) // Set up a crossable portal, without a near clip. let portal = Entity() portal.components.set( ModelComponent( mesh: .generatePlane(width: 0.5, height: 0.5, cornerRadius: 0.1), materials: [PortalMaterial()] ) ) var portalComp = PortalComponent(target: world) portalComp.clippingMode = .plane(.positiveZ) portalComp.crossingMode = .plane(.positiveZ) portal.components.set(portalComp) content.add(world) content.add(portal) ``` The spaceships below have a ``PortalCrossingComponent``. @Video( source: portal-crossing-video, alt: "Four videos of space ships poking out of portals looking into outer space. Each video is in a grid formation. The top left video have both clipping and crossing mode disabled, so the space ship is being bounded by the portal geometry. The bottom left video have clipping mode set to plane and crossing mode disabled, so the space ship is clipped by the portal plane. The two videos on the right column have crossing mode enabled, so the spaceship is rendered outside the portal geometry.", poster: portal-crossing-video-poster ) The spaceships below *don't* have a ``PortalCrossingComponent``. @Video( source: portal-clipping-video, alt: "Four videos of space ships poking out of portals looking into outer space. Each video is in a grid formation. The two videos on the top row have clipping mode disabled so the space ships are bounded by the portal geometry. The two videos on the bottom row have clipping mode enabled so the space ships are clipped by the portal plane.", poster: portal-clipping-video-poster ) ### Lighting You define the lighting in a portal world with ``ImageBasedLightComponent`` and ``ImageBasedLightReceiverComponent``. RealityKit provides a default IBL if you don't specify one with ``ImageBasedLightReceiverComponent``. Contents within a portal world don't receive real-world probe lighting. However, you can achieve a similar effect in the portal world using ``VirtualEnvironmentProbeComponent``. You can configure this virtual probe lighting contribution with ``EnvironmentLightingConfigurationComponent``. Dynamic lights, such as ``PointLightComponent`` and ``DirectionalLightComponent``, don't cross world bounds. Different lighting environments light the portal crossing entities based on which side of the portal they are on: - When inside the portal, the portal world's lighting lights the entity. - When outside the portal, the default world's lighting lights the entity.

Members (15)

static · iOS 27.0+

makePortal

TypeScript
static makePortal(surfaceStyle: PortalComponent_SurfaceStyle, boundaryStyle?: PortalComponent_BoundaryStyle, boundaryMode?: PortalComponent_BoundaryMode): PortalComponent_Portal
Swift declaration
static func makePortal(surfaceStyle: PortalComponent.SurfaceStyle, boundaryStyle: PortalComponent.BoundaryStyle = .infinitePlane(), boundaryMode: PortalComponent.BoundaryMode = .none) -> PortalComponent.Portal

Creates a portal entity and a world entity, and configures them. This is the simplest way to set up a portal. The returned ``Portal`` value contains a fresh portal entity and a fresh world entity that you add to your scene. To add portal world content, parent it under the returned `worldEntity`. ```swift let portal = PortalComponent.makePortal( surfaceStyle: .init(width: 0.5, height: 0.5), boundaryStyle: .infinitePlane(), boundaryMode: .clippingAndCrossing ) content.add(portal.worldEntity) content.add(portal.portalEntity) ``` To configure entities you already own — for example, a portal entity that has gesture components, or a world entity that's already in your scene hierarchy — use ``configure(world:portalEntity:surfaceStyle:boundaryStyle:boundaryMode:)`` instead. - Parameters: - surfaceStyle: The size of the portal surface mesh. - boundaryStyle: The shape of the clipping and crossing boundary. Defaults to ``BoundaryStyle/infinitePlane()``. - boundaryMode: The combination of clipping and crossing behaviors to enable. Defaults to ``BoundaryMode/none``. - Returns: A ``Portal`` containing the new portal entity and world entity.

get · iOS 18.0+

clippingMode

TypeScript
get clippingMode(): PortalComponent_ClippingMode
Swift declaration
var clippingMode: PortalComponent.ClippingMode { get set }

The clipping behavior of the portal component. Provide a ``ClippingMode-swift.enum`` to configure the clipping behaviors.

set · iOS 18.0+

clippingMode

TypeScript
set clippingMode(value: PortalComponent_ClippingMode)
Swift declaration
var clippingMode: PortalComponent.ClippingMode { get set }

The clipping behavior of the portal component. Provide a ``ClippingMode-swift.enum`` to configure the clipping behaviors.

get · iOS 18.0+

crossingMode

TypeScript
get crossingMode(): PortalComponent_CrossingMode
Swift declaration
var crossingMode: PortalComponent.CrossingMode { get set }

The crossing behavior of the portal component. Provide a ``CrossingMode-swift.enum`` to configure the crossing behaviors.

set · iOS 18.0+

crossingMode

TypeScript
set crossingMode(value: PortalComponent_CrossingMode)
Swift declaration
var crossingMode: PortalComponent.CrossingMode { get set }

The crossing behavior of the portal component. Provide a ``CrossingMode-swift.enum`` to configure the crossing behaviors.

get · iOS 18.0+

targetEntity

TypeScript
get targetEntity(): (Entity) | null
Swift declaration
var targetEntity: Entity? { get set }

The root entity for the portal's target world. When the target entity is valid and has a ``WorldComponent``, the portal renders with the target entity and its hierarchy tree. When the target entity doesn't have a ``WorldComponent``, the portal doesn't render.

set · iOS 18.0+

targetEntity

TypeScript
set targetEntity(value: (Entity) | null)
Swift declaration
var targetEntity: Entity? { get set }

The root entity for the portal's target world. When the target entity is valid and has a ``WorldComponent``, the portal renders with the target entity and its hierarchy tree. When the target entity doesn't have a ``WorldComponent``, the portal doesn't render.

get · iOS 18.0+

clippingPlane

TypeScript
get clippingPlane(): (PortalComponent_ClippingPlane) | null
Swift declaration
var clippingPlane: PortalComponent.ClippingPlane? { get set }

The clipping plane of the portal, in the entity's local coordinates. When you set this property to a non-`nil` value, the portal clips meshes inside the portal world that are in front of the clipping plane. This property is a convenience that maps onto the more general ``clippingMode-swift.property``. Reading it returns a value only when ``clippingMode-swift.property`` is ``ClippingMode-swift.enum/plane(_:)``; for ``ClippingMode-swift.enum/disabled`` or ``ClippingMode-swift.enum/volume(_:)``, it returns `nil`. For new code, prefer ``clippingMode-swift.property`` directly. It supports ``ClippingMode-swift.enum/volume(_:)`` for box-shaped clipping boundaries and pairs naturally with ``crossingMode-swift.property``.

set · iOS 18.0+

clippingPlane

TypeScript
set clippingPlane(value: (PortalComponent_ClippingPlane) | null)
Swift declaration
var clippingPlane: PortalComponent.ClippingPlane? { get set }

The clipping plane of the portal, in the entity's local coordinates. When you set this property to a non-`nil` value, the portal clips meshes inside the portal world that are in front of the clipping plane. This property is a convenience that maps onto the more general ``clippingMode-swift.property``. Reading it returns a value only when ``clippingMode-swift.property`` is ``ClippingMode-swift.enum/plane(_:)``; for ``ClippingMode-swift.enum/disabled`` or ``ClippingMode-swift.enum/volume(_:)``, it returns `nil`. For new code, prefer ``clippingMode-swift.property`` directly. It supports ``ClippingMode-swift.enum/volume(_:)`` for box-shaped clipping boundaries and pairs naturally with ``crossingMode-swift.property``.

get · iOS 27.0+

lightingBlendDistance

TypeScript
get lightingBlendDistance(): number
Swift declaration
var lightingBlendDistance: Float { get set }

The distance over which crossing-entity lighting blends between the host scene and the portal world. As an entity with ``PortalCrossingComponent`` crosses the portal boundary, RealityKit transitions its lighting from the host scene's environment to the portal world's environment. This property controls the width, in meters, of that transition: - A value of `0` produces a sharp lighting boundary, with the entity fully lit by the portal world on the inside and the host scene on the outside. - A positive value produces a smooth gradient that spans the given distance into the portal world, portal crossing entities are unaffected by this value. The boundary used for the distance calculation is the geometry you configure with ``crossingMode-swift.property``: a plane for ``CrossingMode-swift.enum/plane(_:)``, or a box for ``CrossingMode-swift.enum/volume(_:)``. - Note: This property only affects rendering when ``crossingMode-swift.property`` is enabled.

set · iOS 27.0+

lightingBlendDistance

TypeScript
set lightingBlendDistance(value: number)
Swift declaration
var lightingBlendDistance: Float { get set }

The distance over which crossing-entity lighting blends between the host scene and the portal world. As an entity with ``PortalCrossingComponent`` crosses the portal boundary, RealityKit transitions its lighting from the host scene's environment to the portal world's environment. This property controls the width, in meters, of that transition: - A value of `0` produces a sharp lighting boundary, with the entity fully lit by the portal world on the inside and the host scene on the outside. - A positive value produces a smooth gradient that spans the given distance into the portal world, portal crossing entities are unaffected by this value. The boundary used for the distance calculation is the geometry you configure with ``crossingMode-swift.property``: a plane for ``CrossingMode-swift.enum/plane(_:)``, or a box for ``CrossingMode-swift.enum/volume(_:)``. - Note: This property only affects rendering when ``crossingMode-swift.property`` is enabled.

init · iOS 18.0+

init

TypeScript
static initTargetClippingModeCrossingMode(target: Entity, clippingMode: PortalComponent_ClippingMode, crossingMode: PortalComponent_CrossingMode): PortalComponent
Swift declaration
init(target: Entity, clippingMode: PortalComponent.ClippingMode, crossingMode: PortalComponent.CrossingMode)

Creates a portal component with a target entity, clipping mode, and crossing mode. To render a portal, an entity needs a ``PortalComponent`` and a ``ModelComponent``, using one or more ``PortalMaterial`` instances. The target entity needs to have a ``WorldComponent`` or the portal does not render. Provide ``ClippingMode-swift.enum`` and ``CrossingMode-swift.enum`` to configure the corresponding clipping and crossing features. Using this initializer is equivalent to setting ``targetEntity``, ``clippingMode-swift.property`` and ``crossingMode-swift.property`` properties directly. See ``PortalComponent`` for example usage. - Parameters: - target: A target world entity the portal is looking into. - clippingMode: A configuration for the portal's clipping feature. - crossingMode: A configuration for the portal's crossing feature.

init · iOS 18.0+

init

TypeScript
static initTargetClippingPlane(target: Entity, clippingPlane?: (PortalComponent_ClippingPlane) | null): PortalComponent
Swift declaration
init(target: Entity, clippingPlane: PortalComponent.ClippingPlane? = nil)

Creates a portal component with a target entity and an optional clipping plane. This initializes the ``PortalComponent`` with the given target entity, and an optional clipping plane. The target entity needs a ``WorldComponent`` in its component set. To render a portal, an entity needs a ``PortalComponent`` and a ``ModelComponent``, using one or more ``PortalMaterial`` instances. This initializer is equivalent to setting ``PortalComponent/clippingMode-swift.property`` with the corresponding ``PortalComponent/Plane``, leaving ``crossingMode-swift.property`` at ``CrossingMode-swift.enum/disabled``. For new code, prefer ``init(target:clippingMode:crossingMode:)``, which lets you configure clipping and crossing together and supports volumetric boundaries. - Parameters: - target: A target world entity the portal is looking into. - clippingPlane: A planar representation of a portal to enable the clipping feature. When `nil`, ``PortalComponent/clippingMode-swift.property`` is ``ClippingMode-swift.enum/disabled``.

init · iOS 18.0+

init

TypeScript
static initTargetPlaneOptions(target: Entity, plane: PortalComponent_Plane, options: PortalComponent_Options): PortalComponent
Swift declaration
init(target: Entity, plane: PortalComponent.Plane, options: PortalComponent.Options)

Creates a portal component with a target entity, a single planar definition, and portal options. Use this initializer to toggle ``clippingMode-swift.property`` and ``crossingMode-swift.property`` with the same ``PortalComponent/Plane``. For new code, prefer ``init(target:clippingMode:crossingMode:)``, which lets you configure clipping and crossing independently and supports ``ClippingMode-swift.enum/volume(_:)`` and ``CrossingMode-swift.enum/volume(_:)`` for box-shaped boundaries. - Parameters: - target: A target world entity the portal is looking into. - plane: A plane for configuring clipping and crossing features. - options: An option set that determines which clipping and crossing features to enable.

static · iOS 27.0+

configure

TypeScript
static configure(world: Entity, portalEntity: Entity, surfaceStyle: PortalComponent_SurfaceStyle, boundaryStyle?: PortalComponent_BoundaryStyle, boundaryMode?: PortalComponent_BoundaryMode): void
Swift declaration
static func configure(world: Entity, portalEntity: Entity, surfaceStyle: PortalComponent.SurfaceStyle, boundaryStyle: PortalComponent.BoundaryStyle = .infinitePlane(), boundaryMode: PortalComponent.BoundaryMode = .none)

Configures an existing pair of entities as a portal and its target world. This method writes a coordinated set of components onto the two entities you provide. Use it when you already own both entities — for example, when the portal entity holds gestures or other components, or when the world entity is a child of an existing scene. On the world entity, this method sets: - ``WorldComponent`` On the portal entity, this method sets: - ``ModelComponent`` with a flat plane mesh sized by `surfaceStyle`, applied with ``PortalMaterial`` - ``PortalComponent`` with ``PortalComponent/clippingMode-swift.property`` and ``PortalComponent/crossingMode-swift.property`` configured from `boundaryStyle` and `boundaryMode` This method replaces any existing ``WorldComponent``, ``ModelComponent``, or ``PortalComponent`` on the entities. Other components on either entity are preserved. To create both entities at once, use ``makePortal(surfaceStyle:boundaryStyle:boundaryMode:)`` instead. - Parameters: - world: The entity that contains the portal's content. Place portal world descendants under this entity. - portalEntity: The entity that displays the portal surface in the host scene. - surfaceStyle: The size of the portal surface mesh. - boundaryStyle: The shape of the clipping and crossing boundary. Defaults to ``BoundaryStyle/infinitePlane()``. - boundaryMode: The combination of clipping and crossing behaviors to enable. Defaults to ``BoundaryMode/none``.

Skipped declarations

No declarations were skipped in this snapshot.

All RealityFoundation types →