Create an Xcode project by choosing iOS as the platform, Augmented Reality as the template, and SwiftUI as the user interface. If you run the default AR template, you’ll see a steel box appear wherever your device detects a horizontal plane. This is because it is using a horizontal plane anchor, and placing the box at the origin of that anchor.
If you’re interested to see how the steel box is put in place, or to change attributes of it, you can do that in the Experience.rcproject file.
We won’t be needing to do anything in that file for this project though.
We’ll start off by extending a couple of Apple’s system classes. The first one should be pretty self-explanatory, it merely returns the centre of a CGRect by giving a point halfway along the width and height. The second one is more complicated. It finds the difference in position between two AR objects (called an Entity
in RealityKit
) and measures the length of that distance.
When our Entity moves, we give it a duration for the animation.
Longer distances will take more time, so we need to know the distance in order to calculate the movement duration.
Next, we’ll create a simple button that will give the command to move the steel box. This code merely describes how the button will look, as we’ll pass the action it actually does as a closure when we create it. This is very similar to when you construct a Button with a string parameter for the title, as you assign the action in a trailing closure in that case. I’m placing the button at the bottom of the screen by putting it in a Group that fills the screen and has alignment .bottom
.

RealityKit still doesn’t have a SwiftUI view, so we rely on UIViewRepresentable
to wrap what is essentially a subclass of UIView
. To make it easier to access the properties inside, I’ve made it so that we have to pass in the box anchor which is loaded from the Experience.rcproject file. The ARView
and waypoint are also passed in for the same reason, it makes it easier to access them from SwiftUI.
All the UIViewRepresentable
does is add the anchor and add the waypoint
as a child.

Now we can construct most of our SwiftUI using what we have created so far.
The ARView
is created at the size of the screen, the box anchor is loaded from the Experience.rcproject file, and the steelBox is loaded from the anchor. The waypoint is a ModelEntity that is constructed from a simple plane 10cm in width and depth. There is a constructor for planes that takes a width and height, but that would make it stand up and it wouldn’t be flat on the ground.
Finally we have speed, which is what we’ll use once the steel box starts moving around.

In the ZStack
we have the ARViewContainer
at the back, the targeting reticule in the middle of the screen, and finally the MoveButton
. I have commented out the function call in MoveButton
, mostly because this code won’t build until I add it. Feel free to leave it commented until you add this next step, or uncomment it if you’re happy for it to have an error there temporarily.
I’m using a protocol to specify what the requirements of my app will be. In order to conform to the protocol, I need all of these properties to exist, but so far all except the funtion and the last property have been added. The computed property destinationRelativeToWaypoint
is simple enough: I want my box to arrive almost exactly where the waypoint is. It needs to be moved up by 2.25 cm so that it is not halfway through the plane. We want it to sit on top of the plane instead.
We also want the steel box to keep its rotation, as otherwise it would always end up facing the same direction as the waypoint does.

The code for setting the waypoint is more complicated, but I’ve commented it enough to help you to understand. We’re casting a ray to the same horizontal plane that the box anchor is on, and hopefully we hit it. If we don’t, no further action is taken. If we do, the location of the first hit will be the waypoint location. The waypoint will instantly move to this location, and we calculate how long it will take for the box to get there. As I said at the beginning, the move animation has a duration, not a speed. That’s why we have to calculate the journey time.
Finally we tell the steel box to look at its destination, and move there.
If you left the call to setWaypoint in the MoveButton closure in ContentView commented out, now would be a good time to uncomment it.
Otherwise you will not be able to set waypoints or move the box at all.