Desktop and Mobile

The package is plain TypeScript with no DOM assumptions, so it runs unchanged in an Electron renderer, an Electron main process, and a Capacitor WebView. Nothing here is web-only.

The One Boundary

thetowersdk/node is the only entry point that needs Node, because it is the one that reads files. That is the boundary you want anyway: the decoder belongs on the side that is allowed to touch the filesystem, and everything else — catalogs, formulas, builders, charts, formatting — runs happily in a renderer or a WebView.

// Renderer or WebView: catalogs and formulas, no filesystem.
import { LAB_CATALOG } from 'thetowersdk/data'
import { computeWaveBaseHealth } from 'thetowersdk/mechanics'

// Main process only: this one reads a file.
import { decodePlayerInfoSaveBytes } from 'thetowersdk/node'

Pin The Toolchain

Electron and Capacitor builds are sensitive to the toolchain that produced them, so pin it with the hash corepack verifies against:

{
  "packageManager": "pnpm@10.8.1+sha512.c50088ba…",
  "engines": { "node": ">=22 <23" }
}

Reading A Save On Each Platform

On desktop, the save is a file and thetowersdk/node reads it directly from the main process. On mobile, a connected device can hand it over without the player exporting anything — see Save Files for the whole route, including the bridge.

Further Detail

The main/renderer split, the IPC boundary, running the bridge in-process, and what is available on mobile are covered in docs/DESKTOP_AND_MOBILE.md in the repository.