OpenHW Studio — React Frontend
The interactive web-based UI for the OpenHW Studio electronics simulation platform. Built with React + Vite, it renders a drag-and-drop circuit editor, streams live simulation state from the emulator, and drives Wokwi web components in real time.
Table of Contents
- Overview
- Tech Stack
- Project Structure
- Pages
- Key Features
- Offline & Storage Features
- Setup & Running Locally
- Environment & Dependencies
- How It Works
Overview
OpenHW Studio Frontend is the visual client of the simulator platform. It allows users to:
- Design circuits by placing and wiring components on a canvas
- Write and edit Arduino C++ code in a built-in syntax-highlighted editor
- Compile and run simulations powered by the backend compiler and the in-browser Web Worker emulator
- Watch simulation output in real time (LEDs blinking, NeoPixels lighting up, servo movement, etc.)
- Save and load projects locally — guests included — using IndexedDB
It connects to one backend service:
- Compiler Backend (
http://localhost:5001) — compiles C++ code to.hex
The simulation itself runs entirely in the browser via a Web Worker powered by avr8js.
Tech Stack
| Technology | Purpose |
|---|---|
| React 18 | UI framework |
| Vite 5 | Build tool and dev server |
| React Router DOM | Client-side routing |
| Axios | HTTP requests to compiler backend |
| avr8js | AVR CPU emulation (used in Web Worker) |
| intel-hex | Parsing .hex firmware files |
| Prism.js | Syntax highlighting in code editor |
| react-simple-code-editor | Embedded code editor component |
| @react-oauth/google | Google OAuth login |
| jwt-decode | Decoding JWT auth tokens |
| @openhw/emulator | Shared component definitions (workspace package) |
| JSZip | Client-side ZIP extraction for custom components |
| @babel/standalone | In-browser transpilation of custom component TypeScript/JSX |
| IndexedDB (native) | Project persistence, hex cache, offline upload queue |
| Service Worker (native) | App shell caching for offline support |
Project Structure
OpenHW-studio-frontend/
├── index.html # App entry HTML
├── vite.config.js # Vite configuration
├── package.json
└── src/
├── main.jsx # React app bootstrap + Service Worker registration
├── App.jsx # Route definitions
├── index.css # Global styles
├── pages/
│ ├── mobileui/ # Mobile-specific UI components/pages
│ ├── simulationpage/ # Simulation page sub-components
│ ├── student/ # Student-specific sub-pages
│ ├── teacher/ # Teacher-specific sub-pages
│ ├── user/ # User profile/settings sub-pages
│ ├── AboutUsPage.jsx # About the platform
│ ├── AdventureMapPage.jsx # Gamified adventure map / learning path
│ ├── ComponentEditorPage.jsx # Custom component creation & editing (194 KB)
│ ├── ComponentsPage.jsx # Browse & manage available components
│ ├── GamificationSimulatorPage.jsx # Gamified simulation entry point
│ ├── GamifiedProjectGuidePage.jsx # Step-by-step guided project (gamified)
│ ├── GradingPage.css # Styles for grading UI
│ ├── GradingPage.jsx # Teacher grading & submission review (63 KB)
│ ├── GuidedSimulatorPage.jsx # Constrained simulator for guided tasks
│ ├── LandingPage.jsx # Public home/landing page
│ ├── LoginPage.jsx # Google OAuth login
│ ├── MaintenancePage.jsx # Maintenance / downtime screen
│ ├── ProjectAssessmentPage.jsx # Project assessment & rubric view
│ ├── ProjectGuidePage.jsx # Project guide / instructions viewer
│ ├── ProjectsGallery.jsx # Browse community/example projects
│ ├── QuizPage.jsx # In-platform quiz / knowledge check
│ ├── RoleSelectPage.jsx # Student / Teacher role selection
│ ├── TheoryPage.jsx # Theory & learning content viewer
│ ├── SimulatorPage.jsx # Main circuit editor + simulation runner
│ ├── admin/ # Admin Portal (Login, Landing, & Dashboard)
│ ├── StudentDashboard.jsx
│ └── TeacherDashboard.jsx
├── context/
│ └── AuthContext.jsx # Global authentication state
├── services/
│ ├── authService.js # Login, logout, token management (localStorage)
│ ├── simulatorService.js # POST /api/compile and component API calls
│ ├── offlineCache.js # IndexedDB: compiled hex cache + ZIP upload queue
│ └── projectStore.js # IndexedDB: full project CRUD (save/load/list/delete)
├── worker/
│ ├── simulation.worker.ts # Web Worker entry point
│ └── execute.ts # AVR CPU execution loop inside worker
└── components/ # Shared UI componentsStatic files:
public/
├── sw.js # Service Worker (app shell caching, offline routing)
└── _redirects # Deployment redirect rulesPages
SimulatorPage.jsx
The core of the application. Responsibilities include:
- Circuit Canvas — drag, drop, and wire Wokwi components
- Resizable Explorer — The file explorer panel is resizable for better code editing space
- Tabbed Interface — Right panel features high-visibility interactive tabs for Editor, Explorer, and Console
- Code Editor — write Arduino sketches with syntax highlighting;
diagram.jsonis protected as read-only - Undo/Redo — Quick toolbar actions for circuit design with updated iconography
- Run/Stop — triggers compilation →
.hexdelivery → Web WorkerSTARTmessage - Live State Rendering — receives
{ type: "state", pins: {...} }at 60 FPS and updates component visual attributes (LEDs, NeoPixels, etc.) - Component Registry — maps component type names to their imported index definitions from
@openhw/emulator - Project Save/Load — auto-saves to IndexedDB every 2.5 s; "My Projects" modal for named saves; auto-loads last project on mount
- Offline resilience — hex cache survives page refresh; ZIP uploads queue while offline
GamificationSimulatorPage.jsx
Entry point for the gamified simulation experience. Wraps the simulator in a gamified context with progress tracking, achievements, and challenge constraints.
GuidedSimulatorPage.jsx
A constrained version of the simulator used during guided project tasks. Limits available components and actions to match the current step's learning objectives.
AdventureMapPage.jsx
Visual adventure map / learning path. Displays the student's progress across projects and theory modules as an interactive map with unlockable nodes.
GamifiedProjectGuidePage.jsx
Step-by-step guided project page with gamification elements (XP, badges, progress bars). Renders project instructions alongside an embedded simulator or component viewer.
ProjectGuidePage.jsx
Standard (non-gamified) project instructions and guide viewer. Renders markdown or structured content for a given project.
TheoryPage.jsx
Theory and learning content viewer. Renders lesson content (text, images, diagrams) for a given topic module before students attempt the hands-on simulator task.
QuizPage.jsx
In-platform quiz and knowledge-check page. Presents multiple-choice or short-answer questions tied to a theory module or project, and records scores.
ProjectAssessmentPage.jsx
Assessment and rubric view for a completed project. Shows the student their submission status and (if graded) their score and teacher feedback.
GradingPage.jsx
Teacher-facing grading and submission review interface. Lists student submissions for a given assignment, allows rubric-based scoring, and submits grades back to the backend.
ComponentEditorPage.jsx
Full custom component creation and editing environment. Allows users to write TypeScript/JSX component definitions, preview them in an isolated canvas, and submit them to the community library.
ComponentsPage.jsx
Browse and manage available simulation components. Shows the installed library, community submissions, and allows searching, filtering, and installing components.
ProjectsGallery.jsx
Community and example project gallery. Displays shareable projects with thumbnails, descriptions, and a one-click "Open in Simulator" action.
AboutUsPage.jsx
Public-facing About page describing the OpenHW Studio platform, team, and mission.
MaintenancePage.jsx
Maintenance / downtime screen. Shown when the platform or backend is undergoing scheduled maintenance.
LoginPage.jsx
Google OAuth 2.0 login page. Decodes JWT and stores user info in AuthContext.
AdminPage.jsx
A powerful administrative hub for platform maintenance:
- 3-Column Management: Independent scrollable panels for Libraries, Pending Submissions, and Installed Components.
- Review Workflow: Admins can check submissions with live Transpile feedback, download source ZIPs, or open them in a live Simulator "Test" tab.
- Real-time Actions: Approval instantly moves components to the backend; rejection removes specific submissions (unique per upload).
- Library Manager: Search and uninstall system-level C++ libraries for the Arduino compiler.
LandingPage.jsx
Public-facing landing page describing the platform.
StudentDashboard.jsx / TeacherDashboard.jsx
Role-specific dashboards shown after login.
Sub-directories
| Folder | Purpose |
|---|---|
mobileui/ | Mobile-specific UI layouts and page variants |
simulationpage/ | Sub-components and utilities extracted from SimulatorPage |
student/ | Student-specific sub-pages (progress, submissions, etc.) |
teacher/ | Teacher-specific sub-pages (class management, assignment creation, etc.) |
user/ | User profile and account settings sub-pages |
Key Features
Real-time Simulation Rendering (60 FPS)
The Web Worker runs the AVR CPU and posts state messages back to the main thread every frame. The frontend maps pin voltages to DOM attribute changes on Wokwi custom HTML elements.
{ "type": "state", "pins": { "D13": true, "D6": false }, "neopixels": [...] }NeoPixel Matrix Support
- Wires NeoPixel components with
GND,VCC,DIN,DOUTpins - Sends matrix topology (component ID, Arduino pin, size) in the Web Worker
STARTmessage - Calls
element.setPixel(row, col, {r, g, b})directly on the Wokwi DOM element
Analog Plotter / Logic Graph
A native high-performance <canvas> rendering engine tab traces simulated logic and analog signals. Users can dynamically specify which pins to track.
Serial Monitor Integration
A built-in terminal streams AVRUSART traffic bidirectionally into the .hex loop.
Physical Workspace Controls
The Arduino Uno Reset Button is fully interactive inside the workspace SVG visualizer, triggering a targeted runner.cpu.reset() reboot in the Web Worker.
Web Worker Simulation
AVR simulation runs entirely in-browser via src/worker/execute.ts inside a Web Worker, keeping the UI thread completely unblocked.
Pico / RP2040 Workflow
- Each Pico board folder now includes both
<boardId>.inoandmain.pystarter files. - File menu supports Disable file / Enable file by renaming with
.disabledsuffix. - Disabled files are excluded from compile and MicroPython source selection.
- If backend RP2040 Arduino core is missing,
.inocompile failures automatically fall back to MicroPython UF2 +main.py.
Explorer Stability
- Project files are normalized and deduplicated when loading saved projects to prevent duplicate file entries after refresh.
Zero-Touch Component Sync
The simulator polls the backend every 12 seconds for newly approved community components:
- Dynamic Injection: New components are transpiled and injected into the registry and palette without a page refresh.
- Live Deletion: If a component is uninstalled from the admin panel, it is purged from all active simulator sessions automatically.
- Admin "Test" Mode: An isolated preview mechanism uses
sessionStorageto test pending components before approval.
Auth Flow
- Google OAuth → JWT stored in context
- Role selection (Student / Teacher / Admin) → role-specific entry points
- Protected routes via
AuthContextandProtectedRoutecomponents
Offline & Storage Features
All storage features use the browser-native IndexedDB API and Service Worker API. No extra npm packages are required, and no backend changes are needed.
Project Persistence (IndexedDB — openhw-projects)
Every circuit is automatically saved to a local IndexedDB database every 2.5 seconds after any change. This works for both authenticated users and guest users with no login required.
| User type | Owner key | What happens |
|---|---|---|
| Guest (no login) | 'guest' | Projects saved locally, visible under "My Projects" on every visit |
| Authenticated user | user.email | Projects saved locally, scoped to that email |
Buttons added to the header:
- Save — opens a name dialog; pressing Enter or clicking Save commits the name
- My Projects — opens a modal listing all saved projects (name, board, components count, last-saved time) with Load and Delete actions
- New — starts a blank canvas (current project is preserved in IDB)
- Project name chip — shows the current project name in the header; click to rename
On page load, the most-recently saved project for the current user (or guest) is automatically restored.
Compiled Hex Cache (IndexedDB — openhw-offline)
Compiled .hex results are saved to IndexedDB after every successful compile. On subsequent runs:
- Check in-memory
lastCompiledRef(fastest — same session) - Check IndexedDB cache (survives page refresh and offline)
- Compile via
POST /api/compile(requires network)
This means: run your simulation offline after compiling at least once while online.
Offline ZIP Component Upload Queue (IndexedDB — openhw-offline)
If you upload a custom component ZIP while offline:
- The component is injected into the local registry immediately (usable right away)
- The backend submission is queued in IndexedDB
- When the internet is restored, the queue is automatically drained
Service Worker (public/sw.js)
Cached on first load. Strategies:
| Request | Strategy |
|---|---|
Navigation (/, any route) | Network-first → fallback to cached index.html |
| JS / CSS / images | Stale-while-revalidate (instant load + background update) |
| CDN scripts (wokwi-elements) | Stale-while-revalidate |
/api/* | Network-only (never cached — hex caching is at the app layer) |
See OFFLINE_AND_STORAGE.md for full technical details.
Setup & Running Locally
Prerequisites
- Node.js 18+
- npm 9+
- The Compiler Backend running at
http://localhost:5001 - For Pico
.inocompilation, backend must haverp2040:rp2040core installed.
Installation
cd OpenHW-studio-frontend
npm installLocal Development & NPM Linking
During local development, you will want the frontend to immediately see changes you make to the emulator source code, without having to push those changes to GitHub first.
We achieve this using Vite Resolve Aliases, which tell the frontend to use your local emulator repository folder. This is controlled by the VITE_EMULATOR_PATH variable in your .env file and bypasses the need for npm link.
Set the path to your own emulator repo name. It can be relative or absolute, as long as it points at the emulator repository root.
To set up your local development:
- Ensure your
.envfile has the correct path:envVITE_EMULATOR_PATH=../path-to-openhw-studio-emulator - Restart the Vite dev server. The
@openhw/emulatorpackage will now point directly to your local source.
Note: You can still use npm link if preferred, but the environment variable approach is more portable across different machines.
Production Deployment (Vercel / Docker)
For production builds (like on Vercel), the VITE_EMULATOR_PATH variable should be left unset. The vite.config.js is designed to automatically fallback to the @openhw/emulator package installed in node_modules (fetched from GitHub) if the local path is not found.
Note: Once deployed to Vercel/Netlify, these local symlinks will be ignored and the remote server will correctly fetch the package directly from GitHub.
Start Development Server
npm run devThe app will be available at http://localhost:5173
Build for Production
npm run buildPreview Production Build
npm run previewEnvironment Variables
The frontend uses Vite environment variables. Create a .env file in the project directory:
| Variable | Description | Default |
|---|---|---|
VITE_GOOGLE_CLIENT_ID | Google OAuth 2.0 Client ID | — |
VITE_API_BASE_URL | Base URL for the Backend API | http://localhost:5001/api |
VITE_EXAMPLES_BASE_URL | Base URL for example assets served by the backend EXAMPLES_PATH route | http://localhost:5001/examples |
VITE_EMULATOR_PATH | Local path to the emulator repository root used by Vite aliasing | ../path-to-openhw-studio-emulator |
VITE_ADMIN_EMAILS | Comma-separated list of admin emails | — |
Sample .env Setup:
VITE_GOOGLE_CLIENT_ID=your_id.apps.googleusercontent.com
VITE_API_BASE_URL=http://localhost:5001/api
VITE_EXAMPLES_BASE_URL=http://localhost:5001/examples
VITE_ADMIN_EMAILS=admin@example.com,user@example.com
VITE_EMULATOR_PATH=../path-to-openhw-studio-emulatorHow It Works
User writes C++ code
│
▼
POST /api/compile ──► Compiler Backend (port 5001)
│
Returns .hex file
│ also cached to IndexedDB
▼
Frontend sends START + .hex + wiring topology
│
Web Worker (browser)
│
Runs AVR CPU at 16 MHz in-browser
Streams pin states at 60 FPS
│
▼
Frontend updates Wokwi component DOM attributes
(LEDs, NeoPixels, Servo, etc.)Part of the OpenHW Studio platform. See also: openhw-studio-backend and openhw-studio-emulator.
