velxio/CLAUDE.md

10 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

This is a local Arduino emulator (Wokwi clone) that provides a full development environment for Arduino projects:

  • Frontend: React + Vite + TypeScript with Monaco Editor and visual simulation canvas
  • Backend: FastAPI + Python for Arduino code compilation via arduino-cli
  • Simulation: Real AVR8 emulation using avr8js with full GPIO/timer/USART support
  • Components: Visual electronic components from wokwi-elements (LEDs, resistors, buttons, etc.)

The project uses local clones of official Wokwi repositories instead of npm packages for maximum compatibility and ease of updates.

Development Commands

Backend (FastAPI + Python)

Setup:

cd backend
python -m venv venv
venv\Scripts\activate  # Windows
pip install -r requirements.txt

Run development server:

cd backend
venv\Scripts\activate
uvicorn app.main:app --reload --port 8001

Access:

Frontend (React + Vite)

Setup:

cd frontend
npm install

Run development server:

cd frontend
npm run dev

Build for production:

cd frontend
npm run build

Lint:

cd frontend
npm run lint

Access:

Wokwi Libraries (Local Repositories)

The project uses local clones of Wokwi repositories in wokwi-libs/:

  • wokwi-elements/ - Web Components for electronic parts
  • avr8js/ - AVR8 CPU emulator
  • rp2040js/ - RP2040 emulator (future use)

Update libraries:

update-wokwi-libs.bat

Or manually:

cd wokwi-libs/wokwi-elements
git pull origin main
npm install
npm run build

External Dependencies

arduino-cli must be installed on your system:

# Verify installation
arduino-cli version

# Initialize (first time)
arduino-cli core update-index
arduino-cli core install arduino:avr

Architecture

High-Level Data Flow

  1. Code Editing: User writes Arduino code → Monaco Editor → Zustand store (useEditorStore)
  2. Compilation: Code → Frontend API call → Backend FastAPI → arduino-cli subprocess → Returns .hex file
  3. Simulation: .hex file → AVRSimulator.loadHex() → Parsed into Uint16Array → CPU execution loop
  4. Pin Updates: CPU writes to PORTB/C/D → Port listeners → PinManager → Component state updates
  5. Visual Updates: Component state changes → React re-renders → wokwi-elements update visually

Critical Architecture Patterns

1. Vite Aliases for Local Wokwi Libs

The frontend/vite.config.ts uses path aliases to import from local repositories:

resolve: {
  alias: {
    'avr8js': path.resolve(__dirname, '../wokwi-libs/avr8js/dist/esm'),
    '@wokwi/elements': path.resolve(__dirname, '../wokwi-libs/wokwi-elements/dist/esm'),
  },
}

This allows importing as if they were npm packages while using local clones.

2. AVR Simulation Loop

The simulation runs at ~60 FPS using requestAnimationFrame:

  • Each frame executes ~267,000 CPU cycles (16MHz / 60fps)
  • Port listeners fire when PORTB/C/D registers change
  • PinManager maps Arduino pins to components (e.g., pin 13 → LED_BUILTIN)

3. State Management with Zustand

Two main stores:

  • useEditorStore: Code content, theme
  • useSimulatorStore: Simulation state, components, wires, compiled hex

4. Component-Pin Mapping

Components are connected to Arduino pins via the PinManager:

  • PORTB maps to digital pins 8-13 (pin 13 = built-in LED)
  • PORTC maps to analog pins A0-A5
  • PORTD maps to digital pins 0-7

When a port value changes, PinManager calls registered callbacks for affected components.

5. Wire System (Phase 1 - Visual Only)

Wires are stored as objects with start/end endpoints:

{
  id: string
  start: { componentId, pinName, x, y }
  end: { componentId, pinName, x, y }
  color: string
  signalType: 'digital' | 'analog' | 'power-vcc' | 'power-gnd'
}

Wire positions auto-update when components move via updateWirePositions().

Key File Locations

