The world of head-mounted display (HMD) hardware technologies is buzzing with recent advancements, sparking a wave of fresh interest among consumers. From virtual reality (VR) and mixed reality (MR) to spatial computing, major tech companies and new startups alike are actively investing the launch of the next generation of immersive computing devices. This article will guide you through the rising popularity of HMDs, demonstrate how to use your existing skills for these new platforms, and explore the potential of flat applications on the Meta Quest 3.

Industry Overview

Ongoing investments in HMD technology has improved it over earlier generations of hardware. New HMDs, like Meta's Quest 3 and Apple's Vision Pro, have enhanced the tracking, camera, and display capabilities that enable seamless mixed reality or spatial computing experiences. Using the device's camera, the HMD displays a live view of the real world around you while positioning high-resolution 2D and 3D graphics within the environment. Although 3D graphics are used for immersive experiences, you'll find that 2D applications have found a more traditional role within HMDs. Because of the high-resolution displays, users have gravitated toward using 2D applications within the augmented environment, freeing themselves from desktop monitors. It's still early, but HMDs are already cementing their future as office workstation replacements.

Using the device's camera, the HMD displays a live view of the real world around you while positioning high-resolution 2D and 3D graphics within the environment.

Immersive Applications and Devices

If you've used an HMD, it's likely that you've experienced a fully immersive application. This type of app completely changes the user's environment for the purpose of virtual reality (VR) or mixed reality (MR). The most common type of immersive applications are VR games. In a VR game, the user's entire vision is replaced with a 3D-rendered environment and the user is completely immersed in the virtual environment.

Immersive MR experiences are less common because they require more advanced hardware and software capabilities. In an immersive MR app, the HMD either needs to be transparent or uses cameras to capture the user's view of the real world and display it in real time. In addition, the HMD needs to analyze spatial data including the user's surroundings, position, and objects within the space. The spatial data is then used to augment the user's view and immerse them in the activity being performed in the application.

Apple, Microsoft, Meta, and have all appeared on the market with different approaches, technologies, capabilities, and vocabulary for their HMDs.

  • Apple Vision Pro: Apple is the latest to enter the market with the Apple Vision Pro. The Vision Pro is marketed as the “first spatial computer.” Apple borrows technology from the telescope industry by using catadioptric lenses (that combine refraction and reflection) in their HMD. An opaque high-density screen is viewed through the lenses immersing the user. HD cameras and a spatial processor produce an immersive “Spatial Computing” environment. Even though the Vision Pro is capable of VR applications, Apple has specifically targeted the device as an immersive operating system. The focus of the Vision Pro is its visionOS operating system (OS) for either immersive applications or flat applications displayed within its OS environment. The Vision Pro is meant for a consumer audience and is priced at $3500.
  • HoloLens: Microsoft first entered the market with the HoloLens. The HoloLens device focuses on immersive “holographic” MR applications. This HMD is a transparent visor to project holograms on top of the user's space. The user interacts with the projections using touch and voice gestures recognized by the headset. Because the focus of this device is a holographic MR, it doesn't typically make use of VR or other computing modes. HoloLens is targeted at enterprise applications and priced between $3500 and $5200, depending on the model.
  • Quest 3: Meta has introduced four generations of HMDs including the: Quest, Quest 2, Quest Pro, and the newest model, Quest 3. Although Quest was traditionally a VR headset, Quest Pro introduced an MR mode that was improved in Quest 3. The Quest 3 HMD uses pancake lenses commonly found in photography. Like Apple's device, the Quest 3 uses an opaque high-density screen viewed through the lenses, immersing the user. Two HD cameras and a processor produce an immersive “Mixed Reality Passthrough” environment. Quest 3 has its roots in VR and is breaking into the MR gaming market. In addition, Quest 3 has an immersive-capable Android-based OS. Meta is focused on creating VR/MR “experiences” in the consumer audience and is priced at $350.

In immersive applications, the software takes exclusive control over the user's environment to make use of spatial data and render elements in 3D. Usually, these applications are built using proprietary 3D engines such as Unity, Unreal Engine, AR Core (Google), or AR Kit (Apple). Developing immersive apps using these technologies requires a set of tools, knowledge, and skills different from those used for 2D applications. However, there's an opportunity to reuse existing code and skills by deploying Flat Applications for use in a spatial OS.

The Case for Flat Applications

A flat application denotes a conventional 2D application (originally designed for desktop monitors, mobile screens, or the browser) that has been modified or redeployed to function within a spatial OS. As HMDs have evolved with better representations of the real-world environment, users are considering HMDs as replacements for other computing activities. Having traditional 2D applications in a spatial context gives users the ability to run these apps freely in virtual 3D space versus being constrained to a physical screen. Flat applications can run directly on the device's OS in floating resizable windows. The feeling of openness and lack of boundaries allows users to work from anywhere while multitasking on limitless screen sizes.

