Deploying
Ship a Voxolith game - HTTPS for WebGPU, the Vite settings the renderer needs, base paths with import.meta.env.BASE_URL, and a GitHub Pages workflow.
A Voxolith game is a static site: HTML, JavaScript and any models you fetch. It can be hosted anywhere that serves files over HTTPS. This page covers what the build needs, how to keep URLs working under a sub-path, and the GitHub Pages workflow the Voxolith apps use.
HTTPS
WebGPU only exists in a secure context: HTTPS, or localhost. Any real host must serve HTTPS
(GitHub Pages does), and a dev server you open from another device must too. The Voxolith apps use
@vitejs/plugin-basic-ssl, which serves a self-signed certificate on localhost and the LAN. Without
WebGPU, initGpu throws WebGPUUnsupportedError; catch it and call showUnsupportedScreen rather
than leave a blank page.
Build settings
@voxolith/renderer ships raw TypeScript and imports its shaders with Vite's ?raw, so it is
compiled with your app:
// vite.config.ts
import { defineConfig } from "vite";
import basicSsl from "@vitejs/plugin-basic-ssl";
export default defineConfig({
// GitHub Pages serves project sites under /<repo>/; the deploy workflow sets BASE_PATH.
base: process.env.BASE_PATH ?? "/",
plugins: [basicSsl()],
// The renderer must be compiled with the app, not pre-bundled.
optimizeDeps: { exclude: ["@voxolith/renderer"] },
server: { host: true },
});In tsconfig.json, include "types": ["@webgpu/types", "vite/client"]. A multi-page app lists its
pages in build.rollupOptions.input, as the examples do.
Base paths
A project site on GitHub Pages lives under /<repo>/, not at the root, so never hard-code absolute
URLs. Fetch assets through import.meta.env.BASE_URL, which Vite sets from base, and link
between your own pages relatively:
const buf = await (await fetch(`${import.meta.env.BASE_URL}models/cat-sit.vox`)).arrayBuffer();<a href="../world/">World</a>Files in public/ are copied as they are. Service workers and web manifests need the same care:
register the worker under import.meta.env.BASE_URL with that scope, and write the manifest's
start_url and scope as "." (see Mobile and PWA).
GitHub Pages
The Voxolith apps (viewer, editor, examples, demolition-shot) deploy on every push to main with a
.github/workflows/pages.yml that builds with BASE_PATH=/<repo>/ and publishes dist/. The core of
it, for an app that installs its Voxolith dependencies from npm:
name: Deploy to GitHub Pages
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bun run build
env:
BASE_PATH: /${{ github.event.repository.name }}/
- uses: actions/upload-pages-artifact@v3
with:
path: dist
deploy:
needs: build
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@v4Enable Pages for the repository with "GitHub Actions" as the source. Until the packages are on npm,
the Voxolith apps' workflow also checks out voxolith/renderer, voxolith/engine and
voxolith/generators next to the app and installs them from a temporary bun workspace root, so
their workspace:* dependencies resolve; copy it from any of the app repositories.
Caches after a deploy
- Vite hashes asset file names, so browsers pick up new code on the next load.
- A generator worker's IndexedDB cache is salted with the worker's hashed URL, so a new build never reads a model the old one generated.
- The engine's service worker (
serviceWorker()from@voxolith/engine/vite) names its cache after a hash of the build, so a deploy installs a new worker that takes over and deletes the old cache; see Offline and installing.
Pitfalls
- A page that works on
localhostand is blank on Pages almost always fetched/models/...from the domain root. Useimport.meta.env.BASE_URL. - Opening the built
dist/index.htmlfrom disk does not work: module scripts and workers do not load fromfile://, and the base path would be wrong anyway. Serve it (vite preview). - Check
navigator.gpusupport on your players' browsers; there is no WebGL fallback.
See also
Offline and installing
Make a Voxolith app load offline after one visit with the engine's service worker plugin, cache fetched data at run time, handle deploys, and make the app installable.
Examples
The live Voxolith example pages and apps, from one .vox model to a streamed valley in 2 cm voxels, with source and what each shows.