Step 2: Add Build Tool for Packaged WebSpatial Apps
WebSpatial Builder
To enable the WebSpatial API features that current browser engines do not yet support and unlock spatial capabilities, your site must run inside the WebSpatial App Shell.
One way to obtain the WebSpatial App Shell is to package your existing Web project into a Packaged WebSpatial App that can be installed and run independently on spatial-computing platforms such as visionOS.
Another option is to pre-install the WebSpatial Browser app (in development) on the target platform and open the WebSpatial App's URL directly in that browser.
Because you cannot assume that visionOS users have installed - or are willing to install - this browser, packaging your site and distributing it through the app store remains the only way to guarantee that your WebSpatial App is available to visionOS users.
During the development phase, you need to build an app, install it in the visionOS simulator or on your own device, and run it.
During the testing or distribution phase, you need to build an app, submit it to a platform such as App Store Connect for testing on other devices, or eventually publish it in an app store.
@webspatial/builder
covers all of these needs.
WebSpatial Builder is a command-line tool. The main command is webspatial-builder
, which provides three subcommands:
run
webspatial-builder run --base=$XR_DEV_SERVER
It builds a visionOS app from the current WebSpatial project, automatically launches the local visionOS simulator, installs the app, and runs it.
This command is totally for the development phase - the main one you'll use during the development process. It is the fastest way to preview and debug a Packaged WebSpatial App. It is usually combined with a Dev Server: the app built with the run
command needs to load a special website URL generated by the Dev Server, specifically for the WebSpatial App Shell on visionOS.
Apps generated by WebSpatial Builder use the start_url
field of the Web App Manifest to figure out where the HTML for its Start Scene should come from.
The run
command allows you to omit the Web App Manifest temporarily. Builder supplies default app information - including start_url
- when the manifest file is absent.
In a standard PWA project, the start_url
in the Web App Manifest can be set in two ways: one includes the full URL with the production domain, and the other uses a relative path without the domain.
The second option is the best practice, because when running the site locally with a dev server, it'll automatically load the manifest from the local domain, not the production one.
If your start_url
is a full URL with a domain included, The run
command supports a --base
option that allows you to set a root path that includes your local dev server's domain, which will replace the root part of the start_url
.
If the WebSpatial-specific site generated by the dev server uses a different URL root, you can include that in the --base
too.
This way, you don't need to change your manifest or maintain multiple versions just to use the run
command.
If your start_url
is a relative path without a domain, you can still use the --base
option to add the domain (which replaces the starting /
in start_url
).
But if you don't provide the --base
, or if it doesn't include a domain too (like when it only includes the specialized root path used by the WebSpatial-specific dev server), the run
command will bundle all site files within this relative path into the app package, the app will load all the web files directly from your app package.
That makes development a lot more annoying - you won't get hot reloading, and you'll have to repackage and reinstall the app every time you make a change.
Therefore, when you use run
, you almost always need the --base
to specify the root part of the WebSpatial-specific Dev Server URL (for example, http://localhost:3000/webspatial/avp/
).
All other run
's options are optional.
build
webspatial-builder build --base=$XR_PRE_SERVER --bundle-id=$XR_BUNDLE_ID --teamId=$XR_TEAM_ID
Based on your current WebSpatial project, this builds a visionOS app package (an .ipa file) that's signed with your Apple Developer account, so you can test it on your real device (like a Vision Pro).
If your Apple Developer account is an enterprise account, the package can run on other people's devices.
Otherwise, it runs only on devices that sign in with the same account as the developer. In that case, testing on other devices requires the publish
command.
Apps generated by WebSpatial Builder use the start_url
field of the Web App Manifest to figure out where the HTML for its Start Scene should come from.
In a standard PWA project, the start_url
in the Web App Manifest can be set in two ways: one includes the full URL with the production domain, and the other uses a relative path without the domain.
The second option is the best practice, because when running the site locally with a dev server, it'll automatically load the manifest from the local domain, not the production one.
For these on-device tests, the URLs the WebSpatial app loads usually differ from the production URLs. If you want to use a testing URL, you must also include the --base
option when you run build
to supply the full root part (with a domain) of the testing URL.
When you configure start_url
as a relative path, similar to the usage with the run
command, if you either don't use the --base
or only use it to replace the root path without adding a domain, the build
command will package all the website files into the app package for offline use. The app will load everything locally at runtime.
When using the run
command, this offline packaging mode isn't recommended. But the situation differs for the build
command: since it's mainly for internal testing before official release, you might not have a convenient way to deploy the current code as a publicly accessible web URL. Offline packaging avoids that network complications - once installed, the app can run right away.
Additionally, when you use build
, you must always provide --bundle-id
and --teamId
so the visionOS app can be signed.
All other build
's options are optional.
publish
webspatial-builder publish --base=$XR_PROD_SERVER --bundle-id=$XR_BUNDLE_ID --teamId=$XR_TEAM_ID --version=$XR_VERSION --u=$XR_DEV_NAME --p=$XR_DEV_PASSWORD
Builds a visionOS app from the current WebSpatial project, applies an Apple Developer signature, adds the other metadata required by App Store Connect, and automatically submits the build to App Store Connect for later testing, review, and store release.
Apps generated by WebSpatial Builder use the start_url
field of the Web App Manifest to figure out where the HTML for its Start Scene should come from.
In a standard PWA project, the start_url
in the Web App Manifest can be set in two ways: one includes the full URL with the production domain, and the other uses a relative path without the domain.
The second option is the best practice, because when running the site locally with a dev server, it'll automatically load the manifest from the local domain, not the production one.
When you configure start_url
as a relative path, you must always include the --base
option when you run publish
to supply the full root part (with a domain) of the production URL.
Additionally, when you use publish
, you must always provide --bundle-id
, --teamId
, --version
, --u
, and --p
for signing and App Store Connect submission.
All other publish
's options are optional.
npm scripts
You could type the WebSpatial Builder command and all of the options above every time you run it, but that is inefficient. A best practice is to add npm scripts to package.json
so the options become environment variables and you can run WebSpatial Builder through fixed familiar npm commands.
"run:avp": "webspatial-builder run --base=$XR_DEV_SERVER",
"build:avp": "webspatial-builder build --base=$XR_PRE_SERVER --bundle-id=$XR_BUNDLE_ID --teamId=$XR_TEAM_ID",
"publish:avp": "webspatial-builder publish --base=$XR_PROD_SERVER --bundle-id=$XR_BUNDLE_ID --teamId=$XR_TEAM_ID --version=$XR_VERSION --u=$XR_DEV_NAME --p=$XR_DEV_PASSWORD",
Once the command-line options are converted to environment variables, you can store most of them in a dotenv file, so you do not have to set them manually each time.