Preview locally

The real room on your machine, around your running dev server, with pitch dev.

On this page

pitch dev serves the real pitch room on your own machine, around the demo as you build it. It is the page, script and stylesheet the platform serves a viewer, with your own dev server on the stage, so what you see is the room your viewers will get: the tour, each step's page and frame and ring, Read more, the next steps and comment mode. Nothing in it is recorded or sent anywhere, and the room says so.

Start it

Start the demo's own dev server as you always do, then pitch dev in the same folder, in another terminal:

pnpm dev
pitch dev
  ok   pitch dev: no problems

  room   http://columbus.localhost:8300
  demo   your dev server at http://127.0.0.1:3000 (`dev` in package.json runs next dev), framed at http://columbus--demo.localhost:8300
  Local preview: nothing is recorded or sent, and comments stay on this machine.
  pitch.json, its pages and pitch.brand.json are watched; the room redraws when they change.
  Opened it in your browser.
  Ctrl-C stops it.

It opens the room in your browser. --no-open leaves the browser alone, and --port picks another port than 8300. It needs a pitch.json that validates to start; Quickstart and pitch init get you one.

What works

Everything a viewer can do, except what needs the platform:

  • The tour. Each step puts its app on the stage, opens the page its path names, in the frame its device names, and rings its point, through the same script the platform adds to your pages. Back, Next, the outline and Explore freely work as they do in a room.
  • Read more. The files pages lists, rendered as the room renders them: Markdown in the room's typography, HTML as you wrote it, sandboxed.
  • What happens next? Every next step, in the room's own words.
  • Comment mode. Pin a comment or mark an area; the room takes a picture of the screen for it, as it does for a viewer. Comments and their pictures go to pitch dev's panel on the room, and are printed in the terminal.
  • A container build's calls. A step's run, the scenarios and the reset are made on your dev server, as the room makes them on a viewer's copy of the demo. See A container build.
  • Your dev server's hot reload, which shows through the stage as it does in a tab of its own.

What needs the platform is left out: On your phone (a phone cannot reach your machine's own addresses), replies from you, and the room's records.

Local preview, not saved

The room carries a bar that says Local preview — not saved, and it means it. pitch dev never signs in and never talks to the platform. A visit, the tour's progress and every other moment a room records are not sent anywhere. A comment, its picture, a reaction and an answer to What happens next? stay in pitch dev while it runs, shown in its panel and printed in the terminal, and are gone when you stop it. Nothing about them ever reaches the app.

It redraws as you work

pitch dev watches pitch.json, the files its pages lists and pitch.brand.json. When one changes, the room redraws itself. Add a step to the story, save, and it is in the tour; rename a page, save, and Read more says so.

When you save a pitch.json that does not validate, the room keeps the last one that did, and says what is wrong.

What is wrong, as you go

The bar on the room counts the problems (pitch dev · 1 problem); click it for the list, each with the docs page that explains it. They are also printed in the terminal, and they are the same checks, in the same words, as the other commands:

  • everything pitch validate checks: pitch.json against the schema, fields pitch does not know, the story, a page file that is not there;
  • each app's page and each step's page, asked of your dev server as the rehearsal asks for it: step "deal": its page, GET /deals/nosuch/, answered 404;
  • a call the demo refused when the room made it, as the rehearsal says it: step "flag": POST /api/demo/flag answered 409: Kestrel is already closed. It stays on the list until the same call works, or pitch.json changes;
  • your dev server not answering at all.
  FAIL story[1].path: step "deal": its page, GET /deals/nosuch/, answered 404
         https://getroomi.com/docs/pitch-json#field-story-path

Finding your dev server

Without --target, pitch dev reads package.json's dev, start, serve and preview scripts, in that order: the port a script names (next dev -p 4000, vite --port 5174, PORT=4000), or else its tool's own default (3000 for next dev, 5173 for Vite, 4321 for Astro). It then tries the common dev ports, and uses the first that answers. When none answers yet, it waits for the most likely one, and the room says it is not answering until it does.

Name it yourself with --target:

pitch dev --target http://127.0.0.1:5174

Only an address on this machine is accepted: 127.0.0.1, localhost or [::1], over http.

pitch dev reaches your dev server addressed by its own name, so a dev server that checks who is asking (Next's dev origins, Vite's allowed hosts) sees nothing unusual.

A static build without a dev server

--static serves the build's output folder, the output in pitch.json, as the platform serves a static build: each path is the file itself or the index.html inside it, a single-page app answers its own deep links, and dotfiles are never served, because a deploy never uploads them. Build first; the story's pages are then checked against what is in the folder, as pitch validate checks them.

pnpm build
pitch dev --static

A container build

Run the demo's server as you do while developing, and point pitch dev at it. The room's calls, a step's run, the scenarios and the reset, go to that server, one after another, and the room says what the demo said back, as it will for a viewer. They change your running demo's state, as they change a viewer's copy.

The room shows the demo as running while your server answers, and as not running on this machine while it does not. --static is refused on a container build: there is no output folder to serve.

Brand

Without anything else, the local room wears Roomi's own look and the Made with Roomi mark, with the demo's name as whose room it is. To see it in your brand, put a pitch.brand.json beside pitch.json:

{
  "name": "Arundel Labs",
  "accent": "#1f6f5c",
  "logo": "brand/logo.png"
}

name is the name the room shows, accent a colour as #rrggbb, and logo a PNG, JPEG or WebP file, relative to the brand file. Each is optional. It dresses the local preview only: the platform never reads it, and a room on the platform wears the brand you set in the app (Brand and next steps).

Addresses

The room is at http://<slug>.localhost:8300 and the demo inside it at http://<slug>--demo.localhost:8300, where the slug is made from name as pitch deploy makes it. They are two origins, as a room and its demo are on the platform, so the demo's scripts cannot reach into the room here either.

Chrome, Edge and Firefox send every *.localhost name to your own machine. If your browser does not, open the room in one that does.

pitch dev listens on 127.0.0.1 only: nothing else on your network can reach it. It answers only its own two addresses, and takes a comment or a call only from its own room page.