{"id":6389,"date":"2025-05-12T17:14:03","date_gmt":"2025-05-12T21:14:03","guid":{"rendered":"https:\/\/ionic.io\/blog\/?p=6389"},"modified":"2025-05-12T17:14:04","modified_gmt":"2025-05-12T21:14:04","slug":"cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii","status":"publish","type":"post","link":"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii","title":{"rendered":"Cross-platform AR\/VR With the Web: WebXR with A-Frame, Angular, and Capacitor (Part II)"},"content":{"rendered":"\n<p><em>This is the second blog post in a multipart series. While it&#8217;s not necessary to read the first part it will definitely add some much needed context: <\/em><a href=\"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor\"><em>Cross-platform AR\/VR With the Web: WebXR with A-Frame, Angular, and Capacito<\/em>r (Part I)<\/a><\/p>\n\n\n\n<p>Last year I covered a topic about incorporating WebXR into your Capacitor projects to create cross-platform Virtual Reality experiences. While this previous blog post was a great starting point for using WebXR it really only scratched the surface of what&#8217;s possible with A-Frame. Recently, I revisited this project to create a low-code AR\/VR <a href=\"https:\/\/www.youtube.com\/watch?v=C_cDjVjT4fI\">video tutorial<\/a> on the OutSystems&#8217; YouTube channel for OutSystems Developer Cloud (ODC) and it inspired me to expand on this original blog post to show off how it can be done in Capacitor. <\/p>\n\n\n\n<p>For the second part of this blog post I want to accomplish three things:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Incorporate a custom animated character<\/li>\n\n\n\n<li>Expand by adding AR functionality<\/li>\n\n\n\n<li>Run the project in a mobile app using native device functionality (i.e. camera)<\/li>\n<\/ul>\n\n\n\n<p>The reason why I want to do these tasks is to provide more depth so you have flexibility with your version of the project. In the original blog post I demonstrated how to create a controlled version of the project that fit within the lines of the tutorial and this time I want to really explore how you would go on to create that experience yourself. This means using custom animated 3D models that you might have created in <a href=\"https:\/\/www.blender.org\/\">Blender<\/a>, showing you libraries that enhance your XR projects that I didn&#8217;t cover, and showing you how to overcome the challenges you&#8217;ll face with native device functionality when you run this AR project in mobile.<\/p>\n\n\n\n<p>To accomplish this I am going to use a 3D Neo model that I custom animated in Blender and use A-Frame, <a href=\"https:\/\/github.com\/c-frame\/aframe-extras\">A-Frame Extras<\/a>, <a href=\"https:\/\/ar-js-org.github.io\/AR.js-Docs\/\">AR.js<\/a>, and Angular to build a project around Neo. Then we&#8217;ll use Capacitor to make our project cross-platform and run it on an iOS device with the proper camera permissions.<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls loop autoplay>\n<source src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2025\/05\/NeoWave-4K-1.mov\">\n<\/video><\/figure>\n\n\n\n<p>Let&#8217;s jump into it!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-setting-up-the-project\">Setting up the Project<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Create an Ionic-Angular Project<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">ionic start webAR blank --type=angular<\/code><\/pre>\n\n\n\n<p>    2. Install A-Frame and A-Frame Extras into your project <\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">npm install --save aframe\nnpm install --save aframe-extras<\/code><\/pre>\n\n\n\n<p><em>Note: The A-Frame Extras library lets us play our animations that are attached to our model<\/em><\/p>\n\n\n\n<p>    3. Import A-Frame and A-Frame Extras in <em>polyfills.ts<\/em> under Browser Polyfills<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">* BROWSER POLYFILLS\n *\/\nimport &#039;aframe&#039;;\nimport &#039;aframe-extras&#039;;\n\/**<\/code><\/pre>\n\n\n\n<p>    4. Download <em>aframe-ar-nft.js<\/em> and add it to the <em>assets<\/em> folder<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">https:\/\/raw.githack.com\/AR-js-org\/AR.js\/master\/aframe\/build\/aframe-ar-nft.js<\/code><\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"496\" height=\"290\" data-src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2025\/05\/Screenshot-2025-05-07-at-12.38.32\u202fPM.png\" alt=\"\" class=\"wp-image-6398 lazyload\" style=\"--smush-placeholder-width: 496px; --smush-placeholder-aspect-ratio: 496\/290;width:417px;height:auto\" data-srcset=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2025\/05\/Screenshot-2025-05-07-at-12.38.32\u202fPM.png 496w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2025\/05\/Screenshot-2025-05-07-at-12.38.32\u202fPM-300x175.png 300w\" data-sizes=\"auto, (max-width: 496px) 100vw, 496px\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" \/><noscript><img loading=\"lazy\" decoding=\"async\" width=\"496\" height=\"290\" src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2025\/05\/Screenshot-2025-05-07-at-12.38.32\u202fPM.png\" alt=\"\" class=\"wp-image-6398\" style=\"width:417px;height:auto\" srcset=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2025\/05\/Screenshot-2025-05-07-at-12.38.32\u202fPM.png 496w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2025\/05\/Screenshot-2025-05-07-at-12.38.32\u202fPM-300x175.png 300w\" sizes=\"auto, (max-width: 496px) 100vw, 496px\" \/><\/noscript><\/figure>\n<\/div>\n\n\n<p class=\"has-text-align-left\"><em>Note: When I tried using NPM for this library it required a separate import for <a href=\"https:\/\/threejs.org\/\">Three.js<\/a> whereas downloading it did not. That&#8217;s why we&#8217;re downloading it.<\/em><\/p>\n\n\n\n<p>    5. Add <em>aframe-ar-nft.js<\/em> to your <em>angular.json<\/em> file scripts<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">&quot;scripts&quot;: [\n&quot;src\/assets\/aframe-ar-nft.js&quot;\n]<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-animated-neo\">Animated Neo<\/h2>\n\n\n\n<p>A really important aspect of this project is the 3D model that we&#8217;ll be using in our Ionic-Angular project, the software we&#8217;re using to build\/animate our characters, and where we plan to store our character:   <\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls loop autoplay>\n<source src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2025\/05\/Screen-Recording-2025-05-07-at-1.03.01\u202fPM-1.mov\">\n<\/video><\/figure>\n\n\n\n<p>In this case, I am using Blender to animate a 3D Neo provided by the OutSystems design team and have named this character animation <em>Waving<\/em> since that is what Neo is doing in the animation. While I don&#8217;t want to get into the details of how to animate the character (since this would quickly become an intermediate Blender tutorial) there&#8217;s many resources on how to animate 3D models online. For this tutorial, you just need to export it from your 3D animation software in a .glb or .gltf format then upload it someplace where it&#8217;ll be accessible like an S3 bucket in AWS to reference it in our HTML.<\/p>\n\n\n\n<p>Once you have exported your 3D model and it&#8217;s in a place where it can be accessed by your app then you can start referencing it in your app. If you don&#8217;t have a 3D model available or want to work with a model that&#8217;s animated then definitely check out places like <a href=\"https:\/\/www.turbosquid.com\/Search\/3D-Models\/animated?max_price=0\">TurboSquid<\/a> that have tons of assets.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-ar\">AR<\/h2>\n\n\n\n<p>Next we&#8217;ll need to modify our project to recognize the custom elements that are a part of A-Frame then download the marker we&#8217;ll be using as a reference for our app to place the 3D model on: <\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Import <em>CUSTOM_ELEMENTS_SCHEMA<\/em> to <em>home.page.ts<\/em> and inject CUSTOM_ELEMENTS_SCHEMA as a schema into our <em>home<\/em> component <\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">import { Component, CUSTOM_ELEMENTS_SCHEMA } from &#039;@angular\/core&#039;;\nimport { IonHeader, IonToolbar, IonTitle, IonContent } from &#039;@ionic\/angular\/standalone&#039;;\n\n@Component({\n  selector: &#039;app-home&#039;,\n  templateUrl: &#039;home.page.html&#039;,\n  styleUrls: [&#039;home.page.scss&#039;],\n  imports: [IonHeader, IonToolbar, IonTitle, IonContent],\n  schemas: [CUSTOM_ELEMENTS_SCHEMA]\n})\nexport class HomePage {\n  constructor() {}\n}<\/code><\/pre>\n\n\n\n<p><em>Note: If you don&#8217;t define CUSTOM_ELEMENTS_SCHEMA your project will throw a<\/em>n error<\/p>\n\n\n\n<p>    2. Add AR HTML to <em>home.page.html<\/em><\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">&lt;a-scene embedded arjs&gt;\n  &lt;a-marker preset=&#039;hiro&#039;&gt;\n    &lt;a-entity\n      position=&#039;0 0 0&#039;\n      scale=&#039;0.5 0.5 0.5&#039;\n      gltf-model=&#039;Place .glb URL here&#039;\n      animation-mixer=&#039;clip: Waving&#039;\n    &gt;&lt;\/a-entity&gt;\n  &lt;\/a-marker&gt;\n  &lt;a-entity camera&gt;&lt;\/a-entity&gt;\n&lt;\/a-scene&gt;<\/code><\/pre>\n\n\n\n<p>    3. Download and print the <em>Hiro<\/em> marker<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img decoding=\"async\" data-src=\"https:\/\/raw.githubusercontent.com\/AR-js-org\/AR.js\/master\/data\/images\/hiro.png\" alt=\"\" style=\"width:403px;height:auto\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" \/><noscript><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/AR-js-org\/AR.js\/master\/data\/images\/hiro.png\" alt=\"\" style=\"width:403px;height:auto\"\/><\/noscript><\/figure>\n<\/div>\n\n\n<p>If you checked out my previous blog post on WebXR this should look familiar but there are a few differences: In our scene we&#8217;re letting A-Frame and AR.js know that this is an embedded AR experience with <em>embedded arjs<\/em> and adding an <em>&lt;a-marker&gt;<\/em> tag defining that we&#8217;ll be placing our object on a <em>Hiro<\/em> marker. Then we are using an <em>&lt;a-entity&gt;<\/em> tag because we&#8217;re moving away from preset shapes to import a custom 3D model and adding <em>animation-mixer<\/em> so the <em>aframe-extras<\/em> library knows that the attached animation clip <em>Waving<\/em> needs to be played. Finally, we are adding another <em>&lt;a-entity&gt;<\/em> tag defining it as a <em>camera<\/em> because the camera in our scene operates as its own entity.<\/p>\n\n\n\n<p>    4. (Optional) Test the application to make sure the experience is working correctly with a camera<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">ionic capacitor build\nionic serve<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-video\"><video controls loop autoplay>\n<source src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2025\/05\/Screen-Recording-2025-05-08-at-6.59.30\u202fPM.mov\">\n<\/video><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-mobile\">Mobile<\/h2>\n\n\n\n<p>For our project to run on mobile we&#8217;ll need to add a iOS as a platform to our Capacitor project and configure the permissions so we have access to the camera:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Add, build, sync, and run on your platform of choice<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">ionic capacitor add ios\n\nionic capacitor build\nionic capacitor sync\n\n\/\/Works best if you run it on a physical device\nionic capacitor run ios<\/code><\/pre>\n\n\n\n<p><em>Note: You should be able to add Android and run it on a WebXR capable Android device. I don&#8217;t have an Android device to test this project so I&#8217;m excluding it as a platform. <\/em><\/p>\n\n\n\n<p>    2. Adjust permissions in <em>info.plist<\/em> in XCode<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">\/\/info.plist - iOS\n&lt;key&gt;NSCameraUsageDescription&lt;\/key&gt;\n&lt;string&gt;Allow camera&lt;\/string&gt;<\/code><\/pre>\n\n\n\n<p>With that complete you can now run your project in XCode on an iPhone! Given the experimental nature of this library with Capacitor it&#8217;s possible to run into sizing issues with orientation and you will likely need to tweak the HTML to fit your particular use case. In my experience, this works best in landscape mode and it minimizes having to code around the interface for it to scale in multiple orientations. It also reduces how much you need to scale and\/or position your 3D model in your scene to get it to fit on your <em>Hiro<\/em> marker.  <\/p>\n\n\n\n<p>Overall, this project was a lot of fun but there&#8217;s still more projects you can do with A-Frame, AR.js, and Capacitor! Be sure to check out some of the other features available and feel free to share your projects with us on <a href=\"https:\/\/discord.com\/invite\/UPYYRhtyzp\">Discord<\/a>, <a href=\"https:\/\/x.com\/ionicframework\">X<\/a>, or <a href=\"https:\/\/bsky.app\/profile\/ionic.io\">Bluesky<\/a>!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is the second blog post in a multipart series. While it&#8217;s not necessary to read the first part it will definitely add some much needed context: Cross-platform AR\/VR With the Web: WebXR with A-Frame, Angular, and Capacitor (Part I) Last year I covered a topic about incorporating WebXR into your Capacitor projects to create [&hellip;]<\/p>\n","protected":false},"author":103,"featured_media":6198,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"publish_to_discourse":"","publish_post_category":"","wpdc_auto_publish_overridden":"","wpdc_topic_tags":"","wpdc_pin_topic":"","wpdc_pin_until":"","discourse_post_id":"","discourse_permalink":"","wpdc_publishing_response":"","wpdc_publishing_error":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1,124],"tags":[282,60,291,151,3,25],"class_list":["post-6389","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-all","category-tutorials","tag-a-frame","tag-angular","tag-blender","tag-capacitor","tag-ionic","tag-tutorials"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v23.0 (Yoast SEO v23.0) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Cross-platform AR\/VR With the Web: WebXR with A-Frame, Angular, and Capacitor (Part II) - Ionic Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Cross-platform AR\/VR With the Web: WebXR with A-Frame, Angular, and Capacitor (Part II)\" \/>\n<meta property=\"og:description\" content=\"This is the second blog post in a multipart series. While it&#8217;s not necessary to read the first part it will definitely add some much needed context: Cross-platform AR\/VR With the Web: WebXR with A-Frame, Angular, and Capacitor (Part I) Last year I covered a topic about incorporating WebXR into your Capacitor projects to create [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii\" \/>\n<meta property=\"og:site_name\" content=\"Ionic Blog\" \/>\n<meta property=\"article:published_time\" content=\"2025-05-12T21:14:03+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-05-12T21:14:04+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2024\/07\/boxcap-feature-image.png\" \/>\n\t<meta property=\"og:image:width\" content=\"2240\" \/>\n\t<meta property=\"og:image:height\" content=\"1120\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Logan Brade\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@loganbrade\" \/>\n<meta name=\"twitter:site\" content=\"@ionicframework\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Logan Brade\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii#article\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii\"},\"author\":{\"name\":\"Logan Brade\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/07a04c81f6b3180076d1a6ac967bc562\"},\"headline\":\"Cross-platform AR\/VR With the Web: WebXR with A-Frame, Angular, and Capacitor (Part II)\",\"datePublished\":\"2025-05-12T21:14:03+00:00\",\"dateModified\":\"2025-05-12T21:14:04+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii\"},\"wordCount\":1125,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/ionic.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2024\/07\/boxcap-feature-image.png\",\"keywords\":[\"A-Frame\",\"Angular\",\"Blender\",\"Capacitor\",\"Ionic\",\"Tutorials\"],\"articleSection\":[\"All\",\"Tutorials\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii\",\"url\":\"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii\",\"name\":\"Cross-platform AR\/VR With the Web: WebXR with A-Frame, Angular, and Capacitor (Part II) - Ionic Blog\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii#primaryimage\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2024\/07\/boxcap-feature-image.png\",\"datePublished\":\"2025-05-12T21:14:03+00:00\",\"dateModified\":\"2025-05-12T21:14:04+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii#primaryimage\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2024\/07\/boxcap-feature-image.png\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2024\/07\/boxcap-feature-image.png\",\"width\":2240,\"height\":1120},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/ionic.io\/blog\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Cross-platform AR\/VR With the Web: WebXR with A-Frame, Angular, and Capacitor (Part II)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/ionic.io\/blog\/#website\",\"url\":\"https:\/\/ionic.io\/blog\/\",\"name\":\"ionic.io\/blog\",\"description\":\"Build amazing native and progressive web apps with the web\",\"publisher\":{\"@id\":\"https:\/\/ionic.io\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/ionic.io\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/ionic.io\/blog\/#organization\",\"name\":\"Ionic\",\"url\":\"https:\/\/ionic.io\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png\",\"width\":1920,\"height\":854,\"caption\":\"Ionic\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/ionicframework\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/07a04c81f6b3180076d1a6ac967bc562\",\"name\":\"Logan Brade\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/03\/IMG_2854-150x150.jpg\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/03\/IMG_2854-150x150.jpg\",\"caption\":\"Logan Brade\"},\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/loganbrade\/\",\"https:\/\/x.com\/loganbrade\"],\"url\":\"https:\/\/ionic.io\/blog\/author\/logan-brade\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Cross-platform AR\/VR With the Web: WebXR with A-Frame, Angular, and Capacitor (Part II) - Ionic Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii","og_locale":"en_US","og_type":"article","og_title":"Cross-platform AR\/VR With the Web: WebXR with A-Frame, Angular, and Capacitor (Part II)","og_description":"This is the second blog post in a multipart series. While it&#8217;s not necessary to read the first part it will definitely add some much needed context: Cross-platform AR\/VR With the Web: WebXR with A-Frame, Angular, and Capacitor (Part I) Last year I covered a topic about incorporating WebXR into your Capacitor projects to create [&hellip;]","og_url":"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii","og_site_name":"Ionic Blog","article_published_time":"2025-05-12T21:14:03+00:00","article_modified_time":"2025-05-12T21:14:04+00:00","og_image":[{"width":2240,"height":1120,"url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2024\/07\/boxcap-feature-image.png","type":"image\/png"}],"author":"Logan Brade","twitter_card":"summary_large_image","twitter_creator":"@loganbrade","twitter_site":"@ionicframework","twitter_misc":{"Written by":"Logan Brade","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii#article","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii"},"author":{"name":"Logan Brade","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/07a04c81f6b3180076d1a6ac967bc562"},"headline":"Cross-platform AR\/VR With the Web: WebXR with A-Frame, Angular, and Capacitor (Part II)","datePublished":"2025-05-12T21:14:03+00:00","dateModified":"2025-05-12T21:14:04+00:00","mainEntityOfPage":{"@id":"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii"},"wordCount":1125,"commentCount":0,"publisher":{"@id":"https:\/\/ionic.io\/blog\/#organization"},"image":{"@id":"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii#primaryimage"},"thumbnailUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2024\/07\/boxcap-feature-image.png","keywords":["A-Frame","Angular","Blender","Capacitor","Ionic","Tutorials"],"articleSection":["All","Tutorials"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii#respond"]}]},{"@type":"WebPage","@id":"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii","url":"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii","name":"Cross-platform AR\/VR With the Web: WebXR with A-Frame, Angular, and Capacitor (Part II) - Ionic Blog","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii#primaryimage"},"image":{"@id":"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii#primaryimage"},"thumbnailUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2024\/07\/boxcap-feature-image.png","datePublished":"2025-05-12T21:14:03+00:00","dateModified":"2025-05-12T21:14:04+00:00","breadcrumb":{"@id":"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii#primaryimage","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2024\/07\/boxcap-feature-image.png","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2024\/07\/boxcap-feature-image.png","width":2240,"height":1120},{"@type":"BreadcrumbList","@id":"https:\/\/ionic.io\/blog\/cross-platform-ar-vr-with-the-web-webxr-with-a-frame-angular-and-capacitor-part-ii#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/ionic.io\/blog"},{"@type":"ListItem","position":2,"name":"Cross-platform AR\/VR With the Web: WebXR with A-Frame, Angular, and Capacitor (Part II)"}]},{"@type":"WebSite","@id":"https:\/\/ionic.io\/blog\/#website","url":"https:\/\/ionic.io\/blog\/","name":"ionic.io\/blog","description":"Build amazing native and progressive web apps with the web","publisher":{"@id":"https:\/\/ionic.io\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/ionic.io\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/ionic.io\/blog\/#organization","name":"Ionic","url":"https:\/\/ionic.io\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png","width":1920,"height":854,"caption":"Ionic"},"image":{"@id":"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/ionicframework"]},{"@type":"Person","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/07a04c81f6b3180076d1a6ac967bc562","name":"Logan Brade","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/image\/","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/03\/IMG_2854-150x150.jpg","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/03\/IMG_2854-150x150.jpg","caption":"Logan Brade"},"sameAs":["https:\/\/www.linkedin.com\/in\/loganbrade\/","https:\/\/x.com\/loganbrade"],"url":"https:\/\/ionic.io\/blog\/author\/logan-brade"}]}},"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2024\/07\/boxcap-feature-image.png","_links":{"self":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/6389","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/users\/103"}],"replies":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/comments?post=6389"}],"version-history":[{"count":18,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/6389\/revisions"}],"predecessor-version":[{"id":6416,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/6389\/revisions\/6416"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/media\/6198"}],"wp:attachment":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/media?parent=6389"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/categories?post=6389"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/tags?post=6389"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}