scripts/setup-displayxr.sh (macOS) and scripts/setup-displayxr.bat
(Windows) are one-command orchestrators that download each DisplayXR
component's release installer from GitHub Releases and run it. They
exist so contributors don't need to chase ~5 separate installer links
to get a working dev box.
Tracking issue: #283. Companion #284 covers the end-user meta-installer; both consume the same
versions.jsonschema.
# macOS
git clone https://github.com/DisplayXR/displayxr-runtime
cd displayxr-runtime
./scripts/setup-displayxr.shThat installs the runtime + bundled sim-display plug-in into
/Library/Application Support/DisplayXR/ and registers it as the active
OpenXR runtime at /etc/xdg/openxr/1/active_runtime.json.
:: Windows — run from an ELEVATED command prompt
git clone https://github.com/DisplayXR/displayxr-runtime
cd displayxr-runtime
scripts\setup-displayxr.batThat installs the runtime, the DisplayXR Shell, and the Leia SR plug-in
into C:\Program Files\DisplayXR\Runtime\ and registers each at
HKLM\Software\DisplayXR\…. The runtime also becomes the active
OpenXR runtime via HKLM\Software\Khronos\OpenXR\1\ActiveRuntime.
| Flag | Effect |
|---|---|
| (none) | macOS: runtime only. Windows: runtime + Shell + Leia plug-in. |
--with mcp |
Also install DisplayXR MCP Tools (now dual-platform: DisplayXRMCPSetup-*.exe on Windows, DisplayXRMCP-*.pkg on macOS). |
--with-demos |
Also install each demo's prebuilt release asset (same download → silent-install → marker-check path as the runtime — no source build, so a contributor's graphics toolchain / Vulkan SDK is irrelevant). A demo with no release asset for this OS warn-and-skips. |
--with-demo-sources |
Clone each DisplayXR/displayxr-demo-* repo into ./demos/<name>/ for building from source. Does not build them — see each demo's README. Independent of --with-demos. |
--dry-run |
Print every download / install command without running it. |
--uninstall |
macOS: chain /Library/Application Support/DisplayXR/uninstall.sh. Windows: silent-uninstall every Publisher=DisplayXR component. |
-h, --help |
Show usage. |
--with, --with-demos, and --with-demo-sources combine freely (pass
both demo flags to install the released demos and clone their sources).
--dry-run works with all other flags.
- macOS 13+ (the runtime targets the macOS 13 SDK; the
.pkgitself enforces a min-OS check). - GitHub CLI (
brew install gh) authenticated viagh auth login. sudo(one prompt up front; the orchestrator keeps the timestamp alive so per-component installs don't re-prompt).
- Windows 10 21H2+ or Windows 11.
- GitHub CLI (
winget install --id GitHub.cli) authenticated viagh auth login. Same requirement asscripts\build_windows.bat. - Elevated command prompt — right-click cmd.exe and choose "Run as administrator". The NSIS installers all write to HKLM + Program Files; non-elevated runs fail with a clearer error than individual installers report.
- PowerShell (preinstalled). The
.batshells out for JSON parsing and the publisher-scan uninstall path. - Install the display vendor's platform runtime first — on a Leia SR box, the SR Platform.
DisplayXR-LeiaSR.dlllinks theSimulatedReality*DLLs, which resolve at load time through the…\LeiaSR\Platform\binentry the SR installer adds to the machinePATH. See below for what happens if you go the other way round.
Nothing is bound at install time — plug-in discovery is registry-driven at
xrCreateInstance — so installing the vendor platform afterwards is
recoverable, not fatal. But two things go quietly wrong if DisplayXR
lands first:
- The end-user meta-bundle skips the vendor plug-in.
DisplayXRBundle-*.exeprobes for the SR Platform on disk at startup and only auto-selects the Leia SR component when it finds it. Installing SR later does not retroactively add the plug-in. Fix: re-run the bundle (ARP → Modify) and tick Leia SR by hand, or runDisplayXRLeiaSRSetup-*.exestandalone — it requires only the DisplayXR runtime, not the SR Platform. (setup-displayxr.batis unaffected; it installs the plug-in unconditionally.) - An installed plug-in silently fails to load.
PATHis captured in a process's environment block at start, anddisplayxr-service.exeauto-starts at logon, so a long-running service keeps the pre-SRPATHand keeps failing theLoadLibrary— the runtime falls back tosim-displayand you get flat 2D with no error. Fix: restart the service (or reboot). Full symptom → diagnosis → fix in Troubleshooting → 3D doesn't weave.
What this orchestrator can actually install depends on which component repos ship an asset for your platform:
| Component | Repo | macOS today | Windows today |
|---|---|---|---|
| runtime | displayxr-runtime |
yes (DisplayXR-Installer-*.pkg) |
yes (DisplayXRSetup-*.exe) |
| shell | displayxr-shell-releases |
— (macOS port deferred, M6) | yes (DisplayXRShellSetup-*.exe) |
| leia_plugin | displayxr-leia-plugin |
— (vendor SDK is Windows-only) | yes (DisplayXRLeiaSRSetup-*.exe) |
| mcp_tools | displayxr-mcp |
yes (DisplayXRMCP-*.pkg) |
yes (DisplayXRMCPSetup-*.exe) |
Empty cells warn-and-skip cleanly: the orchestrator does not abort when a component lacks an asset for the pinned tag.
Top-level pin file. Bump a value here to roll the dev box forward:
{
"runtime": "v1.4.3",
"shell": "v1.2.5",
"leia_plugin": "v1.0.3",
"mcp_tools": "v0.3.2",
"gauss_demo": "v1.4.1",
"modelviewer_demo": "v0.7.0",
"mediaplayer_demo": "v1.0.0"
}Each value must be a tag that exists in the corresponding repo's GitHub
Releases — both orchestrators validate with gh release view <tag>
before attempting any download.
Repo URLs and asset name globs live alongside in
scripts/lib/components.sh (sourced
by the macOS script; mirrored inline at the top of the Windows .bat
because batch can't source bash). The same table is intended to be
re-used by future scripts in displayxr-installer (#284) so all
consumers agree on what each component is.
The orchestrators do exactly this, plus pin validation, sudo / elevation priming, smoke verification, and graceful handling of missing-asset edge cases.
gh release download v1.4.3 \
--repo DisplayXR/displayxr-runtime \
--pattern 'DisplayXR-Installer-*.pkg' \
--dir /tmp/dxr
sudo installer -pkg /tmp/dxr/DisplayXR-Installer-*.pkg -target /:: From an elevated cmd
gh release download v1.4.3 --repo DisplayXR/displayxr-runtime --pattern "DisplayXRSetup-*.exe" --dir %TEMP%\dxr
%TEMP%\dxr\DisplayXRSetup-*.exe /S
gh release download v1.2.5 --repo DisplayXR/displayxr-shell-releases --pattern "DisplayXRShellSetup-*.exe" --dir %TEMP%\dxr
%TEMP%\dxr\DisplayXRShellSetup-*.exe /S
gh release download v1.0.3 --repo DisplayXR/displayxr-leia-plugin --pattern "DisplayXRLeiaSRSetup-*.exe" --dir %TEMP%\dxr
%TEMP%\dxr\DisplayXRLeiaSRSetup-*.exe /SAfter a successful run you should see:
/Library/Application Support/DisplayXR/
├── DisplayProcessors/200-sim-display.json
├── lib/openxr_displayxr.dylib
├── lib/displayxr/plugins/DisplayXR-SimDisplay.dylib
├── openxr_displayxr.json
└── uninstall.sh
/etc/xdg/openxr/1/active_runtime.json -> /Library/Application Support/DisplayXR/openxr_displayxr.json
To run a test app against the system install:
XR_RUNTIME_JSON="/Library/Application Support/DisplayXR/openxr_displayxr.json" \
./_package/DisplayXR-macOS/bin/cube_handle_metal_macosThe log should contain active plug-in: id=sim-display.
Registry markers each component writes:
HKLM\Software\DisplayXR\Runtime\InstallPath = C:\Program Files\DisplayXR\Runtime
HKLM\Software\DisplayXR\WorkspaceControllers\shell (Shell)
HKLM\Software\DisplayXR\DisplayProcessors\leia-sr (Leia plug-in)
HKLM\Software\DisplayXR\Capabilities\MCP\Enabled = 1 (MCP Tools)
HKLM\Software\Khronos\OpenXR\1\ActiveRuntime (active runtime symlink-equivalent)
To launch the spatial workspace shell:
"C:\Program Files\DisplayXR\Runtime\displayxr-shell.exe" path\to\app.exeThe shell auto-starts the service, sets XR_RUNTIME_JSON, and launches
the app inside a spatial window.
./scripts/setup-displayxr.sh --uninstallChains /Library/Application Support/DisplayXR/uninstall.sh (which
ships inside the .pkg) so the uninstall logic stays a single source
of truth.
:: From an elevated cmd
scripts\setup-displayxr.bat --uninstallScans HKLM\…\Uninstall\* for entries with Publisher=DisplayXR and
runs each one's QuietUninstallString (falling back to
UninstallString /S). This covers runtime, Shell, Leia plug-in, and
MCP Tools in one pass regardless of which were installed.
Cloned demo directories under ./demos/ are left in place on both
platforms — they may carry local changes and the orchestrator refuses
to blindly remove them.
You already have the repos cloned and the components installed — you just want to move to the latest pinned matrix and/or pick up tooling changes. There are two independent things you might mean by "update":
Pull displayxr-runtime (the orchestrator + the pin file live here)
and re-run the orchestrator. It re-downloads each component at its
currently-pinned tag and re-installs — a no-op for components already
at that version, an upgrade for the rest.
# macOS
cd <displayxr-runtime>
git pull
./scripts/setup-displayxr.sh # add --with mcp / --with-demos as before:: Windows — elevated cmd
cd <displayxr-runtime>
git pull
scripts\setup-displayxr.batYou do not need to pull the sibling repos for this — the orchestrator downloads released installers from each component's GitHub Releases page, it does not build from your local clones.
The /dxr-release and /installer-release skills live git-tracked
only in displayxr-runtime/.claude/skills/ and are symlinked into
your user-level skills dir so they're invocable from any directory.
After pulling runtime, refresh the symlinks without touching installed
components:
# macOS / Linux
cd <displayxr-runtime>
git pull
./scripts/link-dxr-skills.sh # --check to inspect, --unlink to undo:: Windows — needs an elevated cmd OR Developer Mode (mklink /D requires it)
cd <displayxr-runtime>
git pull
scripts\link-dxr-skills.bat :: --check to inspect, --unlink to undoPath A already runs the linker as its last step, so a full refresh covers both. Use Path B when you only want the skills current.
Why only
displayxr-runtime? The skills used to be copied into each sibling repo; they were consolidated into the runtime hub (parameterized:/dxr-release <component> <version>, e.g./dxr-release mcp v0.3.4). The skill clones the target repo to a temp dir at release time, so your local sibling checkouts can be arbitrarily stale and/dxr-releasestill works. Pull the sibling repos only when you do hands-on source work in them. Full design:docs/specs/runtime/versions-json-autobump.md.
Windows symlink caveat:
mklink /Dsilently needs privilege. In a plain (non-elevated) terminal without Developer Mode,link-dxr-skills.batreportscould not link … (needs admin or Developer Mode)and creates nothing. Run the terminal as Administrator, or enable Developer Mode once (Settings → Privacy & security → For developers). Path A never hits this — it already requires elevation for the NSIS installers.
--from-sourceflag — issue #283's power-user path (clone each repo- build from source). Defers until the binary path is in steady state.
- Code signing / notarization for the downloaded
.pkgand.exeinstallers — tracked as issues #280 and #281. Bundling MCP Tools on macOS — blocked on upstreamDone —displayxr-mcpshipping a.pkg.displayxr-mcpshipsDisplayXRMCP-*.pkg;--with mcpinstalls it on macOS.- End-user meta-installer (single download for non-developers) — #284.