Software companies have realized the potential of flat applications and have started preparing for the emergence market. Apple and Meta have designed their operating systems and app stores to accommodate flat applications and have delivered their first-party applications. Because Apple isn't focused on immersive apps, it relies on flat applications to fill out its offering by including Safari, Mail, FaceTime, Keynote, Notes, Apple TV +, and many more. Although Meta is focused on immersive apps, it does offer a few of its own with Meta Quest Browser, Instagram, and Quest TV. Other big names are releasing flat apps on both platforms as well. Microsoft has released the Microsoft Office suite, including Power Point, Excel, and Word, as shown in Figure 1. Although Meta may have fewer native flat apps, its focus on affordability, visual quality, and developer support makes it a compelling choice for bringing apps to the platform.

Figure 1: This is Microsoft Word running as a flat application in a mixed reality passthrough.
Figure 1: This is Microsoft Word running as a flat application in a mixed reality passthrough.

The Meta Quest 3 Platform

Despite having the fewest first-party flat apps, Meta's platform strategically emphasizes several key advantages. The Meta platform offers a low price point, making it accessible to a wide range of users. Its high-resolution display (2064 x 2208 resolution per eye) and full color passthrough is suitable for productivity purposes. Quest 3's spatial OS allows multitasking with up to three flat applications at once. In addition, Meta has intentionally created a low barrier to entry for developers by choosing the ubiquitous Android OS and supporting Progressive Web Applications (PWAs).

You'll enter Quest's passthrough mode through the interface shown in Figure 2, which is activated by double tapping on the headset or pressing the Enter passthrough mode button from the system's taskbar. Once in passthrough, you'll see the live environment displayed in real-time with the user interface and applications displayed spatially in your surroundings.

Figure 2: The Meta Quest taskbar in Mixed Reality Passthrough floats over the real-world environment.
Figure 2: The Meta Quest taskbar in Mixed Reality Passthrough floats over the real-world environment.

In passthrough mode, you can open three flat applications from the taskbar, as shown in Figure 3. Applications you use in this mode can be resized and rearranged. Using the Quest controllers or gestures from the device's hand tracking capabilities, you grab the edges of an application as if you were using a mouse on the desktop.

Figure 3: The Quest 3 operating system multitasking with three applications displayed: (left to right) App Library, Microsoft Word, Meta Quest Browser.
Figure 3: The Quest 3 operating system multitasking with three applications displayed: (left to right) App Library, Microsoft Word, Meta Quest Browser.

Although multitasking is built into the system's OS, there are third-party applications that offer additional capabilities such as virtual monitors, remote desktop, and collaborative experiences. Because immersive experiences take control over the full user experience, multitasking only works with flat applications. When you launch an immersive experience from within an app or from the taskbar, it hides the OS and all flat applications in your current view.

When you launch an immersive experience from within an app or from the taskbar, it hides the OS and all flat applications in your current view.

Meta has made the platform accessible to developers, and you can deploy and submit your own applications to the Meta Store. Most applications that you've written for the Android operating system that compile to an Android Package Kit (APK) can also deploy to the device. In addition, the ecosystem is open to Progressive Web Applications (PWAs) as well. The only warning with PWAs is that they must be deployed through the app store as an APK, which is accomplished with Meta's command line tool. You'll find that the developer toolchain used for the Quest is quite intuitive as the developer experience integrates with the headset.

Developer Tools

Setting up the developer environment and making sure you have the prerequisites installed is necessary to be successful when writing applications for the Quest. You can consider developing for the Quest as “mobile development” because it follows many of the same principles and uses similar tooling. In addition to the typical development tools, there are platform-specific tools as well. There's an extensive list of prerequisites with each item having its own purpose. You'll find a list of each tool in Table 1 categorized by application name, type, and purpose. Every tool here is used in the Software Development Life Cycle (SDLC) from unlocking developer mode on the device, to writing code, and to publishing.

Quest Mobile App

The Quest Mobile app is required to use the device and part of the standard installation process when you buy a new headset. Using the app, you'll connect to the headset over Wi-Fi or Bluetooth. Once connected, you can manage basic features of the device, manage software bought through the app store, and enable developer mode. To enable developer mode on your device, follow the steps shown in Figure 4. Start by choosing Headset settings (marked as 1 on the image) on the desired device. Next, from settings, choose Developer Mode (marked as 2). Finally, enable Debug Mode (marked as 3), which allows you to connect the device to a PC using a USB cable. Once debugging is enabled, you can use the Quest Developer Hub on your device.

Figure 4: The Quest Mobile App is used to unlock a device's developer mode by selecting settings (1), developer mode (2), and debug mode (3).
Figure 4: The Quest Mobile App is used to unlock a device's developer mode by selecting settings (1), developer mode (2), and debug mode (3).

Quest Developer Hub