Backend

Frontend - Core

Frontend - Simulation

Frontend - UI Components

Important Implementation Notes

1. AVR Instruction Execution

The simulation must call both avrInstruction() and cpu.tick() in the execution loop:

avrInstruction(this.cpu);  // Execute the AVR instruction
this.cpu.tick();           // Update peripheral timers and cycles

Missing avrInstruction() will cause the CPU to appear "stuck" even though cycles increment.

2. Port Listeners

Port listeners in AVRSimulator.ts are attached to AVRIOPort instances, NOT directly to CPU registers:

this.portB!.addListener((value, oldValue) => {
  // value is the PORTB register value (0-255)
  // Check individual pins: this.portB!.pinState(5) for pin 13
});

3. HEX File Format

Arduino compilation produces Intel HEX format. The parser in hexParser.ts:

  • Parses lines starting with :
  • Extracts address, record type, and data bytes
  • Returns a Uint8Array of program bytes
  • AVRSimulator converts this to Uint16Array (16-bit words, little-endian)

4. Component Registration

To add a component to the simulation:

  1. Add it to the canvas in SimulatorCanvas.tsx
  2. Register a pin change callback in PinManager
  3. Update component state when pin changes

Example:

pinManager.registerCallback(13, (state) => {
  // Update LED when pin 13 changes
  useSimulatorStore.getState().updateComponentState('led-builtin', state);
});

5. CORS Configuration

Backend allows specific Vite dev ports (5173-5175). Update backend/app/main.py if using different ports.

6. Wokwi Elements Integration

Wokwi elements are Web Components. React wrappers declare custom elements:

declare global {
  namespace JSX {
    interface IntrinsicElements {
      'wokwi-led': any;
    }
  }
}

Testing

Backend Testing

Test compilation directly:

cd backend
python test_compilation.py

Frontend Testing

No test suite currently implemented. Manual testing via dev server.

Common Development Scenarios

Adding a New Electronic Component

  1. Check if wokwi-elements has the component (see wokwi-libs/wokwi-elements/src/)
  2. Create React wrapper in frontend/src/components/components-wokwi/
  3. Add component type to useSimulatorStore interface
  4. Update SimulatorCanvas to render the component
  5. Register pin callbacks in PinManager if interactive

Adding a New API Endpoint

  1. Create route in backend/app/api/routes/
  2. Include router in backend/app/main.py
  3. Add corresponding service in backend/app/services/ if needed
  4. Create API client function in frontend/src/services/

Debugging Simulation Issues

Common issues:

  • LED doesn't blink: Check port listeners are firing (console logs), verify pin mapping
  • Compilation fails: Check arduino-cli is in PATH, verify arduino:avr core is installed
  • CPU stuck at PC=0: Ensure avrInstruction() is being called in execution loop
  • Wire positions wrong: Check calculatePinPosition() uses correct component coordinates

Enable verbose logging:

  • AVRSimulator logs port changes and CPU state every 60 frames
  • Backend logs all compilation steps and arduino-cli output

Project Status

Implemented:

  • Full Arduino code editing with Monaco Editor
  • Compilation via arduino-cli to .hex files
  • Real AVR8 emulation with avr8js
  • Pin state tracking and component updates
  • Dynamic component system with 48+ wokwi-elements components
  • Component picker modal with search and categories
  • Component property dialog (single-click interaction)
  • Component rotation (90° increments)
  • Wire creation and rendering (orthogonal routing)
  • Segment-based wire editing (drag segments perpendicular to orientation)
  • Real-time wire preview with grid snapping (20px)
  • Pin overlay system for wire connections

In Progress:

  • 🚧 Functional wire connections (electrical signal routing)
  • 🚧 Wire validation and error handling

Planned:

  • 📋 Serial monitor
  • 📋 Project persistence (SQLite)
  • 📋 Multi-board support (Mega, Nano, ESP32)
  • 📋 Undo/redo functionality

Additional Resources