{"id":8386,"date":"2025-12-11T06:53:32","date_gmt":"2025-12-11T11:53:32","guid":{"rendered":"https:\/\/stepinto.vision\/?p=8386"},"modified":"2025-12-11T06:53:34","modified_gmt":"2025-12-11T11:53:34","slug":"spatial-swiftui-ongeometrychange3d","status":"publish","type":"post","link":"https:\/\/stepinto.vision\/example-code\/spatial-swiftui-ongeometrychange3d\/","title":{"rendered":"Spatial SwiftUI: onGeometryChange3D"},"content":{"rendered":"\n<p>We can use this modifier to access data from GeometryProxy3D without using GeometryReader3D.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Overview<\/h2>\n\n\n\n<p>We learned about <code><a href=\"https:\/\/stepinto.vision\/example-code\/spatial-swiftui-geometryreader3d\/\" data-type=\"post\" data-id=\"4696\">GeometryReader3D<\/a><\/code> in a previous example. This provides access to <code><a href=\"https:\/\/developer.apple.com\/documentation\/swiftui\/geometryproxy3d\">GeometryProxy3D<\/a><\/code>. We can use it modify our content based on changes to that proxy. For example, scaling the content of a RealityView when the size of a window or volume changes.<\/p>\n\n\n\n<p>There is another way we can access <code>GeometryReader3D<\/code>. We can use <code>onGeometryChange3D<\/code> instead of wrapping our view in a geometry reader. This lets us track only the data we need, instead of all changes to the proxy.<\/p>\n\n\n\n<p>This modifier is a bit more complex than other SwiftUI modifiers. We provide the type of data we want from the geometry. Then extract the value we need from the\u00a0proxy\u00a0to make it available in the action closure. With those two steps done, we can use the action block to work with the data.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#000000;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#000000;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>SomeView()\n\/\/ Set the type we want to work with. In this case, we'll use Rext3D\n.onGeometryChange3D(for: Rect3D.self) { proxy in\n    return proxy.frame(in: .global) \/\/ extract the Rect3D from the GeometryProxy\n} action: { newValue in \/\/ newValue is a Rect3D\n    volumeSize = newValue.size \/\/ We can read the size of the Rect3D as a Size3D\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki light-plus\" style=\"background-color: #FFFFFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #795E26\">SomeView<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #008000\">\/\/ Set the type we want to work with. In this case, we&#39;ll use Rext3D<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">.<\/span><span style=\"color: #795E26\">onGeometryChange3D<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">for<\/span><span style=\"color: #000000\">: Rect3D.self) { proxy <\/span><span style=\"color: #AF00DB\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #AF00DB\">return<\/span><span style=\"color: #000000\"> proxy.<\/span><span style=\"color: #795E26\">frame<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">in<\/span><span style=\"color: #000000\">: .<\/span><span style=\"color: #001080\">global<\/span><span style=\"color: #000000\">) <\/span><span style=\"color: #008000\">\/\/ extract the Rect3D from the GeometryProxy<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">} action: { newValue <\/span><span style=\"color: #AF00DB\">in<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #008000\">\/\/ newValue is a Rect3D<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    volumeSize = newValue.<\/span><span style=\"color: #001080\">size<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #008000\">\/\/ We can read the size of the Rect3D as a Size3D<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>See <code><a href=\"https:\/\/developer.apple.com\/documentation\/swiftui\/geometryproxy\">GeometryProxy<\/a><\/code> and <code><a href=\"https:\/\/developer.apple.com\/documentation\/swiftui\/geometryproxy3d\">GeometryProxy3D<\/a><\/code> for a list of characteristics.<\/p>\n\n\n\n<p>See also: <a href=\"https:\/\/stepinto.vision\/example-code\/spatial-swiftui-geometryreader3d\/\" data-type=\"post\" data-id=\"4696\">Spatial SwiftUI: GeometryReader3D<\/a>, <a href=\"https:\/\/stepinto.vision\/example-code\/using-ongeometrychange3d-to-scale-realityview-content-when-a-volume-is-resized\/\" data-type=\"post\" data-id=\"8254\">Using onGeometryChange3D to scale RealityView content when a Volume is resized<\/a>, and <a href=\"https:\/\/stepinto.vision\/labs\/lab-080-first-look-at-unified-coordinate-conversion\/\" data-type=\"post\" data-id=\"6435\">Lab 080 \u2013 First Look at Unified Coordinate Conversion<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Video Demo<\/h2>\n\n\n\n<p>We track two changes in this example. When the volume size is changed, we scale the content inside of a RealityView. When the volume is moved, we capture the position of the volume in world space. Volumes use their back bottom corner as an origin so we&#8217;ll add an ornament there to visualize this change.<\/p>\n\n\n\n\t\t<figure class=\"wp-block-jetpack-videopress jetpack-videopress-player\" style=\"\" >\n\t\t\t<div class=\"jetpack-videopress-player__wrapper\"> <div class=\"jetpack-video-wrapper\"><iframe title=\"VideoPress Video Player\" aria-label='VideoPress Video Player' width='720' height='405' src='https:\/\/videopress.com\/embed\/pH3TIbPQ?cover=1&amp;autoPlay=0&amp;controls=1&amp;loop=0&amp;muted=0&amp;persistVolume=1&amp;playsinline=0&amp;preloadContent=metadata&amp;useAverageColor=1&amp;hd=0' frameborder='0' allowfullscreen data-resize-to-parent=\"true\" allow='clipboard-write'><\/iframe><script src='https:\/\/v0.wordpress.com\/js\/next\/videopress-iframe.js?m=1739540970'><\/script><\/div><\/div>\n\t\t\t\n\t\t\t\n\t\t<\/figure>\n\t\t\n\n\n<h2 class=\"wp-block-heading\">Example Code<\/h2>\n\n\n\n<!--more-->\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#000000;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#000000;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>struct Example134: View {\n\n    @Environment(\\.physicalMetrics) var physicalMetrics\n    @State private var volumeSize: Size3D = .zero\n    @State private var volumeRootEntity = Entity()\n\n    \/\/ A place to store the bounds of our 3D content\n    @State private var baseExtents: SIMD3&lt;Float> = .zero\n\n    \/\/ A place to store the Point3D for the volume position in world space\n    @State private var volumePosition: Point3D = .zero\n\n    var body: some View {\n        RealityView { content in\n\n            content.add(volumeRootEntity)\n\n            guard let baseRoot = try? await Entity(named: \"ToyBiplane\", in: realityKitContentBundle) else { return }\n            volumeRootEntity.addChild(baseRoot, preservingWorldTransform: true)\n            baseExtents = baseRoot.visualBounds(relativeTo: nil).extents \/ baseRoot.scale\n            baseRoot.position.y = -baseExtents.y \/ 2\n            scaleContent(by: volumeSize)\n\n        }\n        .ornament(attachmentAnchor: .scene(.bottomLeadingBack), ornament: {\n            VStack(alignment: .leading, spacing: 12) {\n                Text(\"X: \\(volumePosition.x)\")\n                Text(\"Y: \\(volumePosition.y)\")\n                Text(\"Z: \\(volumePosition.z)\")\n            }\n\n            .font(.largeTitle)\n            .padding(24)\n            .glassBackgroundEffect()\n        })\n        .debugBorder3D(.white)\n\n        \/\/ Example 01: Anytime the volume changes in size we'll scale the RealityView content\n        .onGeometryChange3D(for: Rect3D.self) { proxy in\n            return proxy.frame(in: .global)\n        } action: { new in\n            volumeSize = new.size\n            scaleContent(by: volumeSize)\n        }\n\n        \/\/ Example 02: Capture the position of the volume when it changes\n        .onGeometryChange3D(for: Point3D.self) { proxy in try! proxy\n                .coordinateSpace3D()\n                .convert(value: Point3D.zero, to: .worldReference)\n        } action: { _, new in\n            volumePosition = new \/\/ We'll just show this in an ornament\n        }\n    }\n\n    \/\/\/ Scale the 3D content based on the size of the Volume\n    \/\/\/ See this article for details: https:\/\/stepinto.vision\/example-code\/using-ongeometrychange3d-to-scale-realityview-content-when-a-volume-is-resized\/\n    func scaleContent(by volumeSize: Size3D) {\n        let scale = Float(physicalMetrics.convert(volumeSize.width, to: .meters)) \/ baseExtents.x\n        volumeRootEntity.setScale(.init(repeating: scale), relativeTo: nil)\n    }\n\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki light-plus\" style=\"background-color: #FFFFFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #0000FF\">struct<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #267F99\">Example134<\/span><span style=\"color: #000000\">: View {<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">@Environment<\/span><span style=\"color: #000000\">(\\.<\/span><span style=\"color: #001080\">physicalMetrics<\/span><span style=\"color: #000000\">) <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> physicalMetrics<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">@State<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #0000FF\">private<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> volumeSize: Size3D = .<\/span><span style=\"color: #001080\">zero<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">@State<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #0000FF\">private<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> volumeRootEntity = <\/span><span style=\"color: #795E26\">Entity<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #008000\">\/\/ A place to store the bounds of our 3D content<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">@State<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #0000FF\">private<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> baseExtents: SIMD3&lt;<\/span><span style=\"color: #267F99\">Float<\/span><span style=\"color: #000000\">&gt; = .<\/span><span style=\"color: #001080\">zero<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #008000\">\/\/ A place to store the Point3D for the volume position in world space<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">@State<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #0000FF\">private<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> volumePosition: Point3D = .<\/span><span style=\"color: #001080\">zero<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> body: some View {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        RealityView { content <\/span><span style=\"color: #AF00DB\">in<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            content.<\/span><span style=\"color: #795E26\">add<\/span><span style=\"color: #000000\">(volumeRootEntity)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #AF00DB\">guard<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #0000FF\">let<\/span><span style=\"color: #000000\"> baseRoot = <\/span><span style=\"color: #AF00DB\">try<\/span><span style=\"color: #000000\">? <\/span><span style=\"color: #AF00DB\">await<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #795E26\">Entity<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">named<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #A31515\">&quot;ToyBiplane&quot;<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">in<\/span><span style=\"color: #000000\">: realityKitContentBundle) <\/span><span style=\"color: #AF00DB\">else<\/span><span style=\"color: #000000\"> { <\/span><span style=\"color: #AF00DB\">return<\/span><span style=\"color: #000000\"> }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            volumeRootEntity.<\/span><span style=\"color: #795E26\">addChild<\/span><span style=\"color: #000000\">(baseRoot, <\/span><span style=\"color: #795E26\">preservingWorldTransform<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #0000FF\">true<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            baseExtents = baseRoot.<\/span><span style=\"color: #795E26\">visualBounds<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">relativeTo<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #0000FF\">nil<\/span><span style=\"color: #000000\">).<\/span><span style=\"color: #001080\">extents<\/span><span style=\"color: #000000\"> \/ baseRoot.<\/span><span style=\"color: #001080\">scale<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            baseRoot.<\/span><span style=\"color: #001080\">position<\/span><span style=\"color: #000000\">.<\/span><span style=\"color: #001080\">y<\/span><span style=\"color: #000000\"> = -baseExtents.<\/span><span style=\"color: #001080\">y<\/span><span style=\"color: #000000\"> \/ <\/span><span style=\"color: #098658\">2<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #795E26\">scaleContent<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">by<\/span><span style=\"color: #000000\">: volumeSize)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">ornament<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">attachmentAnchor<\/span><span style=\"color: #000000\">: .<\/span><span style=\"color: #795E26\">scene<\/span><span style=\"color: #000000\">(.<\/span><span style=\"color: #001080\">bottomLeadingBack<\/span><span style=\"color: #000000\">), <\/span><span style=\"color: #795E26\">ornament<\/span><span style=\"color: #000000\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #795E26\">VStack<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">alignment<\/span><span style=\"color: #000000\">: .<\/span><span style=\"color: #001080\">leading<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">spacing<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">12<\/span><span style=\"color: #000000\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                <\/span><span style=\"color: #795E26\">Text<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #A31515\">&quot;X: <\/span><span style=\"color: #0000FF\">\\(<\/span><span style=\"color: #000000FF\">volumePosition.<\/span><span style=\"color: #001080\">x<\/span><span style=\"color: #0000FF\">)<\/span><span style=\"color: #A31515\">&quot;<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                <\/span><span style=\"color: #795E26\">Text<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #A31515\">&quot;Y: <\/span><span style=\"color: #0000FF\">\\(<\/span><span style=\"color: #000000FF\">volumePosition.<\/span><span style=\"color: #001080\">y<\/span><span style=\"color: #0000FF\">)<\/span><span style=\"color: #A31515\">&quot;<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                <\/span><span style=\"color: #795E26\">Text<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #A31515\">&quot;Z: <\/span><span style=\"color: #0000FF\">\\(<\/span><span style=\"color: #000000FF\">volumePosition.<\/span><span style=\"color: #001080\">z<\/span><span style=\"color: #0000FF\">)<\/span><span style=\"color: #A31515\">&quot;<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            .<\/span><span style=\"color: #795E26\">font<\/span><span style=\"color: #000000\">(.<\/span><span style=\"color: #001080\">largeTitle<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            .<\/span><span style=\"color: #795E26\">padding<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #098658\">24<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            .<\/span><span style=\"color: #795E26\">glassBackgroundEffect<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        })<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">debugBorder3D<\/span><span style=\"color: #000000\">(.<\/span><span style=\"color: #001080\">white<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        <\/span><span style=\"color: #008000\">\/\/ Example 01: Anytime the volume changes in size we&#39;ll scale the RealityView content<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">onGeometryChange3D<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">for<\/span><span style=\"color: #000000\">: Rect3D.self) { proxy <\/span><span style=\"color: #AF00DB\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #AF00DB\">return<\/span><span style=\"color: #000000\"> proxy.<\/span><span style=\"color: #795E26\">frame<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">in<\/span><span style=\"color: #000000\">: .<\/span><span style=\"color: #001080\">global<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        } action: { new <\/span><span style=\"color: #AF00DB\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            volumeSize = new.<\/span><span style=\"color: #001080\">size<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #795E26\">scaleContent<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">by<\/span><span style=\"color: #000000\">: volumeSize)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        <\/span><span style=\"color: #008000\">\/\/ Example 02: Capture the position of the volume when it changes<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">onGeometryChange3D<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">for<\/span><span style=\"color: #000000\">: Point3D.self) { proxy <\/span><span style=\"color: #AF00DB\">in<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #AF00DB\">try<\/span><span style=\"color: #000000\">! proxy<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                .<\/span><span style=\"color: #795E26\">coordinateSpace3D<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                .<\/span><span style=\"color: #795E26\">convert<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">value<\/span><span style=\"color: #000000\">: Point3D.<\/span><span style=\"color: #001080\">zero<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">to<\/span><span style=\"color: #000000\">: .<\/span><span style=\"color: #001080\">worldReference<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        } action: { <\/span><span style=\"color: #001080\">_<\/span><span style=\"color: #000000\">, new <\/span><span style=\"color: #AF00DB\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            volumePosition = new <\/span><span style=\"color: #008000\">\/\/ We&#39;ll just show this in an ornament<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #008000\">\/\/\/ Scale the 3D content based on the size of the Volume<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #008000\">\/\/\/ See this article for details: https:\/\/stepinto.vision\/example-code\/using-ongeometrychange3d-to-scale-realityview-content-when-a-volume-is-resized\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">func<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #795E26\">scaleContent<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">by<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #001080\">volumeSize<\/span><span style=\"color: #000000\">: Size3D) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        <\/span><span style=\"color: #0000FF\">let<\/span><span style=\"color: #000000\"> scale = <\/span><span style=\"color: #267F99\">Float<\/span><span style=\"color: #000000\">(physicalMetrics.<\/span><span style=\"color: #795E26\">convert<\/span><span style=\"color: #000000\">(volumeSize.<\/span><span style=\"color: #001080\">width<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">to<\/span><span style=\"color: #000000\">: .<\/span><span style=\"color: #001080\">meters<\/span><span style=\"color: #000000\">)) \/ baseExtents.<\/span><span style=\"color: #001080\">x<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        volumeRootEntity.<\/span><span style=\"color: #795E26\">setScale<\/span><span style=\"color: #000000\">(.<\/span><span style=\"color: #0000FF\">init<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">repeating<\/span><span style=\"color: #000000\">: scale), <\/span><span style=\"color: #795E26\">relativeTo<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #0000FF\">nil<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">}<\/span><\/span><\/code><\/pre><\/div>\n","protected":false},"excerpt":{"rendered":"<p>We can use this modifier to access data from GeometryProxy3D without using GeometryReader3D.<\/p>\n","protected":false},"author":93705089,"featured_media":8387,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kad_blocks_custom_css":"","_kad_blocks_head_custom_js":"","_kad_blocks_body_custom_js":"","_kad_blocks_footer_custom_js":"","advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"_EventAllDay":false,"_EventTimezone":"","_EventStartDate":"","_EventEndDate":"","_EventStartDateUTC":"","_EventEndDateUTC":"","_EventShowMap":false,"_EventShowMapLink":false,"_EventURL":"","_EventCost":"","_EventCostDescription":"","_EventCurrencySymbol":"","_EventCurrencyCode":"","_EventCurrencyPosition":"","_EventDateTimeSeparator":"","_EventTimeRangeSeparator":"","_EventOrganizerID":[],"_EventVenueID":[],"_OrganizerEmail":"","_OrganizerPhone":"","_OrganizerWebsite":"","_VenueAddress":"","_VenueCity":"","_VenueCountry":"","_VenueProvince":"","_VenueState":"","_VenueZip":"","_VenuePhone":"","_VenueURL":"","_VenueStateProvince":"","_VenueLat":"","_VenueLng":"","_VenueShowMap":false,"_VenueShowMapLink":false,"_kadence_starter_templates_imported_post":false,"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_wpas_customize_per_network":false,"jetpack_post_was_ever_published":false},"categories":[1365],"tags":[],"class_list":["post-8386","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-example-code"],"jetpack_publicize_connections":[],"taxonomy_info":{"category":[{"value":1365,"label":"Example Code"}]},"featured_image_src_large":["https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/12\/step-example-134-01.jpeg?fit=1024%2C576&ssl=1",1024,576,true],"author_info":{"display_name":"Joseph Simpson","author_link":"https:\/\/stepinto.vision\/author\/vrhermit\/"},"comment_info":0,"category_info":[{"term_id":1365,"name":"Example Code","slug":"example-code","term_group":0,"term_taxonomy_id":11,"taxonomy":"category","description":"Code snippets and examples of using common APIs throughout visionOS development","parent":0,"count":187,"filter":"raw","cat_ID":1365,"category_count":187,"category_description":"Code snippets and examples of using common APIs throughout visionOS development","cat_name":"Example Code","category_nicename":"example-code","category_parent":0}],"tag_info":false,"jetpack_featured_media_url":"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/12\/step-example-134-01.jpeg?fit=3840%2C2160&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/posts\/8386","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/users\/93705089"}],"replies":[{"embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/comments?post=8386"}],"version-history":[{"count":10,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/posts\/8386\/revisions"}],"predecessor-version":[{"id":8399,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/posts\/8386\/revisions\/8399"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/media\/8387"}],"wp:attachment":[{"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/media?parent=8386"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/categories?post=8386"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/tags?post=8386"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}