The Quest Developer Hub is a desktop application used to manage the development experience on the Quest device. This app helps you manage the development experience of your device by connecting to the device and managing deployments and remote controlling actions on the device, as shown in Figure 5. When you connect your device to the PC via USB cable, your device is displayed in the Devices section (marked as 1 on the image). In the Devices section, you can reboot your device, power down, and configure more settings. Below the Devices section on the UI shown in Figure 5 is the Apps section (marked as 2). In the Apps section, you'll see applications that have been loaded on the device. In addition, the Apps section can be used to deploy apps to the device by clicking Add Build or dragging and dropping an APK file into the section. The last section is the Device Actions section (marked as 3), which has the most variety of uses. In the first column of the Device Actions section are the most used features. From here you can cast the device's display to your PC screen, record videos, take screen captures, and push URLs to the Meta Quest Browser.

Figure 5: The Quest Developer Hub allows you to manage development activities on the Quest including Devices (1), App deployments (2), and Device Actions (3).
Figure 5: The Quest Developer Hub allows you to manage development activities on the Quest including Devices (1), App deployments (2), and Device Actions (3).

Visual Studio

Visual Studio is an essential development tool for writing web, mobile, and desktop applications. There are several workloads that you'll need in order to write applications for the Quest. Through the Visual Studio Installer, you'll manage your workloads as shown in Figure 6.

Figure 6: The Visual Studio Installer's workloads configuration screen. In this configuration, the ASP.NET and web development (1) and.NET Multi-platform App UI development (2) workloads are installed.
Figure 6: The Visual Studio Installer's workloads configuration screen. In this configuration, the ASP.NET and web development (1) and.NET Multi-platform App UI development (2) workloads are installed.

First is the ASP.NET and web development workload. You'll need this workload to write Blazor PWAs and ASP.NET Core for serving Blazor applications. When working with web-based applications and the Quest, you'll also make use of Visual Studio's Dev tunnels, a feature that's included in the ASP.NET workload. When working with mobile devices like the Quest, the device needs access to locally hosted web resources (localhost). Dev tunnels are used to create a connection between devices that cannot directly access each other. This feature is useful for testing locally hosted web applications on the Quest.

The second item is the .NET Multi-Platform App UI development (.NET MAUI) workload. This workload is what you'll use to write applications that target the Android OS. This includes the .NET MAUI application using XAML or Blazor Hybrid, an application that uses HTML, CSS, and C#. Both types of app compile to APK and can be deployed to the Quest as a flat application.

Meta Quest CLI

All publicly available applications for the Quest must be published through the official Quest store. This means that if you develop a PWA, it too must be published and installed via the app store. The Meta Quest create-app CLI tool is a packaging tool used to wrap your PWA as an APK so it can be delivered through the app store. The tool requires other dependencies on Java and the Android SDK. You'll find the full installation instruction in the Meta developer documentation under PWA tools and Packaging.

Quest Remote Desktop

The Quest Remote Desktop application is a Quest application that runs on the device and connects to a remote PC. You'll need to download and install a companion app on the PC that will be connected. Remote Desktop isn't necessary for development, but it allows you to access your development PC from within the Quest. Use Remote Desktop to access Visual Studio while using the Quest. You'll find that the developer experience here is quite good on the Quest 3 due to the high-resolution display. This setup also enables you to write, test, and debug flat applications while wearing the device and multitasking with its spatial OS, as shown in Figure 7.

Figure 7: The Quest Remote Desktop (right) displaying Visual Studio on a remote PC while debugging on a .NET MAUI app running on the Quest (left)
Figure 7: The Quest Remote Desktop (right) displaying Visual Studio on a remote PC while debugging on a .NET MAUI app running on the Quest (left)

Meta Quest Browser

The Meta Quest Browser is the default web browser that runs on the Quest device, shown in Figure 8. This browser is built using the open-source Chromium rendering engine, commonly used in popular browsers. It's optimized for WebXR and WebGL, allowing fully immersive 3D experiences. Specifically designed for Meta Quest hardware, it offers fast performance and improved battery life. It's important to note that the Meta Quest Browser isn't the same browser implemented by the device's Web View. When using Blazor Hybrid on .NET MAUI, the WebXR APIs aren't present in the device's Web View.

Figure 8: The Meta Quest Browser running in mixed reality passthrough. The browser shows a webpage from telerik.com.
Figure 8: The Meta Quest Browser running in mixed reality passthrough. The browser shows a webpage from telerik.com.

Flat Applications with .NET

When creating spatial computing applications, you'll have a variety of languages and frameworks to choose from. For immersive app development, it's necessary to use specialized 3D software development tools, such as the .NET-based Unity platform. In contrast, the development of flat applications is more accessible, thanks to .NET's robust support for cross-platform development, sidestepping the intricacies and demands of 3D application development. In addition, you may be able to update existing .NET applications, allowing them to run as flat applications.

Table 2 is a list of .NET stacks that are compatible with building flat applications for the Quest. First is .NET MAUI, a cross-platform application framework. The unified approach of .NET MAUI abstracts the platform-specific details, allowing you to focus on building features rather than dealing with platform complexities. Second is Blazor Hybrid, which is part of .NET MAUI. Blazor Hybrid gives you the benefits of .NET MAUI with the addition of Blazor's component model that uses HTML and CSS to render UI components. The third choice is Blazor PWA. Blazor PWA apps use browser-based technologies to build native-like experiences. All these options compile to APKs and deploy on the Quest, and each choice comes with its own benefits. When you build your first Hello World app with each platform, you'll be able to decide which stack works for you.

