Skip to content

Simulator

Note: The simulator supports both Node and Python edge apps, as well as Node-based screen apps. Any project scaffolded with phy app create is ready to run against the simulator out of the box.

The PhyStack CLI includes a local device simulator that simulates the on-device environment and runtime locally, letting you test application logic, settings behavior, and more. You can also test messaging between multiple apps running on your computer and connected to the same simulator instance. The simulator runs in offline mode and does not fully replicate the real device environment, so always verify your app on a real device before publishing.

Screen and edge boilerplate templates already integrate with the simulator out of the box.

Project Structure Requirements

The simulator expects your project to follow a specific structure. Projects scaffolded with phy app create meet these requirements automatically.

Required for all apps

  • package.json at the project root with:
    • "application-type": must be "screen" or "edge" (used for auto-detection). You can also pass --type to override this.
    • "name": used to identify the app in the simulator

Screen apps

  • A "start" script in package.json (e.g., "start": "vite"), this is used as the launch command
  • Settings in src/settings/index.json (optional, defaults are generated from schema.ts if the file doesn’t exist)

Edge apps

  • With Dockerfile (recommended): a Dockerfile at the project root. The simulator builds the image and runs the container with environment variables injected. Container configuration is read from settings.json at the project root.
  • Without Dockerfile: falls back to the "start" script in package.json, similar to screen apps
  • Settings in src/settings/index.json (optional, same behavior as screen apps)

If package.json is missing, the simulator exits with an error. If application-type is missing and --type is not passed, it will fail with “Cannot detect app type.”

Starting the Simulator

The simulator is a standalone server that runs in the background. Start it in a separate terminal before running any apps:

phy simulator start

This can be run from any directory, the simulator listens on port 55000 and serves all apps launched against it.

OptionDescriptionDefault
-p, --port <port>Port to listen on55000

Running Apps

Once the simulator is running, launch an app against it:

phy simulator run <path>

To run the app in the current directory:

phy simulator run .
OptionDescriptionDefault
--type <type>Override app type (screen or edge)Auto-detected from application-type in package.json
--dev-command <command>Override launch commandnpm start
--settings-dir <path>Path to the directory containing index.json with local settingssrc/settings

How It Works

The simulator injects the PHYSTACK_SIMULATOR_URL environment variable, which instructs the PhyStack SDK in your app to connect to the local simulator instance instead of the edge runtime on the device. It also creates a local simulated twin and provides the mandatory TWIN_ID environment variable so your app can connect when running locally.

For screen apps, the TWIN_ID must be passed to the browser as a URL hash parameter (/#instanceId=<twin-id>). This mirrors how the production screen bootloader delivers the instance ID to screen apps running inside iframes. The Vite config in the screen app boilerplate handles this automatically by opening the browser with the correct hash when the simulator is active.

For this reason, your launch script should ensure these environment variables are propagated to your app on start. Screen and edge app boilerplate created using the CLI configures this for you out of the box.

When you run phy simulator run, the CLI performs the following steps:

  1. App type detection, reads application-type from package.json, or uses the --type flag if provided
  2. Twin and settings setup, creates a virtual simulated twin identity for the app and uses your local settings from src/settings/index.json (generates defaults from schema.ts if the file doesn’t exist)
  3. Launch:
  • Screen apps runs npm start (or your custom --dev-command)
  • Edge apps with Dockerfile builds a Docker image and runs the container with Docker config from settings.json
  • Edge apps without Dockerfile falls back to npm start (or your custom --dev-command)

Troubleshooting

“No package.json found” The simulator requires a package.json at the project root with "application-type": "edge" (or "screen"), this is how it identifies and launches the app, regardless of the runtime inside. Both Node and Python edge templates scaffold this file alongside their Dockerfile. You’ll see this error if you ran phy simulator run from a directory without a package.json or pointed it at the wrong path. Make sure you run it from your project root.

“Cannot detect app type” Your package.json is missing the "application-type" field. Add "application-type": "screen" or "application-type": "edge", or pass --type screen / --type edge.

“Simulator is not running” Start the simulator first with phy simulator start in a separate terminal. The simulator server must be running before you can launch apps against it.

“No Dockerfile or start script found” Your edge app has no Dockerfile at the project root and no "start" script in package.json. Add one or the other. For Docker-based edge apps, the Dockerfile should be at the project root (not in a subdirectory).

Settings not loading The simulator looks for settings in src/settings/index.json by default. If your settings are elsewhere, pass --settings-dir <path>. The JSON file must contain settings nested under app.gridApp.settings.