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
  1. Build (when needed) — Studio detects npm run build and common frameworks (Vite, Next static export, plain HTML). Pure static projects skip the build step.
  2. Upload — The sandbox uploads files directly to Cloudflare R2 using short-lived credentials from the broker (the sandbox never holds storage admin keys).
  3. Go live — The broker flips a slug → version pointer. The publish router at *.studio.trellis.computer serves 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.md in the Studio repo). Reserved names (for example api, 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) or unlisted. 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.

StateWhat you see
Never publishedPublish opens a first-publish popover
PublishingSpinner while build → upload → commit runs
LiveLive 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).

  1. Studio suggests a slug from the open workspace folder name (slugifyPublishName in studio/packages/app/src/lib/publish-slug.ts).
  2. The slug field validates locally before any network call: length (3–63), charset, hyphen boundaries, and at least one letter.
  3. 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 example my-game-2) with a Use … action (suggestNextSlug).
  4. 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.
  5. Choose Visibility: Public (default) or Unlisted (reachable by URL, not promoted in product surfaces).
  6. Publish now runs POST /publish with 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 ….

MethodPathPurpose
GET/publish/planInfer build command, output directory, SPA fallback
GET/publish/checkSlug availability (slug, projectId, brokerUrl query params)
POST/publishRun 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:

MethodPathPurpose
POST/project/:id/publish/beginValidate slug + manifest; return presigned R2 upload URLs
POST/project/:id/publish/commitVerify uploads; flip live pointer; return public URL
GET/publish/checkDebounced 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, orchestration
  • cloud/src/publish/ — broker begin/commit, slug policy, R2 presigning
  • cloud/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

ItemStatus
Backend publish pipeline (build, upload, broker)Shipped
Preview-panel publish control + first-publish popoverShipped
Publish progress UI in preview consolePlanned
Version history flyout + rollbackPlanned (v1.5)
Report link on public pages + teacher moderationPlanned (v1.5)
Custom domainsPlanned (v2)
Full Node/Bun runtime hosts (Sprite/Railway)Planned (v2)