.NET MAUI

.NET MAUI uses the latest technologies for building native apps on Windows, macOS, iOS, and Android, abstracting them into one common framework built on .NET. You use a single C# codebase and project system for all device targets to build apps that look and feel like native platforms. The .NET runtime is the execution environment for MAUI applications, even though the underlying implementations of the runtime may be different, depending on the host. For example, on Windows, WinRT provides the environment with optimizations for the Windows platform and on Quest, the environment is implemented by Mono, a .NET runtime for Android. The Android features of .NET MAUI make it possible to target the Quest with your application.

In a .NET MAUI application, the code you write mainly engages with the .NET MAUI API, as seen in Figure 9 (marked as 1 on the image). .NET MAUI then directly consumes the native platform APIs, illustrated in Figure 9 (marked as 2). In addition, the application code can directly invoke platform APIs when necessary, shown in Figure 9 (marked as 3).

Figure 9: A block diagram of .NET MAUI. The highlighted items show where Android is implemented in the stack.
Figure 9: A block diagram of .NET MAUI. The highlighted items show where Android is implemented in the stack.

To create your .NET MAUI app, you need the .NET Multi-Platform App UI development workload installed, as you can see in Figure 10. With the workload installed, the .NET MAUI App template is available in Visual Studio. Create a new project and choose the .NET MAUI App template, as highlighted in Figure 10, then click Next to continue through the remaining prompts.

Figure 10: The Create new project dialog in Visual Studio with the .NET MAUI App template highlighted
Figure 10: The Create new project dialog in Visual Studio with the .NET MAUI App template highlighted

Once you've created a .NET MAUI project, you see the project in Visual Studio's Solution Explorer. The project's key files identified in Figure 11 are where you begin working with the application. The first file, MauiProgram.cs (marked as 1 on the image), is the entry point of the application. In MauiProgram.cs, you'll find the startup routines and configuration for the application. The second file, MainPage.xaml (marked as 2), is the default content page for your application's user interface. The third file, MainPage.xaml.cs (marked as 3), is the code-behind logic for the main page's user interface.

Figure 11: The .NET MAUI project's file structure. The key files are highlighted: MauiProgram.cs (1), MainPage.xaml (2), and <a href=
Figure 11: The .NET MAUI project's file structure. The key files are highlighted: MauiProgram.cs (1), MainPage.xaml (2), and

The main page consists of multiple controls that are specified through XAML markup, as shown in the snippet below. In the markup, you'll find a button control that provides basic functionality for the app. The button control here describes a UI element that renders a button natively on the device. The button's Clicked property indicates that it's assigned to the OnCounterClicked delegate method found in respective code-behind file.

<Button
    x:Name="CounterBtn"
    Text="Click me" 
    SemanticProperties.Hint="Counts the number of times you click"
    Clicked="OnCounterClicked"
    HorizontalOptions="Fill" />

To see the logic for this page and the OnCounterClicked action, open and inspect the MainPage.xaml.cs file. In the OnCounterClicked method, you'll see a simple routine that increases the value of the count field and displays the value in the button's text.

private void OnCounterClicked(object sender, EventArgs e)
{
    count++;
    
    if (count == 1)
        CounterBtn.Text = $"Clicked {count} time";
    else
        CounterBtn.Text = $"Clicked {count} times";

    SemanticScreenReader.Announce(CounterBtn.Text);
}

After reviewing the logic for the page, you'll want to start the application and check the functionality. When you work with .NET MAUI in Visual Studio, the Start menu (shown in Figure 12) lets you choose target devices, emulators, and platforms.

Figure 12: The Start menu in Visual Studio expanded to reveal a list of target platform options
Figure 12: The Start menu in Visual Studio expanded to reveal a list of target platform options

For the initial test run, choose Windows Machine from the start menu, then start with debugging. When you click start, the application runs on the Windows desktop, shown in Figure 13. Test the app by clicking the counter button.

Figure 13: The .NET MAUI sample project running on the Windows Desktop
Figure 13: The .NET MAUI sample project running on the Windows Desktop

Once you feel familiar with the application, try starting the app on the Quest device. Begin by opening the Quest Developer Hub and connecting your Quest via USB cable to the development machine. Once you connect the device, you'll see it displayed in Quest Developer Hub's devices section, shown in Figure 14. Make sure that the developer mode is enabled on your device; if it doesn't appear in the Quest Developer Hub, look for any permission prompts on the device's screen, or use the Device menu from Figure 14 and choose Set Up New Device.

Figure 14: The Quest Developer Hub's Devices section with key elements highlighted: the active Quest device (1), the current user (2), and the Device menu (3)
Figure 14: The Quest Developer Hub's Devices section with key elements highlighted: the active Quest device (1), the current user (2), and the Device menu (3)

