Skip to content

Installation

Prerequisites

  • Node.js 20+ (node --version should show v20 or later)
  • Python 3.11 (3.12 also works locally; CI uses 3.11)
  • Xcode Command Line Tools on macOS (xcode-select --install). Verify the C++ toolchain actually works with npm run check:toolchain — a macOS update can leave xcode-select pointing at a broken Xcode, which reports as a missing compiler even though several are installed (see Troubleshooting).
  • For signed macOS releases (CI): an Apple Developer ID Application certificate

First-time setup

Four things to create: the PyHelios submodule + compiled native library, the Python venv, Node modules, and the bundled PyInstaller sidecar that the Electron app spawns (on a port chosen at runtime) in packaged builds and E2E.

PyHelios is vendored as a git submodule (built from source — there is no pip wheel), so clone recursively and compile its native libhelios. This needs cmake and a C++ compiler (Xcode Command Line Tools on macOS, MSVC on Windows). The compile covers the plantarchitecture and lidar plugins (--nogpu skips only the radiation/OptiX plugin; the lidar CUDA ray-tracing path still compiles if a CUDA toolkit is present — see the GPU note below). The lidar plugin transitively builds the visualizer (OpenGL) plugin — fine on macOS and Windows with no extra packages; on Linux you'd also need libgl1-mesa-dev, xorg-dev, and — both for PotreeConverter — libtbb-dev and patchelf: sudo apt-get install -y libgl1-mesa-dev xorg-dev libtbb-dev patchelf.

GPU acceleration is decided at build time

The lidar/collisiondetection plugin compiles a CUDA ray-tracing path whenever a CUDA toolkit is found on the build machine (CMake's find_package(CUDAToolkit) → HELIOS_CUDA_AVAILABLE); otherwise the build is CPU/OpenMP-only. --nogpu doesn't change this — it only drops the separate radiation/OptiX plugin. The release workflow installs the CUDA toolkit on the Windows + Linux runners, so the shipped installers for those platforms are GPU-capable; macOS is always CPU-only (no CUDA on Apple hardware). cudart is linked statically, so GPU-enabled builds still run on machines with no CUDA/driver and fall back to CPU automatically. A local dev build is GPU-enabled only if you have a CUDA toolkit installed.

# 1. Clone the repo (recursively, to pull the PyHelios + helios-core submodules)
git clone --recursive https://github.com/PlantSimulationLab/Phytograph.git
cd Phytograph
# (already cloned non-recursively? run: git submodule update --init --recursive)

# 2. Python backend — create venv and install deps
cd backend-api
python3 -m venv venv
source venv/bin/activate              # Windows: venv\Scripts\activate
pip install --upgrade pip
pip install -r requirements.txt pyinstaller   # pyinstaller needed for step 5
deactivate
cd ..

# 3. Compile PyHelios from source (libhelios + editable install). A few
#    minutes the first time. build-backend.mjs / dev.mjs also auto-run this
#    if the native lib is missing, but doing it explicitly surfaces errors.
node scripts/build-pyhelios.mjs

# 4. Node deps
npm install

# 5. Build the Python sidecar into resources/phytograph_backend/.
npm run build:backend

Don't rely on a system-wide pyinstaller

On a dev machine with anaconda installed, a bare pyinstaller from PATH picks up anaconda's Python — which lacks the project's deps — and produces a broken bundle that crashes on launch. npm run build:backend auto-discovers backend-api/venv/bin/python; override with PYTHON=/path/to/python if needed. See the header comment of scripts/build-backend.mjs for the full resolution logic.

Step 5 is not needed for npm run dev: with backend-api/venv present, scripts/dev.mjs runs uvicorn directly and the Electron supervisor stands down. Build the sidecar when you want to run the E2E suite or package an installer. It takes a few minutes the first time; re-run only when backend code changes. (Step 3 is the PyHelios native compile; it's a prerequisite of step 5, which bundles libhelios into the sidecar.)

Verifying the install

npm run typecheck         # tsc --noEmit, should succeed silently
npm run test:backend      # pytest in backend-api/ (uses ./venv/bin/pytest)
npm run test:unit         # vitest

If all three pass, you're ready to launch the app — see First Run.