Skip to content

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

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

TechnologyPurpose
React 18UI framework
Vite 5Build tool and dev server
React Router DOMClient-side routing
AxiosHTTP requests to compiler backend
avr8jsAVR CPU emulation (used in Web Worker)
intel-hexParsing .hex firmware files
Prism.jsSyntax highlighting in code editor
react-simple-code-editorEmbedded code editor component
@react-oauth/googleGoogle OAuth login
jwt-decodeDecoding JWT auth tokens
@openhw/emulatorShared component definitions (workspace package)
JSZipClient-side ZIP extraction for custom components
@babel/standaloneIn-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 components

Static files:

public/
├── sw.js                           # Service Worker (app shell caching, offline routing)
└── _redirects                      # Deployment redirect rules

Pages

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.json is protected as read-only
  • Undo/Redo — Quick toolbar actions for circuit design with updated iconography
  • Run/Stop — triggers compilation → .hex delivery → Web Worker START message
  • 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

FolderPurpose
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.

json
{ "type": "state", "pins": { "D13": true, "D6": false }, "neopixels": [...] }

NeoPixel Matrix Support

  • Wires NeoPixel components with GND, VCC, DIN, DOUT pins
  • Sends matrix topology (component ID, Arduino pin, size) in the Web Worker START message
  • 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>.ino and main.py starter files.
  • File menu supports Disable file / Enable file by renaming with .disabled suffix.
  • Disabled files are excluded from compile and MicroPython source selection.
  • If backend RP2040 Arduino core is missing, .ino compile 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 sessionStorage to 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 AuthContext and ProtectedRoute components

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 typeOwner keyWhat happens
Guest (no login)'guest'Projects saved locally, visible under "My Projects" on every visit
Authenticated useruser.emailProjects 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:

  1. Check in-memory lastCompiledRef (fastest — same session)
  2. Check IndexedDB cache (survives page refresh and offline)
  3. 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:

RequestStrategy
Navigation (/, any route)Network-first → fallback to cached index.html
JS / CSS / imagesStale-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 .ino compilation, backend must have rp2040:rp2040 core installed.

Installation

bash
cd OpenHW-studio-frontend
npm install

Local 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:

  1. Ensure your .env file has the correct path:
    env
        VITE_EMULATOR_PATH=../path-to-openhw-studio-emulator
  2. Restart the Vite dev server. The @openhw/emulator package 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

bash
npm run dev

The app will be available at http://localhost:5173

Build for Production

bash
npm run build

Preview Production Build

bash
npm run preview

Environment Variables

The frontend uses Vite environment variables. Create a .env file in the project directory:

VariableDescriptionDefault
VITE_GOOGLE_CLIENT_IDGoogle OAuth 2.0 Client ID
VITE_API_BASE_URLBase URL for the Backend APIhttp://localhost:5001/api
VITE_EXAMPLES_BASE_URLBase URL for example assets served by the backend EXAMPLES_PATH routehttp://localhost:5001/examples
VITE_EMULATOR_PATHLocal path to the emulator repository root used by Vite aliasing../path-to-openhw-studio-emulator
VITE_ADMIN_EMAILSComma-separated list of admin emails

Sample .env Setup:

env
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-emulator

How 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.

Released under the MIT License.