After connecting your Quest device, return to Visual Studio and use the start menu shown in Figure 15 (marked as 1) to select Android Local Devices (marked as 2), then Oculus Quest 3 (marked as 3).

Figure 15: The Visual Studio start menu expanded (1), and the Android Local Devices selection (2) with the Oculus Quest 3 device shown (3)
Figure 15: The Visual Studio start menu expanded (1), and the Android Local Devices selection (2) with the Oculus Quest 3 device shown (3)

After you've selected the Quest 3 option, start the application in debug mode. You'll need to wait a moment when deploying the project for the first time as it must recompile and deploy. If you're unsure of the process status, you can check the Build Output window to inspect the progress. The build process output should be like the example below:

Found device: {your device id here}
...
2>Deployment was successful to Oculus Quest 3.
========== 
Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped
========== 
Build completed at 2:38 PM and took 13.972 seconds
========== 
Deploy: 1 succeeded, 0 failed, 0 skipped ==========
========== 
Deploy completed at 2:38 PM and took 13.972 seconds
==========
Done building project "MauiApp1.csproj".
Build succeeded.

Once the deployment is complete, you'll see the application appear in the Quest Developer Hub under the Apps section, as shown in Figure 16.

Figure 16: The Quest Developer Hub's Apps section with a highlight showing where deployed .NET MAUI apps are listed
Figure 16: The Quest Developer Hub's Apps section with a highlight showing where deployed .NET MAUI apps are listed

Using the Quest, you'll see the application displayed as a floating window, as shown in Figure 17. From this view, you can interact with the application using the Quest's controllers or using the device's the built-in hand-tracking capabilities. The app can be resized and moved to one of three positions within your view.

Figure 17: The .NET MAUI sample app displayed in the Meta Quest 3's spatial OS
Figure 17: The .NET MAUI sample app displayed in the Meta Quest 3's spatial OS

You can debug the application running on the device from Visual Studio. Instead of removing the device to debug from the PC, you can use the Quest. First, drag the .NET MAUI app to a secondary location on either side of the center position. Then open the Quest Remote Desktop app from the device. Next, connect to the PC where Visual Studio is running and view the windows side-by-side, as shown in Figure 18. Using the PC's mouse and keyboard, set a break point in the OnCounterClicked method. On the running application, click the Count button until the breakpoint triggers. When the app pauses for debugging, it may cause the Quest to display the message “The app has stopped responding.” Choose “Wait” from the menu to continue.

Figure 18: Visual Studio via remote desktop debugging the .NET MAUI sample app from the Meta Quest 3's spatial OS
Figure 18: Visual Studio via remote desktop debugging the .NET MAUI sample app from the Meta Quest 3's spatial OS

After familiarizing yourself with the basics of .NET MAUI, you'll want to test the platform integration aspects of .NET MAUI. .NET MAUI's unified platform API allows you to access native platform functionality when supported by the platform. Because the Quest 3 isn't a smartphone, some common hardware doesn't exist, or the APIs are restricted by Meta. You can learn a lot from the comprehensive set of platform integration examples found in the PlatformIntergrationDemo project that's part of the dotnet/maui-samples repository https://github.com/dotnet/maui samples. From Visual Studio, select Clone Repository from the File menu and then enter the repository location, as shown in Figure 19.

Figure 19: The GitHub dialog box from Visual Studio cloning the maui-samples.git repo
Figure 19: The GitHub dialog box from Visual Studio cloning the maui-samples.git repo

After you clone the repo, open the PlatformIntegrationDemo solution. In this solution, you'll find forty samples of .NET MAUI APIs that support platform features. Not every feature works on Quest, but the demo serves as a quick way for you to discover and test the Quest platform from .NET MAUI code. Use the Start menu to select Oculus Quest 3, and then start the app with debugging enabled. Explore the application using your Quest, and then exercise the demos to see what features work, as shown in Figure 20. If a feature isn't supported, the application displays the message “Specified method is not supported.”

Figure 20: Running the Platform integration demos for the .NET MAUI application
Figure 20: Running the Platform integration demos for the .NET MAUI application

In the File System demo, you'll see how to read and write to the Quest's storage using the .NET File IO. Select the file demo in the running application, as shown in Figure 21.

Figure 21: The File System demo featured in the platform integration demo app
Figure 21: The File System demo featured in the platform integration demo app

Now inspect the corresponding code in ViewModels/FIleSystemViewModel.cs. Find the DoLoadFile method and add a breakpoint to lines 43 and 50, as referenced in the code snippet below. Next, click the Load button on the application and you'll see the breakpoint on line 50 activate. This part of the code has checked the Quest filesystem for an existing text file that wasn't found. The next line then reads from a file in the application's internal resource. Continue running the application and then click Save to create a new file in the filesystem. Now that a file exists in storage, clicking the load button a second time triggers the breakpoint at line 43. This time, the code reads the saved file from storage.

