Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ading2210/sandstone/llms.txt

Use this file to discover all available pages before exploring further.

Sandstone supports two distinct deployment models. You can host it on a server like any standard Node.js web app, or you can bundle everything into a single self-contained HTML file that runs from a local file path or a data: URL — no server, no domain, and no service worker required. The right choice depends on your environment and how much infrastructure you want to maintain.
Sandstone is licensed under AGPL-3.0-only. If you distribute a modified version — including deploying a modified build to a public server — you must make the corresponding source code available to your users under the same license. See the full license text for details.
The official public deployment at https://sandstone.pages.dev/ is hosted on Cloudflare Pages and is a useful reference for how Sandstone behaves in production. You can inspect its network requests and behavior before setting up your own deployment.

Deployment models

This model deploys the example Express server to a host of your choice. The server serves the compiled static files and provides a local Wisp WebSocket endpoint at the same origin.

Build for production

From the repository root, build the main library first, then build the example:
npm run build:prod
cd example
npm install
npm run build:prod

Start the server

npm run start
The server reads PORT and HOST from the environment. To bind to a specific port:
PORT=8080 npm run start

Wisp endpoint

The Express server in example/server.mjs automatically handles WebSocket upgrades and routes them to the bundled Wisp server:
server.on("upgrade", (request, socket, head) => {
  wisp.routeRequest(request, socket, head);
});
This gives you a Wisp endpoint at ws://yourserver/ (or wss://yourserver/ behind TLS) without running a separate service. When the example app detects it is being served over http: or https:, it automatically connects to the local origin as the Wisp server:
wisp_url = location.origin.replace("http", "ws");
sandstone.libcurl.set_websocket(wisp_url);

Reverse proxy

When you put the Express server behind a reverse proxy such as nginx or Caddy, make sure your proxy forwards WebSocket upgrade requests. Wisp relies on the HTTP upgrade mechanism and will not work through a proxy that strips those headers.

Wisp URL configuration

Both deployment models expose a Wisp URL input in the options panel. Users can change the Wisp endpoint at runtime without reloading the page. The new URL takes effect when the options panel is closed:
function toggle_options() {
  options_div.style.display = options_div.style.display === "none" ? "flex" : "none";
  frame_container.style.filter = frame_container.style.filter ? "" : "brightness(50%)";

  // apply options
  sandstone.libcurl.set_websocket(wisp_url_input.value);
}
If you operate a private Wisp server, you can pre-populate the wisp_url_input field with your server’s address so users connect to it by default.

Build docs developers (and LLMs) love