
A web and mobile application for ZoneMinder for viewing live camera feeds, reviewing events, and managing multiple profiles. It is a rewrite of the original zmNinja application, built on React, TypeScript, Capacitor, and Electron.
Screenshots
frames courtesy appleframer



I (Pliablepixels) don't plan to support zmNinjaNg with any urgency. Please don't ping me and expect quick answers. ZoneMinder however does plan to offer limited support, just like it did with zmNinja.
zmNinjaNg, esNg and pyzmNg heavily use Agentic UI (Claude) for development. Thanks to these tools, I was able to redo things and get it to a point where the new codebase is better in many ways than the old one. I don't plan to change this anytime soon (and if I did, I won't have time to extend this anymore). In short, in my view, this is the new way of development for me atleast. I've spent a lot of time working with Claude to build this system - just because I used AI doesn't really mean I don't know what is going on. I do and I still spend time reading/understanding the code as changes are made.
I am happy to accept PRs, but I don't want AI slop. Funny I am saying this, given this repo is largely AI agent(s) generated. The difference is I understand the code and know how to prompt it with directions that make the tools generate better quality code. Remember these tools are capable but love to write a lot of code doing custom things when simpler/better means are available. They also make mistakes. So here are the rules:
If you're setting up automated builds via GitHub Actions, you need to enable write permissions:
This allows the workflows to create GitHub releases automatically when you push a tag.
git clone https://github.com/ZoneMinder/zmNinjaNg
cd zmNinjaNg/app
npm install
# Desktop development
npm run electron:dev # Electron shell (Chromium)
Desktop builds use Electron (bundles its own Chromium).
npm run electron:build # -> desktop_release_builds/electron/
Signs with the Developer ID and notarizes when APPLE_ID, APPLE_PASSWORD, and APPLE_TEAM_ID are set in the environment. Append :nosign for an unsigned build:
npm run electron:build:nosign
The target folder is wiped at the start of each build.
npm run build # Output: app/dist/
npm run preview # Preview the production build
Deploy the web build (app/dist/) to Netlify, Vercel, GitHub Pages, AWS S3, etc.
The project includes unit tests and cross-platform E2E tests. All commands run from app/.
npm run test:unit # Run all unit tests
npm run test:unit -- --watch # Watch mode
npm run test:coverage # With coverage report
Uses Playwright with Gherkin .feature files against a real ZoneMinder server. Configure credentials in app/.env.
npm run test:e2e # All web E2E tests
npm run test:e2e -- tests/features/dashboard.feature # Single feature
npm run test:e2e -- --headed # See the browser
npm run test:e2e:visual-update # Regenerate visual baselines
npm run test:all # Unit + web E2E
Tests run on real devices: Android emulator and iOS simulator (phone + tablet). Each platform uses shell scripts that handle building, booting, and running tests.
bash scripts/test-android.sh # Android emulator (Playwright via CDP)
bash scripts/test-ios.sh phone # iPhone simulator (WebDriverIO + Appium)
bash scripts/test-ios.sh tablet # iPad simulator (WebDriverIO + Appium)
bash scripts/test-all-platforms.sh # All platforms sequentially
Device tests require one-time setup (Xcode, Android Studio, Appium, etc.). Run npm run test:platform:setup to verify your machine is ready. See app/tests/README.md for setup instructions and docs/developer-guide/06-testing-strategy.rst for the full testing guide.
pip install -r docs/requirements.txt sphinx-autobuild && cd docs && make clean && make html && sphinx-autobuild . _build/html
scripts/make_release.sh here. This automatically tags the current state and triggers release buildsapp/package.json is the source of truth for the version numbernpm run notice <version> to draft a short "what's new" notice from the closed issues since the last release (Claude writes it, you approve it). It only writes docs/notices.json for you to test; nothing is committed. To discard a test draft, run git checkout -- docs/notices.json. On minor/major releases make_release.sh offers to generate one for you. Details in the developer guide.$ claude mcp add zmNinjaNg \
-- python -m otcore.mcp_server <graph>