A web-based Arduino simulator with a browser UI, server-side Arduino compilation and an interactive Arduino Preview for sketches.
Administration: For local development and Docker installation, see
docs/INSTALL_LOCAL.mdanddocs/INSTALL_SERVER.md. Security requirements are indocs/SECURITY.md.
- Code Editor: Monaco editor integration for writing Arduino sketches with syntax highlighting
- Compilation: Compile Arduino code through the UnoSim backend
- Serial Monitor: Real-time output display from simulated Arduino execution
- Pause/Resume Simulation: Pause running sketches to inspect state, change pin values, and resume execution
- Arduino Preview: A preview of analog/digital inputs and outputs directly in the Arduino SVG
- Web-based UI: Use the simulator in a browser; local/server installation runs the backend
- Modern UI: Built with React and TailwindCSS for a responsive, professional interface
- I/O Registry: You can see what Pins are used in your Program!
- Frontend: React, TypeScript, Vite, TailwindCSS, Radix UI
- Backend: Node.js (TypeScript), Express, WebSocket support
- Editor: Monaco Editor
- Testing: Vitest with React Testing Library
- Build Tools: Vite, esbuild
- Node.js 24.20.0 LTS (see
.nvmrc) - npm or yarn
- Clone the repository:
git clone https://github.com/MoDevIO/UnoSim.git
cd UnoSim- Install dependencies:
npm ci- Start the dev-server:
npm run dev:fullThis will start both the backend server and the frontend development server.
UnoSim supports two runtime profiles: local development and Docker deployment.
npm run dev:fullStarts the backend (Express + WebSocket) and the Vite dev server with hot-reload.
The backend runs via tsx (TypeScript execution) and the client is served by Vite on a separate port with HMR.
Compilation uses arduino-cli directly on the host — Docker is not required.
npm run dev starts only the backend on the local listener (127.0.0.1). The
development profile is single-user and is not a deployment mode. Both commands
use the configured external-example source, ref, and host allowlist from the
development script.
The accepted target architecture keeps that server configuration as the
default, while allowing each browser to select a validated public GitHub
Examples repository and ref in Settings. The browser preference is
request-scoped, never changes the server default, and never fetches GitHub
directly. The default is ttbombadil/unosim-examples at main; the server
resolves the ref to a full commit SHA before loading a complete snapshot. See
ssot_function_definition_ExternalExamples.md.
| Component | Details |
|---|---|
| Backend | tsx server/index.ts on configured PORT (default 3000) |
| Client | Vite HMR dev server (proxied) |
| Compiler | Direct arduino-cli calls on host |
| Worker Pool | Disabled (CompilerWithFallback.usePool = false outside production) |
npm run build
npm run startBuilds the full stack (client + server + worker) into dist/. The supported
production profile runs this server in Docker and executes every simulation in
a Docker sandbox. The Vite-built client is served as static files from
dist/public/.
| Component | Details |
|---|---|
| Backend | node dist/index.js on configured PORT (default 3000) |
| Client | Static files from dist/public/ |
| Compiler | Configured Worker Pool (Compose reference: 8 parallel workers) |
| Docker | Required for the server container and all simulation sandboxes |
Note: Local development compiles and executes directly on the host. The Docker profile requires a working Docker daemon and sandbox image and never falls back to host-native simulation.
docker build -t unosim-sandbox:latest -f Dockerfile.sandbox .
docker build -t unosim-server:latest .For a manual production container, use the same gateway, sandbox and mount
requirements as Compose. At minimum, production requires Gateway mode,
UNOSIM_GATEWAY_SECRET (at least 32 characters), UNOSIM_TRUSTED_PROXY, and
UNOSIM_ALLOWED_WS_ORIGINS; the backend also needs the Docker socket and the
unosim-sandbox:latest image available to the configured Docker daemon:
docker run --rm -p 3000:3000 \
-e NODE_ENV=production \
-e UNOSIM_SERVER_MODE=docker \
-e UNOSIM_GATEWAY_SECRET='<secret-from-secret-store>' \
-e UNOSIM_TRUSTED_PROXY='<gateway-ip-or-cidr>' \
-e UNOSIM_ALLOWED_WS_ORIGINS='https://classroom.example.edu' \
-e DOCKER_HOST=unix:///var/run/docker.sock \
-e DOCKER_SANDBOX_IMAGE=unosim-sandbox:latest \
-e ARDUINO_CACHE_DIR=${PWD}/server/arduino-cache \
-e UNOSIM_SHARED_TEMP_DIR=${PWD}/temp \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ${PWD}/server/arduino-cache:${PWD}/server/arduino-cache \
-v ${PWD}/temp:${PWD}/temp \
-v ${PWD}/storage:/app/storage \
unosim-server:latestOr with Docker Compose (backend only):
export DOCKER_GID="$(stat -c '%g' /var/run/docker.sock)"
export UNOSIM_GATEWAY_SECRET="<at-least-32-random-characters>"
export UNOSIM_TRUSTED_PROXY="<gateway-ip-or-cidr>"
export UNOSIM_ALLOWED_WS_ORIGINS="https://classroom.example.edu"
docker compose up --buildCompose starts the UnoSim backend only. Docker mode always requires an authentication gateway; the four variables above are mandatory and must be supplied by the deployment's secret/environment management. A reverse proxy/auth gateway must forward authenticated HTTP and WebSocket requests. Sandbox execution remains dynamic and uses the Docker socket at runtime.
If you need SonarQube, run it separately in its own stack or service; the UnoSim compose file does not include SonarQube or MCP.
The application runs inside a container and is available at http://localhost:3000.
For sandboxed sketch execution, the server container must use a temp directory that is bind-mounted from the host at the same absolute path. The provided Compose file does this via UNOSIM_SHARED_TEMP_DIR=${PWD}/temp and ${PWD}/temp:${PWD}/temp.
On macOS, make sure your project directory is allowed under Docker Desktop file sharing, otherwise the inner sandbox container cannot see generated files such as sketch.cpp.
| Command | Description |
|---|---|
npm run dev:full |
Start backend + client in development mode |
npm run dev |
Start backend only (no client) |
npm run dev:client |
Start Vite client only |
npm run build |
Build client, server, and worker for production |
npm run start |
Run the production build |
npm run check |
TypeScript type-check (tsc --noEmit) |
npm run test:fast |
Run deterministic unit tests |
npm run test:integration |
Run Arduino/toolchain integration tests |
npm run test:docker |
Run Docker sandbox integration tests |
npm run test:e2e |
Run Playwright browser tests |
npm run test:all |
Run unit, integration and Docker gates |
./run-tests.sh |
Full pipeline: lint, unit tests, Docker build, integration tests, E2E |
RUN_HEAVY_TESTS=1 ./run-tests.sh |
Full pipeline inklusive langsamem Parallel-Instanz-Stresstest |
- Sandbox Runner Pool — Manages runner leases for sketch execution. In the documented production path, each simulation runs in a short-lived isolated Docker sandbox with stdout/stderr capture for serial output and pin state reporting.
- Compilation Worker Pool — In production mode, the configured Node.js Worker Thread pool handles compilations in parallel via
CompilerWithFallback. The Compose reference uses 8 workers; capacity limits are documented indocs/SCALABILITY.md. - WebSocket Layer — Real-time communication between client and server for serial output, pin state batches, and simulation control (start/stop/pause/resume).
- SonarQube Integration — Optional SonarQube scans are wired into the pre-push hook and
./run-tests.shwhenSONAR_TOKENand a reachable SonarQube service are available. Release blocking is controlled byREQUIRE_RELEASE_GATE=1.
The repository contains a robust, fast test pipeline:
- Unit tests (Vitest + React Testing Library) cover business logic and UI
components.
npm run test:unitis the deterministic refactoring gate; toolchain, Docker, browser and load tests are separate gates. - E2E smoke flow comprises three Playwright tests in
e2e/smoke-and-flow.spec.tsfor startup, compile/run with serial output, and dialogs. The repository also contains separate responsive, board, visual, and scalability E2E suites; runnpm run test:e2efor the configured suite. - Heavy stress tests are opt-in. Use
RUN_HEAVY_TESTS=1 ./run-tests.shwhen validating Docker sandbox isolation and cleanup. Load-test commands are listed indocs/RELEASE_RUNBOOK.mdand capacity conclusions belong indocs/SCALABILITY.md.
Local quick‑check example:
npm run test:unitFor release gates, follow docs/RELEASE_RUNBOOK.md.
Testing conventions and timing budgets are maintained in
docs/TESTING_STANDARDS.md.
MIT License - See LICENSE for details
This project uses third-party open-source dependencies under their respective licenses.
- Issues & Bugs: Use the GitHub Issues tracker
- Feature Requests: Create an Pull Request
- Questions: Open a discussion or check existing issues
- Mo Tiltmann (MoDevIO) - Couven-Gymnasium, Aachen
- Tom Tiltmann (ttbombadil) - Technische Hochschule, Köln


