Publish to the web
Ship static sites and games from Trellis Cloud at yourname.studio.trellis.computer without tying uptime to the sandbox VM.
Publish to the web
On studio.trellis.computer, you can publish a static snapshot of your project to a durable public URL:
https://<slug>.studio.trellis.computer
Examples: fractions-game.studio.trellis.computer, mrs-smith-class.studio.trellis.computer.
Publishing is separate from Share session (the transcript link in the session header menu). Share session copies a conversation URL. Publish uploads your built site to object storage and serves it from a wildcard edge router, so the link stays up when your sandbox sleeps.
How it works
Preview panel → Studio backend (in sandbox) → Trellis Cloud broker → R2 + edge router
- Build (when needed) — Studio detects
npm run buildand common frameworks (Vite, Next static export, plain HTML). Pure static projects skip the build step. - Upload — The sandbox uploads files directly to Cloudflare R2 using short-lived credentials from the broker (the sandbox never holds storage admin keys).
- Go live — The broker flips a slug → version pointer. The publish router at
*.studio.trellis.computerserves the current version.
Preview URLs (https://{port}-{sandboxId}.e2b.dev) are for development only. They stop when the sandbox pauses. Published URLs do not.
Slugs and visibility
- Slug format: lowercase letters, digits, and hyphens; 3–63 characters; must include at least one letter; cannot start or end with a hyphen. The broker enforces the full v1 regex (
slug-policy.mdin the Studio repo). Reserved names (for exampleapi,admin,login) are blocked at commit time. - First publish: pick a slug once per project. Republish reuses it and uploads a new content-addressed version.
- Visibility:
public(default) orunlisted. Unlisted sites are still reachable by URL but are not promoted in product surfaces.
Failed republishes do not take down the last successful version.
Preview and browser panels (cloud workspaces)
When you run a cloud workspace on studio.trellis.computer, a Publish control appears in the preview panel header (next to refresh and open-in-browser) while a web preview service is running. The same control appears in the browser panel toolbar when a page is loaded in the embedded browser view.
| State | What you see |
|---|---|
| Never published | Publish opens a first-publish popover |
| Publishing | Spinner while build → upload → commit runs |
| Live | Live opens the public site; the chevron menu adds View, Copy URL, Republish, and Versions (placeholder) |
First publish
The first-publish flow lives in publish-first-popover.tsx (opened from preview-publish-control.tsx).
- Studio suggests a slug from the open workspace folder name (
slugifyPublishNameinstudio/packages/app/src/lib/publish-slug.ts). - The slug field validates locally before any network call: length (3–63), charset, hyphen boundaries, and at least one letter.
- After local validation, Studio debounces
GET /publish/check(~400ms) for availability, reserved names, and broker-side policy. If the slug is taken, Studio suggests the next name (for examplemy-game-2) with a Use … action (suggestNextSlug). - On open, Studio loads Build settings from
GET /publish/plan: inferred build command (or “static site — no build step”), output folder, and SPA fallback. You can override these before publishing. - Choose Visibility: Public (default) or Unlisted (reachable by URL, not promoted in product surfaces).
- Publish now runs
POST /publishwith your slug, visibility, and build overrides.
Inline hints follow the slug policy table (for example “between 3 and 63 characters”, “must include at least one letter”, “taken — try another”). The broker response on commit is authoritative; the UI is optimistic feedback only.
Republish
After a successful publish, choose Republish from the chevron menu. Studio re-runs the full publish pipeline under the same slug (no second popover). The last live version stays up if a republish fails. Versions in the menu is reserved for rollback/history (planned v1.5).
Publish state for the current cloud project is remembered in the browser (project-publish.v1 persisted store) so Live survives refreshes until you clear site data.
Studio API (cloud workspaces)
The OpenCode server in your cloud workspace exposes publish routes. The cloud dashboard passes your InstantDB token; Studio forwards it as Authorization: Bearer ….
| Method | Path | Purpose |
|---|---|---|
GET | /publish/plan | Infer build command, output directory, SPA fallback |
GET | /publish/check | Slug availability (slug, projectId, brokerUrl query params) |
POST | /publish | Run full publish (build → upload → commit) |
POST /publish body:
{
"projectId": "<cloud-project-id>",
"brokerUrl": "https://api.studio.trellis.computer",
"slug": "fractions-game",
"visibility": "public",
"buildCommand": "npm run build",
"outputDir": "dist",
"spaFallback": true
}
buildCommand, outputDir, and spaFallback are optional overrides. Omit them to use inferred defaults.
Build logs stream to the preview console under the publish channel while a publish runs.
Broker API (control plane)
The Trellis Cloud broker (cloud/, deployed at api.studio.trellis.computer) owns slug registry and credentials:
| Method | Path | Purpose |
|---|---|---|
POST | /project/:id/publish/begin | Validate slug + manifest; return presigned R2 upload URLs |
POST | /project/:id/publish/commit | Verify uploads; flip live pointer; return public URL |
GET | /publish/check | Debounced slug availability for the first-publish UI |
Artifact paths in storage follow:
publish/{workspaceId}/{slug}/{version}/{path}
Versions are content-addressed (sha256-…) so identical builds can no-op at the broker.
Infrastructure (operators)
Product code for v1 lives in:
studio/packages/opencode/src/publish/— manifest, upload, orchestrationcloud/src/publish/— broker begin/commit, slug policy, R2 presigningcloud/publish-router/— Cloudflare Worker for*.studio.trellis.computer
Deploying the router requires Cloudflare DNS, an R2 bucket (studio-publish), a KV namespace, and broker env vars (R2_*, CF_*). See cloud/publish-router/README.md in the trellis-cloud repo.
Internal design notes: publishing architecture in the Studio repo under packages/docs/plans/publishing.md, slug rules in slug-policy.md, upload contract in storage-contract.md.
Roadmap
| Item | Status |
|---|---|
| Backend publish pipeline (build, upload, broker) | Shipped |
| Preview-panel publish control + first-publish popover | Shipped |
| Publish progress UI in preview console | Planned |
| Version history flyout + rollback | Planned (v1.5) |
| Report link on public pages + teacher moderation | Planned (v1.5) |
| Custom domains | Planned (v2) |
| Full Node/Bun runtime hosts (Sprite/Railway) | Planned (v2) |