Skip to content
quest'n'click

CreateHow-toFor authorsApplies from 4.1.2

Testing on a phone over the LAN

Cette page en françaisThis page on the GitHub wiki

A game is made for a phone held in landscape. This page starts the development server so that a phone on the same Wi-Fi opens the game you are writing, with the reloads as you edit, and says what stays protected while it does.

What you get

The game you are editing, open on your phone at http://<your machine's address>:5173/, reloading each time you save a file. The Studio and the placement editor stay reachable from the phone too, but only with a one-session token the command prints.

Context and versions

  • Engine repository: npm run dev:lan (and npm run studio:lan for the Studio). It exists since 3.0.0; since 4.1.2 the Studio's write routes also check the Host the browser sends (below).
  • Created project (made by npx create-quest-n-click <folder> or quest-n-click create <folder>): there is no dev:lan script. Its dev passes extra options to Vite, so npm run dev -- --host serves the game on the network. That mode gives no token: the phone plays, but the Studio and the placement editor refuse every write that does not come from this machine (see Limits).

Prerequisites

  • The game runs on your machine: npm run dev opens it at http://localhost:5173/ (The working loop).
  • The phone and the machine are on the same network, and the network lets two devices talk to each other (a guest Wi-Fi or a public hotspot often does not).
  • Your machine's firewall lets incoming connections reach Node on port 5173.

Where to run the commands

On your machine, in a terminal open in the engine repository (or in the created project, for its own command). Nothing runs on the phone: it only opens a URL.

Steps

  1. Start the development server on the network.

    # in the engine repository, on your machine
    npm run dev:lan
    # in a created project, on your machine
    npm run dev -- --host

    dev:lan first points @game at the current game (GAME=<id>, else the game last selected, else package.json → config.game), then starts Vite listening on every interface (--host 0.0.0.0). Before Vite's own lines it prints a banner:

    LAN write access is protected by this one-session token:
      <token>
    Studio: http://192.168.1.20:5173/__studio/?token=<token>
    Layout editor: http://192.168.1.20:5173/?edit=<room>&token=<token>

    The address is your machine's first IPv4 address on the network. Vite then lists its own Network: URLs.

  1. On the phone, open http://<that address>:5173/ and turn the phone to landscape.
  1. Play what you just wrote. In the lamp of Your first game, tap the lamp with Use: the line shows, the prop changes, and the save remembers it when you reload. That is the loop: write a rule, place it, check, play.
  1. Optional: to edit from another device, open the Studio or Layout editor URL of the banner, with its ?token=. The first request with the token sets an HttpOnly, SameSite=Strict cookie, so the next pages need no token in the URL. To start the Studio itself on the network, run npm run studio:lan instead of step 1 (engine repository): it opens the Studio's URL with the token.

What stays protected

  • Without dev:lan/studio:lan, Vite listens on 127.0.0.1 only (vite.config.ts): no other device reaches it.
  • In LAN mode, every file-writing route of the Studio (the Studio's API, the placement editor's save) asks for the token: in the x-web-scumm-token header, in ?token=, or in the cookie. Without it: 401 Studio token required. The token is new at each start, unless WEB_SCUMM_STUDIO_TOKEN is set (environment variables).
  • In every mode, those routes answer only to this machine's names (localhost, 127.0.0.1, [::1]) and, in LAN mode, to the addresses dev:lan printed. Any other Host gets 403 the Studio answers its own names only, so a page that rebinds a name to your port cannot write. A write whose Origin is another site gets 403 cross-origin Studio request refused.
  • In a created project with npm run dev -- --host, no LAN address is on that list and no token exists: the phone plays the game, and any write through the Studio or the placement editor from the phone is refused with a 403. Edit on the machine itself.

Expected result, and how to check it

The phone shows the title screen, then the game in landscape. Save a room file on the machine: the phone reloads with the change. In the Studio opened from the banner's URL, a save goes through (no 401).

Common errors

SymptomCauseFix
The phone's browser waits, then says the site cannot be reachedThe phone is on another network, the Wi-Fi isolates its clients, or the firewall blocks port 5173Put both on the same Wi-Fi, allow Node through the firewall (macOS asks at the first start), or try another network
It works on the machine (localhost) but not on the phonenpm run dev was started, not npm run dev:lan: Vite listens on 127.0.0.1 onlyStop it and start npm run dev:lan (created project: npm run dev -- --host)
401 Studio token required when saving from the phoneThe Studio or editor page was opened without the banner's ?token=Open the banner's URL; the token changes at each start of the server
403 the Studio answers its own names only …The page was opened under a name that is not this machine's or the printed address (a .local name, another interface's address), or in a created project with --hostOpen the exact address of the banner; in a created project, edit on the machine
✖ games/<id>/index.ts not found (GAME=<id>)GAME names a game that does not existCheck ls games, or unset GAME
Port 5173 in use, Vite picks another portAnother dev server runsStop it, or open the port Vite prints; the banner's URLs say 5173 whatever Vite chose

Files or data changed

dev:lan itself writes nothing but the .cache/game link to the current game. What the phone saves (the game's progress) stays in the phone's browser storage. A write made through the Studio or the editor changes the game's files on the machine, as on localhost.

Recovery or going back

Stop the server with Ctrl+C: the token dies with it, and npm run dev goes back to listening on 127.0.0.1 only.

References