Async void DoLoadFile()
{
    if (File.Exists(localPath))
    {
        //Line 43
        CurrentContents = File.ReadAllText(localPath);
    }
    else
    {
        Using (var stream = await FileSystem.
          OpenAppPackageFileAsync(templateFileName))
        using (var reader = new StreamReader(stream))
        {
            //Line 50
            CurrentContents = await reader.ReadToEndAsync();
        }
    }
}

Now that you're familiar with .NET MAUI, let's explore another UI option. If you're a developer with technical skills from web development, you may be unfamiliar with .NET MAUI's XAML implementation. For a web developer, Blazor Hybrid may be a better fit.

Blazor Hybrid with .NET MAUI

Blazor Hybrid is built upon .NET MAUI's API while adding in a web presentation layer powered by the Blazor framework. When you use Blazor Hybrid, you get platform API access and a rich HTML UI component model. Blazor Hybrid support is built into the .NET MAUI framework. .NET MAUI includes the BlazorWebView control that permits rendering Razor components into an embedded Web View. By using .NET MAUI and Blazor together, you can reuse one set of web UI components across mobile, desktop, and web. This approach is ideal if you've worked with ASP.NET or have an existing Blazor application you want to deploy beyond the web browser. Even third-party UI component libraries, like Telerik UI for Blazor, are supported with Blazor Hybrid applications, giving you the ability to use hundreds of UI components.

To create your Blazor Hybrid with .NET MAUI app, you need the .NET Multi-Platform App UI development workload installed. To do this, refer back to Figure 6. With the workload installed, the .NET MAUI App template is available in Visual Studio. Create a new project and choose the .NET MAUI App template, as shown in Figure 22, then click Next to continue through the remaining prompts.

Figure 22: The Visual Studio Create project dialog with the.NET MAUI Blazor Hybrid template selected (highlighted)
Figure 22: The Visual Studio Create project dialog with the.NET MAUI Blazor Hybrid template selected (highlighted)

Once you've created your Blazor Hybrid project, you'll see the project in Visual Studio's Solution Explorer. The project's key files are identified in Figure 23, where you'll begin working with the application. The first file, MauiProgram.cs (marked as number 1 on the figure) is the entry point of the application. In MauiProgram.cs, you find the startup routines and configuration for the application. The second file, MainPage.xaml (marked as number 2) is where the BlazorWebView gets rendered. Next are the Razor components that are located under the Pages folder (marked as number 3). The three files: Home.razor, Counter.razor, and Weather.razor represent the examples in the app with corresponding names (Home, Counter, Weather).

Figure 23: The file structure of the Blazor Hybrid project with key files highlighted: MauiProgram.cs (1), MainPage.xaml (2), and Pages folder (3) with three component samples
Figure 23: The file structure of the Blazor Hybrid project with key files highlighted: MauiProgram.cs (1), MainPage.xaml (2), and Pages folder (3) with three component samples

The main page in Blazor Hybrid is written using XAML and contains a BlazorWebView control. The BlazorWebView is the root UI control for the application and displays Blazor pages and components. When the application is initialized, the BlazorWebView bootstraps Blazor, the HostPage property defines the HTML file to use: wwwroot/index.html. Next, the ComponentType property chooses the Razor component that appears in the BlazorWebView. Because Routes is the app router and the Home.razor component has the base route, the Home component is the first component rendered by the application.

    <BlazorWebView x:Name="blazorWebView" HostPage="wwwroot/index.html">
        <BlazorWebView.RootComponents>
            <RootComponent Selector="#app" 
                           ComponentType="{x:Type local:Components.Routes}" />
        </BlazorWebView.RootComponents>
    </BlazorWebView>

After reviewing the logic for the page, you'll want to start the application and check the functionality. To test the application, choose Oculus Quest 3 from the start menu, then start with debugging. When the application starts, you'll be greeted with the Home page and a menu containing three items. Choose the Counter menu item to view the example shown in Figure 24. The Counter example is like the .NET MAUI project's sample, but the Blazor Hybrid version uses HTML and Razor instead of XAML.

Figure 24: The Blazor Hybrid application displaying the counter page, viewed through the Quest 3
Figure 24: The Blazor Hybrid application displaying the counter page, viewed through the Quest 3

In the Pages folder, you'll find the Counter.razor component that contains the code for the Counter page. An excerpt is shown in the snippet below. The Counter uses a standard HTML button element. The button's onclick event is bound using Razor syntax to delegate the event to the IncrementCount method in C# code. When the IncrementCount method is triggered, the currentCount field value is updated and displayed in the preceding p element.

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" 
@onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

With the application running in debug mode, you can inspect the contents of the WebView. To inspect the WebView, open a Chrome-based browser (Chrome or Edge) on the host PC. Enter the address chrome|edge://inspect in the browser's address bar, then look for the application name to be displayed in the Remote Target heading, as shown in Figure 25.

Figure 25: Using Edge via Quest Remote Desktop, the browser's debug window is open showing the app running remotely on the Quest.
Figure 25: Using Edge via Quest Remote Desktop, the browser's debug window is open showing the app running remotely on the Quest.

