OpenNOW

Development Guide

Local setup, scripts, native streamer builds, CI, and release packaging

OpenNOW's active desktop client lives in opennow-stable/ in the OpenCloudGaming/OpenNOW repository. This site is the canonical public documentation for that codebase.

Prerequisites

  • Node.js 22
  • npm
  • Git
  • Rust/Cargo when working on the native streamer
  • GStreamer development packages when building the Rust streamer with the gstreamer backend
  • A GeForce NOW account for end-to-end session testing

Install from the Electron workspace:

git clone https://github.com/OpenCloudGaming/OpenNOW.git
cd OpenNOW/opennow-stable
npm install

Scripts

Root scripts proxy into opennow-stable/:

Root commandPurpose
npm run devStart Electron/Vite development mode
npm run buildBuild the renderer and Electron bundles
npm run native:checkRun cargo check for native/opennow-streamer
npm run native:buildBuild the release Rust streamer and copy it into native/opennow-streamer/bin
npm run typecheckRun Node and renderer TypeScript checks
npm run locales:checkValidate renderer translation keys and locale JSON files
npm run crowdin:uploadUpload locales/en.json source strings to Crowdin
npm run crowdin:downloadDownload translated locale JSON files from Crowdin
npm run distBuild app + native streamer, then package unsigned artifacts
npm run dist:signedBuild app + native streamer, then package with signing enabled

Workspace scripts available inside opennow-stable/:

Workspace commandPurpose
npm run devElectron/Vite dev server
npm run previewPreview a production build
npm run lintRun oxlint src
npm testRun the Node test harness
npm run native:checkCargo check the native streamer crate
npm run native:buildRun scripts/build-native-streamer.mjs
npm run typecheckType-check main/preload and renderer projects
npm run locales:checkValidate renderer translation keys and locale JSON files
npm run buildProduction build only
npm run distUnsigned electron-builder packaging
npm run dist:signedSigned electron-builder packaging

Source layout

locales/                         Source and translated renderer locale JSON files

opennow-stable/
├── src/main/                 Electron main process
│   ├── gfn/                  Auth, service URLs, catalog, CloudMatch, NVST transport
│   ├── ipc/                  Account/catalog/cache, session, and media IPC handlers
│   ├── session/              Cloud G-Sync, session conflict, selection/lifecycle helpers
│   ├── signaling/            Signaling IPC coordinator and native-streamer routing
│   ├── media/                Screenshot/recording persistence and thumbnails
│   ├── services/             Cache services, PrintedWaste queue metadata, region ping, timeouts
│   ├── nativeStreamer/       Rust child-process lifecycle plus input/surface helpers
│   ├── discordRpc.ts         Discord Rich Presence integration
│   ├── appBuildInfo.ts       packaged version/build metadata
│   ├── updater.ts            electron-updater integration
│   ├── videoAcceleration.ts  Chromium video acceleration feature/switch selection
│   ├── settings.ts           settings.json defaults and migration
│   └── index.ts              app bootstrap, Chromium/WebRTC flags, windows, protocol/services wiring
├── src/preload/              contextBridge API
├── src/renderer/src/         React UI, stream view, settings, hooks, controller mode
├── src/shared/               Shared IPC, Settings, protocol, and GFN types
├── scripts/build-native-streamer.mjs
├── scripts/check-translations.mjs
└── package.json

native/opennow-streamer/       Rust native streamer process with modular GStreamer backend

Localization

Renderer UI strings live in locales/en.json as the English source file. Crowdin maps that file to locales/%two_letters_code%.json for translated locale files; current locale codes are de, en, es, fr, ja, ko, nl, pl, ro, ru, tr, and zh. The Settings UI defines friendly language names for every current locale code and falls back to uppercase codes for any newly loaded locale without a label. Run npm run locales:check before merging localization changes to verify renderer t("...") keys exist in English and that non-English locale JSON files parse cleanly.

At runtime the renderer loads locales/*.json, normalizes locale codes such as en-US or en_US to en, stores the selected app language in browser localStorage as opennow.locale, and falls back to English for missing files or keys.

Native streamer builds

npm run native:build runs Cargo in release mode through opennow-stable/scripts/build-native-streamer.mjs. By default it builds with the gstreamer feature. Set OPENNOW_NATIVE_STREAMER_FEATURES=none to build without optional media support, or set a comma-separated feature list to override. The script also supports OPENNOW_NATIVE_STREAMER_TARGET, OPENNOW_NATIVE_STREAMER_PLATFORM_KEY, and OPENNOW_BUNDLE_GSTREAMER_RUNTIME.

When the gstreamer feature is enabled, the build environment must provide GStreamer development files and plugins needed by webrtcbin. Release builders bundle a private GStreamer runtime on Windows x64 and macOS. Linux packages use distro GStreamer dependencies instead.

See Native Streamer for runtime behavior, environment variables, protocol, and platform decoder paths.

CI and releases

PRs and pushes run the auto-build.yml CI workflow. The select-builds job builds a platform matrix on sponsored Blacksmith runners (blacksmith-2vcpu-windows-2025, blacksmith-6vcpu-macos-15, blacksmith-2vcpu-ubuntu-2404, and blacksmith-2vcpu-ubuntu-2404-arm). Pull requests that target dev validate the reduced Windows x64 and Linux x64 matrix; other events use the full Windows x64/ARM64, macOS x64/arm64, and Linux x64/arm64 matrix.

Each matrix job installs the Electron workspace dependencies with Node.js 22, then runs lint, typecheck, and tests. The Node test harness discovers src/**/*.test.ts, runs them through tsx --test, and appends a GitHub step summary with discovered files, pass/fail counts, skipped/todo/cancelled counts, and runner startup errors when present. The CI workflow also writes a compact lint/typecheck/test summary to the job summary.

The release workflow packages this matrix:

TargetNative/GStreamer behaviorArtifacts
Windows x64Builds native streamer and bundles private GStreamer runtimeNSIS setup, portable exe, updater metadata
Windows ARM64Packages app without native streamer buildNSIS setup, portable exe
macOS x64 / arm64Builds native streamer and bundles private GStreamer runtimedmg, zip
Linux x64 / arm64Builds native streamer against host distro GStreamer packagesAppImage, deb

Windows ARM64 artifacts are release downloads only; the Windows updater feed remains the x64 latest.yml channel. Manual releases can update opennow-stable/package.json and lockfile to the requested version before tagging so source archives match the app version.

On this page

On this page