{"id":20730656,"url":"https://github.com/gbmhunter/ninjaterm","last_synced_at":"2026-04-26T04:02:52.737Z","repository":{"id":35023486,"uuid":"39129282","full_name":"gbmhunter/NinjaTerm","owner":"gbmhunter","description":"A serial port terminal that's got your back.","archived":false,"fork":false,"pushed_at":"2026-04-24T01:14:38.000Z","size":57043,"stargazers_count":110,"open_issues_count":23,"forks_count":8,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-04-24T02:26:16.351Z","etag":null,"topics":["arduino","embedded","mbedded","ninja","ninjaterm","pwa","rs-232","serial","serial-ports","serialport","terminal","uart","vite","web"],"latest_commit_sha":null,"homepage":"https://ninjaterm.mbedded.ninja/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"Shashank02051997/FancyWalkthrough-Android","license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gbmhunter.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"ko_fi":"gbmhunter"}},"created_at":"2015-07-15T09:52:44.000Z","updated_at":"2026-04-12T09:34:06.000Z","dependencies_parsed_at":"2023-09-22T11:49:49.275Z","dependency_job_id":"4f75ec7c-a75c-494d-8b25-370bf103ded0","html_url":"https://github.com/gbmhunter/NinjaTerm","commit_stats":null,"previous_names":[],"tags_count":101,"template":false,"template_full_name":null,"purl":"pkg:github/gbmhunter/NinjaTerm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gbmhunter%2FNinjaTerm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gbmhunter%2FNinjaTerm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gbmhunter%2FNinjaTerm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gbmhunter%2FNinjaTerm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gbmhunter","download_url":"https://codeload.github.com/gbmhunter/NinjaTerm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gbmhunter%2FNinjaTerm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32285283,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-25T18:29:39.964Z","status":"online","status_checked_at":"2026-04-26T02:00:05.962Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","embedded","mbedded","ninja","ninjaterm","pwa","rs-232","serial","serial-ports","serialport","terminal","uart","vite","web"],"created_at":"2024-11-17T05:12:20.390Z","updated_at":"2026-04-26T04:02:52.731Z","avatar_url":"https://github.com/gbmhunter.png","language":"TypeScript","funding_links":["https://ko-fi.com/gbmhunter"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\u003cimg src=\"img/logo/v3/github-readme-logo.png\" alt=\"The NinjaTerm logo.\" height=\"200px\"\u003e\u003c/p\u003e\n\n#### A serial port terminal that's got your back.\n\n\u003cbr\u003e\n\n\u003cbr\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n[![Build Status][github-actions-status]][github-actions-url]\n[![Github Tag][github-tag-image]][github-tag-url]\n\n\u003c/div\u003e\n\n## Install\n\nIf you want to use NinjaTerm, visit the [NinjaTerm homepage](https://ninjaterm.mbedded.ninja) to download the desktop application or use the older web-based version (the web-based version is no longer being updated).\n\nFrom the homepage there are also links to the [NinjaTerm manual](https://ninjaterm.mbedded.ninja/docs/manual/).\n\nYou can also access older versions of NinjaTerm at [GitHub Releases](https://github.com/gbmhunter/NinjaTerm/releases).\n\nThe rest of this README is for developers who want to contribute to NinjaTerm.\n\n## Directory Structure\n\nBelow is the directory structure of this repository:\n\n```\nninjaterm/\n├── firmware-test-apps/ # Contains firmware test applications (Arduino sketches and a Zephyr RTT test app) used for exercising NinjaTerm against real hardware.\n├── docs/ # Contains Docusaurus website which contains the homepage, installation guide and manual. Self-contained node project.\n├── src/ # Contains the Electron application code.\n├── tests/ # Contains the end-to-end tests using Playwright.\n├── web/ # Contains the web-based version of NinjaTerm. Self-contained node project.\n```\n\n## Development\n\nClone this repo. Then run `npm install` to install dependencies:\n\n```bash\nnpm install\n```\n\nStart electron for development:\n\n```bash\nnpm run dev\n```\n\n## To Build The App\n\n```bash\nnpm run build\n```\n\n## To Build A Single Executable\n\n```bash\nnpm run dist\n```\n\nThis will be generated in the `dist` directory.\n\n## Testing\n\nBoth unit tests and end-to-end tests can be run with:\n\n```shell\nnpm run test\n```\n\n### Unit Tests\n\nUnit tests are run with `vitest`, which has good integration with Vite.\n\nTo run just the unit tests, use the command:\n\n```shell\nnpx vitest run\n```\n\n### E2E Tests\n\nEnd-to-end (E2E) (a.k.a. integration tests) are performed using [Playwright](https://playwright.dev/). The Playwright tests are located in the `tests/` directory, and the Playwright config is at `playwright.config.ts`.\n\nTo run just the E2E tests from command line:\n\n```bash\nnpx playwright test\n```\n\nThe Playwright plug-in for VS Code is recommended if interacting with these tests, as it makes running and debugging of them easy!\n\n### Real Tests With An Arduino \n\nArduino sketches in `firmware-test-apps/arduino_*/` allow you to program different applications onto an Arduino for testing the serial port with.\n\n## Releasing\n\nReleases are fully automated from a single command. Prerequisites on release day:\n\n1. You're on `main` with a clean working tree, and the merge of the dev branch has landed.\n2. The CHANGELOG's `## Unreleased` section covers everything going out.\n3. If the app data schema (`LATEST_VERSION` in `src/renderer/src/model/AppDataManager/DataClasses/AppData.ts`) was bumped this cycle, save a fresh default snapshot:\n   - Run `npm run dev` and open the app.\n   - `Settings → General → Clear app data`.\n   - DevTools Console: `copy(localStorage.getItem('appData'))`.\n   - Save clipboard to `local-storage-data/appData-v{N}-app-v{X.Y.Z}-default.json`.\n\nThen cut the release. Always pass the full version explicitly — no `patch` /\n`minor` / `major` shortcuts, just one consistent form for stable, prerelease, or\notherwise:\n\n```\nnpm run release 5.11.0         # next minor\nnpm run release 5.10.1         # patch\nnpm run release 5.11.0-rc.1    # prerelease\nnpm run release v5.11.0        # v-prefix accepted too\n```\n\nChoosing a number follows semver:\n\n- **Major** (`X.0.0`) — breaking changes. Examples from the README's history:\n  framework change, complete UI overhaul.\n- **Minor** (`5.X.0`) — new features added without breaking existing ones.\n- **Patch** (`5.10.X`) — bug fixes and small changes to existing functionality.\n\nThe script runs typecheck + unit tests + the snapshot preflight, finalizes\nCHANGELOG (moves `Unreleased` into a dated section and adds the compare link),\nwrites `package.json`, commits `Release v{X.Y.Z}`, tags `v{X.Y.Z}` (annotated),\nand pushes `main` with the tag. Pass `--preview` to see what the changes would\nlook like without writing anything, or `--allow-dev` to release from the `dev`\nbranch.\n\n(We use `--preview` rather than `--dry-run` because npm intercepts `--dry-run`\nas one of its own flags before it reaches the script.)\n\nFrom there CI takes over: it builds and signs all three platforms, creates the\nGitHub Release, uploads the installers / updater manifests, and extracts the\n`## [X.Y.Z]` section from CHANGELOG.md as the Release body. There's no manual\n\"create draft release\" step any more.\n\n**How CI works:**\n- On every `main` / `dev` push: `test-electron` runs unit tests, the Electron\n  e2e suite (Ubuntu), and a packaging smoke-test on all three platforms with\n  `--publish never`. No upload.\n- On a `v*` tag push: `test-electron` runs first, then the `release` job\n  rebuilds all three platforms with signing + `electron-builder --publish always`,\n  which creates the GitHub Release and attaches the artifacts. A follow-up\n  `release-notes` job fills the Release body from CHANGELOG via `gh release edit`.\n\n## Deployment\n\nNetlify is used to deploy and host the static NinjaTerm HTML/JS. Netlify automatically deploys when the `main` branch is updated. Netlify also creates preview deploys on pull requests (link will be automatically posted into the PR comments).\n\n## Web App\n\nNinjaTerm used to be a progressive web app (PWA). This older web app is now located in the `web` directory. The `web` directory is a project in it's own right, see it's `README.md` for more details.\n\nThis is no longer being updated and is in maintenance mode only.\n\nThe web app is deployed by Netlify to `ninjaterm-app.mbedded.ninja`.\n\n### styled_default is not a function\n\nIf you get the following error in the web app:\n\n```\nGrid2.js:7 Uncaught TypeError: styled_default is not a function\n    at Grid2.js:7:26\n```\n\nComment out the line:\n\n```\ninclude: ['@mui/material/Tooltip', '@emotion/styled', '@mui/material/Unstable_Grid2'],\n```\n\nin `vite.config.ts`. This should fix it. You can then uncomment the line again. Toggling this seems to fix this bug, which after reading online might be due to Vite.\n\n## Graphing\n\nBoth recharts and chart.js was trialed for graphing data coming in on a serial port.\n\nchart.js was chosen as it offered much better performance when the data update rate was fast. rechart could handle about 100 points, any more than that at the render time per new point started to take more than 50ms. chart.js can re-render 1000 points and stay under that limit.\n\n## Performance\n\nNinjaTerm can easily handle 50kB/s of incoming serial data when maximized on a 1920x1080 screen. Reported \"CPU usage\" inside the app (busy time of the main javascript event loop) is around 50% when this is happening on my machine.\n\nMake sure that often updating React components are in their own MobX `observer`s. Prior to doing this, I had things like the throughput, CPU usage, and TX/RX activity bulbs (all in the bottom status bar) directly in the main AppView component. This causes the entire app to re-render when any of these values change, at caused noticeable performance problems at 10kB/s.\n\n## Fonts\n\nFontCreator was used to create the special `NinjaTerm` font. It is based of Consolas. The FontCreator project file is at `src/fonts/NinjaTerm.fcp` and the generated font files are `NinjaTerm-Regular.woff` and `NinjaTerm-Regular.woff2`.\n\nThe PUA (Personal Use Area) is used to add custom glyphs to represent control characters and generic hex bytes. The following code point ranges are used:\n\n* `U+E000` - `U+E07F`: Contains control character glyphs were applicable. Add `0xE000` to a byte which contains a control character to get the equivalent glyph.\n* `U+E100` - `U+E1FF`: Contains a glyph for each byte from `0x00` to `0xFF` containing the byte as a hex number. For example, `U+E100` contains a glyph that says `00`, and `U+E1FF` contains a glyph that says `FF`. Add `0xE100` to a normal byte to get the corresponding glyph.\n\nIn FontCreator, make sure the setting _Tools-\u003eOptions-\u003eFonts-\u003eExclude unused glyphs_ is unchecked, otherwise glyphs at code points like `0x0001` will not be generated.\n\n## Theme Colors\n\n* `#DC3545` (red): Primary colour, used for logo.\n* `#E47F37` (orange): Secondary colour, used for buttons on homepage.\n\n## Saving App Data\n\nSettings are stored to the browser's local storage. The app data is saved under the key `appData`. The `AppDataManager` class is responsible for loading the data, updating it to the latest version if out of date, and saving it back to local storage.\n\nThe folder `local-storage-data/` contains some example app data files for different versions of the app.\n\nThe files with `default` in the name are the default data for that app version. These are used in the unit tests to make sure upgrading app data works correctly.\n\n## Extensions\n\n* Prettier ESLint: Provides formatting of .tsx files.\n* Playwright: Provides useful add-ons for running and debugging the Playwright E2E tests.\n\n[github-actions-status]: https://github.com/gbmhunter/NinjaTerm/actions/workflows/build-and-test.yml/badge.svg?branch=main\n[github-actions-url]: https://github.com/gbmhunter/NinjaTerm/actions\n[github-tag-image]: https://img.shields.io/github/tag/gbmhunter/NinjaTerm.svg?label=version\n[github-tag-url]: https://github.com/gbmhunter/NinjaTerm/releases/latest\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgbmhunter%2Fninjaterm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgbmhunter%2Fninjaterm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgbmhunter%2Fninjaterm/lists"}