Below the application name is the “inspect” link that opens the debugger. Click the link to debug your app's rendered HTML, CSS, and JavaScript. For a seamless developer experience, try using the Quest Remote Desktop while debugging the application and running side-by-side in the Quest, as seen in Figure 26.

Figure 26: Use Edge to remotely debug the HTML of the .NET MAUI WebView via Remote Desktop.
Figure 26: Use Edge to remotely debug the HTML of the .NET MAUI WebView via Remote Desktop.

Blazor Hybrid offers a balance between .NET and web development by combining the two in a native package. With Blazor Hybrid, you can leverage .NET MAUI's cross platform APIs directly from Razor code. From a cross-platform perspective, Blazor Hybrid offers the most flexibility. If you'd like to take a pure web approach, Blazor Progressive Web Apps (PWAs) are an option.

Blazor PWAs

Blazor Progressive Web Apps use web standard technology to create applications that run in the browser and have features that parallel native platform applications. Blazor PWAs use the .NET Runtime for WebAssembly to execute .NET code in the browser. When a Blazor PWA runs on Quest, it has complete access to the Meta Quest Browser and any APIs it supports. To test the Quest Browser's API support, try visiting What PWA Can Do Today using the Quest Browser.

You can also repackage existing Blazor WebAssembly applications with relative ease, thus making them discoverable through the Quest Store and browser. Web apps that have a PWA in the Quest Store prompt users to install it on their devices, as shown in Figure 27.

Figure 27: The Install App prompt is shown in the Quest Browser when a PWA can be installed from the Quest Store.
Figure 27: The Install App prompt is shown in the Quest Browser when a PWA can be installed from the Quest Store.

To create your Blazor PWA app, you need the ASP.NET and web development workload installed. To do this, refer back to Figure 6. With the workload installed, the Blazor Standalone App template is available in Visual Studio. Create a new project and choose the Blazor Standalone App template, as shown in Figure 28, and then click Next to continue through the next prompts.

Figure 28: The Visual Studio Create dialog with the Blazor WebAssembly Standalone App template (highlighted)
Figure 28: The Visual Studio Create dialog with the Blazor WebAssembly Standalone App template (highlighted)

On the Additional information menu, select the Progressive Web Application option. Enabling this option adds the supporting resources required for your app to qualify as a PWA, as shown in Figure 29. After enabling this option, click Create to generate the solution.

Figure 29: The Additional information dialog for a Blazor WebAssembly Standalone App. A Progressive Web Application option is selected to include PWA support.
Figure 29: The Additional information dialog for a Blazor WebAssembly Standalone App. A Progressive Web Application option is selected to include PWA support.

Once you've created your Blazor PWA project, you'll see the solution in Visual Studio's Solution Explorer. The project's key files, as identified in Figure 30, are where you begin working with the application.

Figure 30: A Blazor PWA project's file structure with key files highlighted: Program.cs (1), the Pages folder with three component files (2), and manifest.webmanifest (3)
Figure 30: A Blazor PWA project's file structure with key files highlighted: Program.cs (1), the Pages folder with three component files (2), and manifest.webmanifest (3)

The first file, Program.cs, is the entry point of the application. In Program.cs, you'll find the startup routines and configuration for the application. Next are the Razor components that are located under the Pages folder. The three files, Home.razor, Counter.razor, and Weather.razor, represent the examples in the app with corresponding names (Home, Counter, Weather). The next notable file is mainifest.webmainfest, which contains your application's metadata. You set values in the manifest to represent your app's name, home screen icon, and start URL.

Get familiar with the application by starting it locally on your PC. Choose https and start with Debugging enabled to launch the application. When your application is started, it launches in the browser, and you'll see localhost in the browser's address bar, as shown in Figure 31. As you explore the app's sample pages, you'll notice that the project is nearly identical to those found in the Blazor Hybrid project.

Figure 31: The Blazor Progressive Web Application running in a web browser with the web address “localhost”
Figure 31: The Blazor Progressive Web Application running in a web browser with the web address “localhost”

At this point, you'll want to try the application on the Quest's browser, but the device can't directly connect to the localhost development server. Unlike .NET MAUI applications, a Blazor PWA project can't be started directly on the Quest. Instead, you need to host the application locally and use the dev tunnels feature to access it. The dev tunnels feature acts like a virtual private network (VPN) but is scoped to your .NET application. The dev tunnels feature is included with the ASP.NET workload and appears in the expanded start menu. To create a new dev tunnel, expand the Start menu and select Create a Tunnel, as shown in Figure 32.

Figure 32: Visual Studio's Start menu expanded to show the Create a Tunnel menu in the Dev Tunnels section
Figure 32: Visual Studio's Start menu expanded to show the Create a Tunnel menu in the Dev Tunnels section

Next, configure the dev tunnel by connecting your Microsoft account, naming the tunnel, assigning a lifetime, and setting the scope of access. The dev tunnels dialog, shown in Figure 33 uses the settings, Name: demoTunnel, Tunnel Type: Persistent, and Access: Public. Once the settings are entered, you'll see a confirmation dialog letting you know the process is complete.

Figure 33: Visual Studio's dev tunnels configuration dialog with the settings used for this example
Figure 33: Visual Studio's dev tunnels configuration dialog with the settings used for this example

With the dev tunnel created, expand the Start menu again to choose the dev tunnel by name, as seen in Figure 34. Now start your application without debugging. When the application starts, it opens a browser window and displays an information message. Click Continue from the dialog to access your app. The browser's address bar displays a generated address ending with devtunnels.ms. You use this address to connect to your application from any device outside your network.

Figure 34: Visual Studio's Start menu expanded to show the selected dev tunnel, demoTunnel
Figure 34: Visual Studio's Start menu expanded to show the selected dev tunnel, demoTunnel

Copy the address from the browser's address bar, as shown in Figure 35. Next, open the Quest Developer Hub with your device connected and paste the address into the Open URL field under Device Actions. After you've entered the URL, click Open to launch the Meta Quest Browser on the device using your dev tunnel address.

Figure 35: Opening a web app that uses dev tunnels displays a connection prompt before accessing the app
Figure 35: Opening a web app that uses dev tunnels displays a connection prompt before accessing the app

Now that you've successfully launched the app from the Quest, you'll want to test it as a deployable PWA that can be submitted to the Quest Store. A deployable PWA doesn't use the browser directly; instead it looks like a standard platform application running on the Quest's spatial OS. For the application to be deployed, you'll need to package it as an Android APK using Quest's command line tool. Start by prepping your manifest by opening the file and entering the dev tunnel's URL as the start_url value, as shown in the snippet below.

...  
"start_url": "https://your-url.devtunnels.ms/";,
...

Next, you'll need to use the Quest create-pwa command line tool to create an APK from your application. Install the Quest create-pwa tool and its prerequisites. Then ensure that your application is running and the dev tunnel is working. Next, open a command window and target your app's manifest file using create-pwa. An example of the completed command is shown in the snippet below.

ovr-platform-util.exe create-pwa 
-o blazor-pwa-outputAPK 
--android-sdk C:\{androidSDK path} 
--package-name com.blazorapp1.pwa
--manifest-content-file ".\path\manifest.webmanifest"

Once the command completes, find the file specified by the command's output parameter. For this example, the file name is blazor-pwa-outputAPK. To deploy the app, drag-and-drop the file into the Quest Developer Hub from the Windows File Explorer. After the deployment, you'll find the app in your Quest's library under unknown sources, as shown in Figure 35.

Figure 36: The Quest Library with Unknown sources (1) highlighted and the BlazorApp1 (PWA) application (2) listed in the library
Figure 36: The Quest Library with Unknown sources (1) highlighted and the BlazorApp1 (PWA) application (2) listed in the library

The Blazor PWA opens on the Quest in a native application shell, as shown in Figure 36. The shell displays the application so it appears as a native application to the user.

Figure 37: A Blazor PWA running on the Quest's spatial OS in a native shell
Figure 37: A Blazor PWA running on the Quest's spatial OS in a native shell

If you're a web developer using Blazor, the option of using a PWA so you can deploy on Quest is compelling. With this deployment model, it's possible to “lift and shift” an existing Blazor PWA by repackaging your application using Meta's create-pwa tool.

Conclusion

As HMD hardware and software advance, they open new possibilities for developers. These days, the market is showing interest in consumers using HMDs as desktop replacement options. As consumers shift from gaming on these devices to using them for daily computing tasks, the need for flat applications will follow. Because the Meta Quest 3's platform uses Android as its operating system, it's accessible to many developers. There are currently three ways to deploy flat applications on the Quest using the .NET stack including: .NET MAUI, Blazor Hybrid, and Blazor PWA. Each stack complements a certain .NET developer skill set, whether it's XAML, HTML, or web standards. As a .NET developer, you should look at your current flat applications and experiment with them on the Quest 3. There just may be an opportunity to bring your app into the future using spatial computing.

Table 1: Developer Tools

ApplicationApp TypePurpose
Quest Mobile AppPhoneManage developer mode on the Quest headset.
Quest Developer HubDesktopManage the Quest device, app deployments, and casting.
Visual StudioDesktopDevelop and debug applications using the ASP.NET and web development workload and .NET multi-platform app UI development workloads. Access localhost with Dev Tunnels.
ChromeDesktopRemotely debug applications running web-based user interfaces.
Quest Create-PWA CLIPackage PWAs as APK files to deploy on the Quest.
Quest Remote DesktopQuestAccess the developmental desktop to use Visual Studio remotely.
Quest Web BrowserQuestTest PWA applications before packaging them using the `create-pwa` command.

Table 2: Quest-Compatible .NET Stacks

StackUIPlatform
.NET MAUIXAML.NET MAUI, native UI
Blazor HybridHTML, CSS, XAML optionalBrowser API, .NET MAUI
Blazor PWAHTML, CSSBrowser API, .NET Web Assembly