Create documentation page accessible at /docs
- Add docs/ folder with intro, getting-started, emulator, components, roadmap markdown files - Add DocsPage.tsx with sidebar navigation, section content, pagination - Add DocsPage.css matching existing dark theme - Register /docs route in App.tsx - Add /docs to sitemap.xml Co-authored-by: davidmonterocrespo24 <47928504+davidmonterocrespo24@users.noreply.github.com>pull/21/head
parent
6a2a3df970
commit
d711fe49b1
|
|
@ -0,0 +1,113 @@
|
|||
# Components Reference
|
||||
|
||||
Velxio ships with **48+ interactive electronic components** powered by [wokwi-elements](https://github.com/wokwi/wokwi-elements). All components can be placed on the simulation canvas, connected with wires, and interact with your Arduino sketch in real time.
|
||||
|
||||
---
|
||||
|
||||
## Adding Components
|
||||
|
||||
1. Click the **+** button on the simulation canvas.
|
||||
2. Use **search** or browse by **category** in the component picker.
|
||||
3. Click a component to place it on the canvas.
|
||||
4. **Drag** to reposition; click to open the **Property Dialog** (pin roles, Arduino pin assignment, rotate, delete).
|
||||
|
||||
---
|
||||
|
||||
## Connecting Components
|
||||
|
||||
1. Click a **pin** on any component — a wire starts from that pin.
|
||||
2. Click a **destination pin** to complete the connection.
|
||||
3. Wires are **color-coded** by signal type:
|
||||
|
||||
| Color | Signal type |
|
||||
|-------|-------------|
|
||||
| 🔴 Red | VCC (power) |
|
||||
| ⚫ Black | GND (ground) |
|
||||
| 🔵 Blue | Analog |
|
||||
| 🟢 Green | Digital |
|
||||
| 🟣 Purple | PWM |
|
||||
| 🟡 Gold | I2C (SDA/SCL) |
|
||||
| 🟠 Orange | SPI (MOSI/MISO/SCK) |
|
||||
| 🩵 Cyan | USART (TX/RX) |
|
||||
|
||||
---
|
||||
|
||||
## Component Categories
|
||||
|
||||
### Output
|
||||
|
||||
| Component | Description |
|
||||
|-----------|-------------|
|
||||
| LED | Single LED with configurable color |
|
||||
| RGB LED | Three-color LED (red, green, blue channels) |
|
||||
| 7-Segment Display | Single digit numeric display |
|
||||
| LCD 16×2 | 2-line character LCD (I2C or parallel) |
|
||||
| LCD 20×4 | 4-line character LCD |
|
||||
| ILI9341 TFT | 240×320 color TFT display (SPI) |
|
||||
| Buzzer | Passive piezo buzzer |
|
||||
| NeoPixel | Individually addressable RGB LED strip |
|
||||
|
||||
### Input
|
||||
|
||||
| Component | Description |
|
||||
|-----------|-------------|
|
||||
| Push Button | Momentary push button |
|
||||
| Slide Switch | SPDT slide switch |
|
||||
| Potentiometer | Analog voltage divider (ADC input) |
|
||||
| Rotary Encoder | Incremental rotary encoder |
|
||||
| Keypad 4×4 | 16-button matrix keypad |
|
||||
| Joystick | Dual-axis analog joystick |
|
||||
|
||||
### Sensors
|
||||
|
||||
| Component | Description |
|
||||
|-----------|-------------|
|
||||
| HC-SR04 | Ultrasonic distance sensor |
|
||||
| DHT22 | Temperature and humidity sensor |
|
||||
| PIR Motion | Passive infrared motion sensor |
|
||||
| NTC Thermistor | Analog temperature sensor |
|
||||
| Photoresistor | Light-dependent resistor (LDR) |
|
||||
| IR Receiver | 38 kHz infrared receiver |
|
||||
|
||||
### Passive Components
|
||||
|
||||
| Component | Description |
|
||||
|-----------|-------------|
|
||||
| Resistor | Standard resistor (configurable value) |
|
||||
| Capacitor | Electrolytic capacitor |
|
||||
| Inductor | Coil inductor |
|
||||
|
||||
### Communication
|
||||
|
||||
| Component | Description |
|
||||
|-----------|-------------|
|
||||
| I2C EEPROM | 24Cxx series EEPROM (I2C) |
|
||||
| SPI Flash | 25-series SPI NOR flash |
|
||||
| RFID (RC522) | SPI RFID reader/writer |
|
||||
|
||||
### Power & Connectors
|
||||
|
||||
| Component | Description |
|
||||
|-----------|-------------|
|
||||
| Power Rail | VCC / GND bus bar |
|
||||
| Terminal Block | 2-pin screw terminal |
|
||||
|
||||
---
|
||||
|
||||
## Component Properties
|
||||
|
||||
Each component has a **Property Dialog** accessible by clicking it on the canvas:
|
||||
|
||||
| Property | Description |
|
||||
|----------|-------------|
|
||||
| Arduino Pin | The digital or analog pin this component is connected to |
|
||||
| Color | Visual color (LEDs, wires) |
|
||||
| Value | Component value (e.g., resistance in Ω) |
|
||||
| Rotation | Rotate in 90° increments |
|
||||
| Delete | Remove the component from the canvas |
|
||||
|
||||
---
|
||||
|
||||
## Adding Custom Components
|
||||
|
||||
See [Architecture: Component System](./emulator.md#component-system) for details on registering new wokwi-elements components in the simulation.
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
# Emulator Architecture
|
||||
|
||||
Velxio uses **real CPU emulation** rather than a simplified model. This document describes how each layer of the simulation works.
|
||||
|
||||
---
|
||||
|
||||
## High-Level Data Flow
|
||||
|
||||
```
|
||||
User Code (Monaco Editor)
|
||||
│
|
||||
▼
|
||||
Zustand Store (useEditorStore)
|
||||
│
|
||||
▼
|
||||
FastAPI Backend ──► arduino-cli subprocess ──► .hex / .uf2 file
|
||||
│
|
||||
▼
|
||||
AVRSimulator / RP2040Simulator
|
||||
│ loadHex()
|
||||
▼
|
||||
CPU execution loop (~60 FPS via requestAnimationFrame)
|
||||
│
|
||||
▼
|
||||
Port listeners (PORTB / PORTC / PORTD)
|
||||
│
|
||||
▼
|
||||
PinManager ──► Component state updates ──► React re-renders
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## AVR8 Emulation (Arduino Uno / Nano / Mega)
|
||||
|
||||
The AVR backend uses **[avr8js](https://github.com/wokwi/avr8js)**, which implements a complete ATmega328p / ATmega2560 processor.
|
||||
|
||||
### Execution Loop
|
||||
|
||||
Each animation frame executes approximately 267,000 CPU cycles (16 MHz ÷ 60 FPS):
|
||||
|
||||
```typescript
|
||||
avrInstruction(cpu); // decode and execute one AVR instruction
|
||||
cpu.tick(); // advance peripheral timers and counters
|
||||
```
|
||||
|
||||
### Supported Peripherals
|
||||
|
||||
| Peripheral | Details |
|
||||
|-----------|---------|
|
||||
| GPIO | PORTB (pins 8–13), PORTC (A0–A5), PORTD (pins 0–7) |
|
||||
| Timer0 / Timer1 / Timer2 | `millis()`, `delay()`, PWM via `analogWrite()` |
|
||||
| USART | Full transmit and receive — powers the Serial Monitor |
|
||||
| ADC | 10-bit, 5 V reference on pins A0–A5 |
|
||||
| SPI | Hardware SPI (enables ILI9341, SD card, etc.) |
|
||||
| I2C (TWI) | Hardware I2C with virtual device bus |
|
||||
|
||||
### Pin Mapping
|
||||
|
||||
| Arduino Pin | AVR Port | Bit |
|
||||
|-------------|----------|-----|
|
||||
| 0–7 | PORTD | 0–7 |
|
||||
| 8–13 | PORTB | 0–5 |
|
||||
| A0–A5 | PORTC | 0–5 |
|
||||
|
||||
---
|
||||
|
||||
## RP2040 Emulation (Raspberry Pi Pico)
|
||||
|
||||
The RP2040 backend uses **[rp2040js](https://github.com/wokwi/rp2040js)**.
|
||||
|
||||
### Features
|
||||
|
||||
- Real RP2040 emulation at 133 MHz
|
||||
- UART0 serial output displayed in the Serial Monitor
|
||||
- 12-bit ADC on GPIO 26–29 (A0–A3) with 3.3 V reference
|
||||
|
||||
### Compilation
|
||||
|
||||
Pico sketches are compiled with the [arduino-pico](https://github.com/earlephilhower/arduino-pico) core via `arduino-cli`. The Serial redirect patch is applied only to `sketch.ino` to route `Serial.print()` output to UART0.
|
||||
|
||||
---
|
||||
|
||||
## HEX File Format
|
||||
|
||||
Arduino compilation produces **Intel HEX** format. The parser in `hexParser.ts`:
|
||||
|
||||
1. Reads lines starting with `:`
|
||||
2. Extracts the address, record type, and data bytes
|
||||
3. Returns a `Uint8Array` of program bytes
|
||||
4. `AVRSimulator` converts this to a `Uint16Array` (16-bit words, little-endian) and loads it into the CPU's program memory
|
||||
|
||||
---
|
||||
|
||||
## Component System
|
||||
|
||||
Components are rendered using **[wokwi-elements](https://github.com/wokwi/wokwi-elements)** — a library of Web Components for electronic parts.
|
||||
|
||||
### Component Registration
|
||||
|
||||
1. The component is rendered on the `SimulatorCanvas`.
|
||||
2. A pin-change callback is registered in `PinManager`.
|
||||
3. The callback updates component state in the Zustand store.
|
||||
4. React re-renders the component with the updated state.
|
||||
|
||||
### Wire Routing
|
||||
|
||||
Wires use **orthogonal routing** (no diagonal paths). Each wire stores:
|
||||
|
||||
```typescript
|
||||
{
|
||||
id: string
|
||||
start: { componentId, pinName, x, y }
|
||||
end: { componentId, pinName, x, y }
|
||||
color: string // e.g. 'red' for VCC
|
||||
signalType: 'digital' | 'analog' | 'power-vcc' | 'power-gnd'
|
||||
}
|
||||
```
|
||||
|
||||
Wire positions update automatically when components are moved.
|
||||
|
||||
---
|
||||
|
||||
## Key Source Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `frontend/src/simulation/AVRSimulator.ts` | AVR8 CPU emulator wrapper |
|
||||
| `frontend/src/simulation/PinManager.ts` | Maps Arduino pins to UI components |
|
||||
| `frontend/src/utils/hexParser.ts` | Intel HEX parser |
|
||||
| `frontend/src/components/simulator/SimulatorCanvas.tsx` | Canvas rendering |
|
||||
| `backend/app/services/arduino_cli.py` | arduino-cli wrapper |
|
||||
| `backend/app/api/routes/compile.py` | Compilation API endpoint |
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
# Getting Started
|
||||
|
||||
Velxio is an open-source Arduino emulator that runs entirely in your browser. Follow these steps to simulate your first Arduino sketch.
|
||||
|
||||
---
|
||||
|
||||
## Option 1: Use the Hosted Version
|
||||
|
||||
No installation needed — go to **[https://velxio.dev](https://velxio.dev)** and start coding immediately.
|
||||
|
||||
---
|
||||
|
||||
## Option 2: Self-Host with Docker
|
||||
|
||||
Run a single Docker command to start a fully local instance:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name velxio \
|
||||
-p 3080:80 \
|
||||
-v $(pwd)/data:/app/data \
|
||||
ghcr.io/davidmonterocrespo24/velxio:master
|
||||
```
|
||||
|
||||
Then open **http://localhost:3080** in your browser.
|
||||
|
||||
---
|
||||
|
||||
## Option 3: Manual Setup (Development)
|
||||
|
||||
**Prerequisites:** Node.js 18+, Python 3.12+, `arduino-cli`
|
||||
|
||||
### 1. Clone the repository
|
||||
|
||||
```bash
|
||||
git clone https://github.com/davidmonterocrespo24/velxio.git
|
||||
cd velxio
|
||||
```
|
||||
|
||||
### 2. Start the backend
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
python -m venv venv && source venv/bin/activate # Windows: venv\Scripts\activate
|
||||
pip install -r requirements.txt
|
||||
uvicorn app.main:app --reload --port 8001
|
||||
```
|
||||
|
||||
### 3. Start the frontend
|
||||
|
||||
```bash
|
||||
# In a new terminal:
|
||||
cd frontend
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open **http://localhost:5173**.
|
||||
|
||||
### 4. Set up arduino-cli (first time)
|
||||
|
||||
```bash
|
||||
arduino-cli core update-index
|
||||
arduino-cli core install arduino:avr
|
||||
|
||||
# For Raspberry Pi Pico support:
|
||||
arduino-cli config add board_manager.additional_urls \
|
||||
https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
|
||||
arduino-cli core install rp2040:rp2040
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Your First Simulation
|
||||
|
||||
1. **Open the editor** at [velxio.dev/editor](https://velxio.dev/editor) (or your local instance).
|
||||
2. **Select a board** from the toolbar (e.g., *Arduino Uno*).
|
||||
3. **Write Arduino code** in the Monaco editor, for example:
|
||||
|
||||
```cpp
|
||||
void setup() {
|
||||
pinMode(13, OUTPUT);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
digitalWrite(13, HIGH);
|
||||
delay(500);
|
||||
digitalWrite(13, LOW);
|
||||
delay(500);
|
||||
}
|
||||
```
|
||||
|
||||
4. **Click Compile** — the backend calls `arduino-cli` and returns a `.hex` file.
|
||||
5. **Click Run** — the AVR8 emulator executes the compiled program.
|
||||
6. **Add components** using the component picker (click the **+** button on the canvas).
|
||||
7. **Connect wires** by clicking a component pin and then another pin.
|
||||
|
||||
---
|
||||
|
||||
## Loading an Example Project
|
||||
|
||||
1. Click **Examples** in the navigation bar.
|
||||
2. Choose a project such as *Blink*, *Traffic Light*, or *LCD 20×4*.
|
||||
3. Click **Load** — the code and components are imported automatically.
|
||||
4. Click **Run** to start the simulation.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Problem | Solution |
|
||||
|---------|----------|
|
||||
| `arduino-cli: command not found` | Install `arduino-cli` and add it to your PATH. |
|
||||
| LED doesn't blink | Check the browser console for port listener errors; verify pin assignment in the component property dialog. |
|
||||
| Serial Monitor is empty | Ensure `Serial.begin()` is called inside `setup()` before any `Serial.print()`. |
|
||||
| Compilation errors | Check the compilation console at the bottom of the editor for full `arduino-cli` output. |
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
# Velxio — Introduction
|
||||
|
||||
**Velxio** is a fully local, open-source Arduino emulator that runs entirely in your browser.
|
||||
|
||||
Write Arduino C++ code, compile it with a real `arduino-cli` backend, and simulate it using true AVR8 / RP2040 CPU emulation — with 48+ interactive electronic components, all without installing any software on your machine.
|
||||
|
||||
---
|
||||
|
||||
## Why Velxio?
|
||||
|
||||
- **No installation required** — everything runs in the browser.
|
||||
- **Real emulation** — not a simplified model, but accurate AVR8 / RP2040 CPU emulation.
|
||||
- **Interactive components** — LEDs, buttons, potentiometers, displays, sensors, and more.
|
||||
- **Open-source** — inspect, modify, and self-host it yourself.
|
||||
|
||||
---
|
||||
|
||||
## Supported Boards
|
||||
|
||||
| Board | CPU | Emulator |
|
||||
|-------|-----|----------|
|
||||
| Arduino Uno | ATmega328p @ 16 MHz | avr8js |
|
||||
| Arduino Nano | ATmega328p @ 16 MHz | avr8js |
|
||||
| Arduino Mega | ATmega2560 @ 16 MHz | avr8js |
|
||||
| Raspberry Pi Pico | RP2040 @ 133 MHz | rp2040js |
|
||||
|
||||
---
|
||||
|
||||
## Quick Links
|
||||
|
||||
- [Getting Started](./getting-started.md)
|
||||
- [Emulator Architecture](./emulator.md)
|
||||
- [Components Reference](./components.md)
|
||||
- [Roadmap](./roadmap.md)
|
||||
- [Live Demo](https://velxio.dev)
|
||||
- [GitHub Repository](https://github.com/davidmonterocrespo24/velxio)
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
# Roadmap
|
||||
|
||||
This document lists the features that are implemented, in progress, and planned for future releases of Velxio.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Implemented
|
||||
|
||||
### Editor
|
||||
- Monaco Editor with C++ syntax highlighting, autocomplete, and minimap
|
||||
- Multi-file workspace — create, rename, delete, and switch between `.ino`, `.h`, `.cpp` files
|
||||
- Unsaved-changes indicator on file tabs
|
||||
- Resizable file explorer panel
|
||||
|
||||
### Compilation
|
||||
- Arduino compilation via `arduino-cli` backend
|
||||
- Multi-file sketch support
|
||||
- Compilation console with full output, warnings, and errors
|
||||
|
||||
### Simulation — AVR (Uno / Nano / Mega)
|
||||
- Real ATmega328p / ATmega2560 emulation at 16 MHz via avr8js
|
||||
- Full GPIO: PORTB (8–13), PORTC (A0–A5), PORTD (0–7)
|
||||
- Timer0/1/2 — `millis()`, `delay()`, `analogWrite()`
|
||||
- USART — Serial transmit and receive
|
||||
- ADC — `analogRead()` on A0–A5, voltage injection from potentiometers
|
||||
- SPI — ILI9341 TFT display
|
||||
- I2C (TWI) — virtual device bus
|
||||
|
||||
### Simulation — RP2040 (Raspberry Pi Pico)
|
||||
- Real RP2040 emulation at 133 MHz via rp2040js
|
||||
- UART0 serial output in Serial Monitor
|
||||
- 12-bit ADC on GPIO 26–29
|
||||
|
||||
### Components
|
||||
- 48+ wokwi-elements components
|
||||
- Component picker with search and category filters
|
||||
- Drag-and-drop repositioning
|
||||
- Component rotation (90° increments)
|
||||
- Property dialog (pin assignment, rotate, delete)
|
||||
|
||||
### Wire System
|
||||
- Click-to-connect wire creation
|
||||
- Orthogonal routing (no diagonal paths)
|
||||
- 8 signal-type color codes
|
||||
- Segment-based wire editing (drag segments)
|
||||
|
||||
### Serial Monitor
|
||||
- Live serial output
|
||||
- Auto baud-rate detection
|
||||
- Send data to Arduino RX
|
||||
|
||||
### Library Manager
|
||||
- Browse and install the full Arduino library index
|
||||
- Live search, installed-tab, version display
|
||||
|
||||
### Auth & Projects
|
||||
- Email/password and Google OAuth sign-in
|
||||
- Project save, update, and delete
|
||||
- Permanent project URLs (`/project/:id`)
|
||||
- User profile page (`/:username`) with public projects
|
||||
|
||||
### Example Projects
|
||||
- 8 built-in examples: Blink, Traffic Light, Button Control, Fade LED, Serial Hello World, RGB LED, Simon Says, LCD 20×4
|
||||
|
||||
### Deploy
|
||||
- Single-container Docker image (GHCR + Docker Hub)
|
||||
- GitHub Actions CI/CD pipeline
|
||||
|
||||
---
|
||||
|
||||
## 🔄 In Progress
|
||||
|
||||
- **Functional wire connections** — electrical signal routing and validation
|
||||
- **Wire connection error handling** — detect short circuits and invalid connections
|
||||
|
||||
---
|
||||
|
||||
## 🗓 Planned
|
||||
|
||||
### Near-Term
|
||||
- **Undo / redo** — for code edits and canvas changes
|
||||
- **Export / import projects** as `.zip` files
|
||||
- **More boards** — ESP32, Arduino Nano, Arduino Leonardo
|
||||
- **Breadboard** — place components on a virtual breadboard with automatic wire routing
|
||||
|
||||
### Mid-Term
|
||||
- **TypeDoc API documentation** — auto-generated from source code
|
||||
- **GitHub Pages docs site** — automatic deployment on push to `main`
|
||||
- **More sensor simulations** — HC-SR04 (ultrasonic), DHT22 (temperature/humidity), IR receiver
|
||||
- **EEPROM emulation** — persistent read/write across simulation restarts
|
||||
- **Oscilloscope component** — plot analog pin voltages over time
|
||||
|
||||
### Long-Term
|
||||
- **Multiplayer** — share and co-edit simulations in real time
|
||||
- **Embedded tutorial system** — step-by-step guided projects inside the editor
|
||||
- **Custom component SDK** — define new components with a JSON/TypeScript API
|
||||
- **Mobile / tablet support** — responsive layout for touch devices
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
Feature requests, bug reports, and pull requests are welcome at [github.com/davidmonterocrespo24/velxio](https://github.com/davidmonterocrespo24/velxio).
|
||||
|
||||
All contributors must sign a Contributor License Agreement (CLA); a CLA check runs automatically on pull requests.
|
||||
|
|
@ -16,6 +16,13 @@
|
|||
<priority>0.9</priority>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://velxio.dev/docs</loc>
|
||||
<lastmod>2026-03-11</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://velxio.dev/examples</loc>
|
||||
<lastmod>2026-03-06</lastmod>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { UserProfilePage } from './pages/UserProfilePage';
|
|||
import { ProjectPage } from './pages/ProjectPage';
|
||||
import { ProjectByIdPage } from './pages/ProjectByIdPage';
|
||||
import { AdminPage } from './pages/AdminPage';
|
||||
import { DocsPage } from './pages/DocsPage';
|
||||
import { useAuthStore } from './store/useAuthStore';
|
||||
import './App.css';
|
||||
|
||||
|
|
@ -28,6 +29,7 @@ function App() {
|
|||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/register" element={<RegisterPage />} />
|
||||
<Route path="/admin" element={<AdminPage />} />
|
||||
<Route path="/docs" element={<DocsPage />} />
|
||||
{/* Canonical project URL by ID */}
|
||||
<Route path="/project/:id" element={<ProjectByIdPage />} />
|
||||
{/* Legacy slug route — redirects to /project/:id */}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,441 @@
|
|||
/* ── CSS Variables (match LandingPage) ─────────────────── */
|
||||
:root {
|
||||
--accent: #007acc;
|
||||
--bg: #09090b;
|
||||
--bg-card: #0f0f12;
|
||||
--bg-alt: #07070a;
|
||||
--border: #18181f;
|
||||
--border-hi: #252530;
|
||||
--text: #d8d8e0;
|
||||
--text-muted: #72727e;
|
||||
--font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
--mono: 'Fira Code', 'Cascadia Code', 'Consolas', monospace;
|
||||
--radius: 3px;
|
||||
--sidebar-w: 240px;
|
||||
--nav-h: 52px;
|
||||
}
|
||||
|
||||
/* ── Page layout ────────────────────────────────────────── */
|
||||
.docs-page {
|
||||
min-height: 100vh;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
font-family: var(--font);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* ── Nav ─────────────────────────────────────────────────── */
|
||||
.docs-nav {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 0 24px;
|
||||
height: var(--nav-h);
|
||||
background: rgba(9, 9, 11, 0.92);
|
||||
backdrop-filter: blur(10px);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.docs-nav-brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: var(--text);
|
||||
text-decoration: none;
|
||||
font-family: var(--mono);
|
||||
}
|
||||
|
||||
.docs-nav-brand svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.docs-nav-divider {
|
||||
color: var(--text-muted);
|
||||
font-size: 18px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.docs-nav-section {
|
||||
font-size: 14px;
|
||||
color: var(--text-muted);
|
||||
font-family: var(--mono);
|
||||
}
|
||||
|
||||
.docs-nav-links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.docs-nav-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 5px 10px;
|
||||
color: var(--text-muted);
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
border-radius: var(--radius);
|
||||
transition: color 0.15s, background 0.15s;
|
||||
}
|
||||
|
||||
.docs-nav-link svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.docs-nav-link:hover {
|
||||
color: var(--text);
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.docs-nav-btn {
|
||||
padding: 5px 12px;
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border-hi);
|
||||
color: var(--text);
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
border-radius: var(--radius);
|
||||
transition: border-color 0.15s, background 0.15s;
|
||||
}
|
||||
|
||||
.docs-nav-btn:hover {
|
||||
border-color: #444;
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
.docs-sidebar-toggle {
|
||||
display: none;
|
||||
background: transparent;
|
||||
border: 1px solid var(--border-hi);
|
||||
color: var(--text-muted);
|
||||
cursor: pointer;
|
||||
padding: 5px 7px;
|
||||
border-radius: var(--radius);
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.docs-sidebar-toggle svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* ── Body layout ─────────────────────────────────────────── */
|
||||
.docs-body {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* ── Sidebar ─────────────────────────────────────────────── */
|
||||
.docs-sidebar {
|
||||
width: var(--sidebar-w);
|
||||
min-width: var(--sidebar-w);
|
||||
background: var(--bg-card);
|
||||
border-right: 1px solid var(--border);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 24px 0 24px;
|
||||
position: sticky;
|
||||
top: var(--nav-h);
|
||||
height: calc(100vh - var(--nav-h));
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.docs-sidebar-title {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
padding: 0 20px 12px;
|
||||
}
|
||||
|
||||
.docs-sidebar-nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.docs-sidebar-item {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
padding: 7px 12px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--text-muted);
|
||||
font-size: 13.5px;
|
||||
border-radius: var(--radius);
|
||||
cursor: pointer;
|
||||
transition: color 0.15s, background 0.15s;
|
||||
}
|
||||
|
||||
.docs-sidebar-item:hover {
|
||||
color: var(--text);
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.docs-sidebar-item--active {
|
||||
color: var(--accent);
|
||||
background: rgba(0, 122, 204, 0.12);
|
||||
}
|
||||
|
||||
.docs-sidebar-footer {
|
||||
margin-top: auto;
|
||||
padding: 16px 20px 0;
|
||||
}
|
||||
|
||||
.docs-sidebar-gh {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
color: var(--text-muted);
|
||||
text-decoration: none;
|
||||
font-size: 12.5px;
|
||||
transition: color 0.15s;
|
||||
}
|
||||
|
||||
.docs-sidebar-gh svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.docs-sidebar-gh:hover {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* ── Main content ─────────────────────────────────────────── */
|
||||
.docs-main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding: 48px 64px;
|
||||
max-width: 860px;
|
||||
}
|
||||
|
||||
/* ── Section typography ───────────────────────────────────── */
|
||||
.docs-section {
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.docs-label {
|
||||
font-family: var(--mono);
|
||||
font-size: 12px;
|
||||
color: var(--accent);
|
||||
letter-spacing: 0.04em;
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.docs-section h1 {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
margin: 0 0 20px;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.docs-section h2 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
margin: 36px 0 14px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.docs-section h3 {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: #d0d0e0;
|
||||
margin: 24px 0 10px;
|
||||
}
|
||||
|
||||
.docs-section p {
|
||||
color: var(--text);
|
||||
margin: 0 0 16px;
|
||||
}
|
||||
|
||||
.docs-section ul,
|
||||
.docs-section ol {
|
||||
margin: 0 0 16px;
|
||||
padding-left: 24px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.docs-section li {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.docs-section a {
|
||||
color: var(--accent);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.docs-section a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.docs-section code {
|
||||
font-family: var(--mono);
|
||||
font-size: 0.88em;
|
||||
background: rgba(255, 255, 255, 0.07);
|
||||
border: 1px solid var(--border-hi);
|
||||
border-radius: 3px;
|
||||
padding: 1px 5px;
|
||||
color: #c9d1d9;
|
||||
}
|
||||
|
||||
.docs-section pre {
|
||||
background: var(--bg-alt);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
padding: 18px 20px;
|
||||
overflow-x: auto;
|
||||
margin: 0 0 20px;
|
||||
}
|
||||
|
||||
.docs-section pre code {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0;
|
||||
font-size: 0.85rem;
|
||||
color: #c9d1d9;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
/* ── Tables ───────────────────────────────────────────────── */
|
||||
.docs-section table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 14px;
|
||||
margin: 0 0 24px;
|
||||
}
|
||||
|
||||
.docs-section th {
|
||||
background: var(--bg-card);
|
||||
color: var(--text-muted);
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
padding: 9px 14px;
|
||||
border: 1px solid var(--border);
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.docs-section td {
|
||||
padding: 9px 14px;
|
||||
border: 1px solid var(--border);
|
||||
color: var(--text);
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.docs-section tr:hover td {
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
}
|
||||
|
||||
/* ── Callout ─────────────────────────────────────────────── */
|
||||
.docs-callout {
|
||||
background: rgba(0, 122, 204, 0.08);
|
||||
border: 1px solid rgba(0, 122, 204, 0.25);
|
||||
border-radius: 6px;
|
||||
padding: 14px 18px;
|
||||
font-size: 14px;
|
||||
color: var(--text);
|
||||
margin: 24px 0;
|
||||
}
|
||||
|
||||
.docs-callout a {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
/* ── Wire dot ─────────────────────────────────────────────── */
|
||||
.wire-dot {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
margin-right: 6px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* ── Pagination ──────────────────────────────────────────── */
|
||||
.docs-pagination {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 56px;
|
||||
padding-top: 24px;
|
||||
border-top: 1px solid var(--border);
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.docs-pagination-btn {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border-hi);
|
||||
color: var(--text-muted);
|
||||
font-size: 13.5px;
|
||||
border-radius: var(--radius);
|
||||
padding: 9px 16px;
|
||||
cursor: pointer;
|
||||
transition: color 0.15s, border-color 0.15s, background 0.15s;
|
||||
}
|
||||
|
||||
.docs-pagination-btn:hover {
|
||||
color: var(--text);
|
||||
border-color: #444;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.docs-pagination-btn--next {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
/* ── Responsive ──────────────────────────────────────────── */
|
||||
@media (max-width: 768px) {
|
||||
.docs-sidebar {
|
||||
position: fixed;
|
||||
top: var(--nav-h);
|
||||
left: 0;
|
||||
height: calc(100vh - var(--nav-h));
|
||||
z-index: 200;
|
||||
transform: translateX(-100%);
|
||||
transition: transform 0.25s ease;
|
||||
box-shadow: 4px 0 20px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.docs-sidebar--open {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.docs-sidebar-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.docs-nav-links {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.docs-main {
|
||||
padding: 32px 20px;
|
||||
}
|
||||
|
||||
.docs-section h1 {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,562 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useAuthStore } from '../store/useAuthStore';
|
||||
import './DocsPage.css';
|
||||
|
||||
const GITHUB_URL = 'https://github.com/davidmonterocrespo24/velxio';
|
||||
|
||||
/* ── Icons ─────────────────────────────────────────────── */
|
||||
const IcoChip = () => (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
||||
<rect x="5" y="5" width="14" height="14" rx="2" />
|
||||
<rect x="9" y="9" width="6" height="6" />
|
||||
<path d="M9 1v4M15 1v4M9 19v4M15 19v4M1 9h4M1 15h4M19 9h4M19 15h4" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
const IcoGitHub = () => (
|
||||
<svg viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.3 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61-.546-1.385-1.335-1.755-1.335-1.755-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 21.795 24 17.295 24 12c0-6.63-5.37-12-12-12z" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
/* ── Doc sections ──────────────────────────────────────── */
|
||||
type SectionId = 'intro' | 'getting-started' | 'emulator' | 'components' | 'roadmap';
|
||||
|
||||
interface NavItem {
|
||||
id: SectionId;
|
||||
label: string;
|
||||
}
|
||||
|
||||
const NAV_ITEMS: NavItem[] = [
|
||||
{ id: 'intro', label: 'Introduction' },
|
||||
{ id: 'getting-started', label: 'Getting Started' },
|
||||
{ id: 'emulator', label: 'Emulator Architecture' },
|
||||
{ id: 'components', label: 'Components Reference' },
|
||||
{ id: 'roadmap', label: 'Roadmap' },
|
||||
];
|
||||
|
||||
/* ── Section content ───────────────────────────────────── */
|
||||
const IntroSection: React.FC = () => (
|
||||
<div className="docs-section">
|
||||
<span className="docs-label">// overview</span>
|
||||
<h1>Introduction</h1>
|
||||
<p>
|
||||
<strong>Velxio</strong> is a fully local, open-source Arduino emulator that runs entirely in your browser.
|
||||
Write Arduino C++ code, compile it with a real <code>arduino-cli</code> backend, and simulate it using
|
||||
true AVR8 / RP2040 CPU emulation — with 48+ interactive electronic components, all without installing
|
||||
any software on your machine.
|
||||
</p>
|
||||
|
||||
<h2>Why Velxio?</h2>
|
||||
<ul>
|
||||
<li><strong>No installation required</strong> — everything runs in the browser.</li>
|
||||
<li><strong>Real emulation</strong> — not a simplified model, but accurate AVR8 / RP2040 CPU emulation.</li>
|
||||
<li><strong>Interactive components</strong> — LEDs, buttons, potentiometers, displays, sensors, and more.</li>
|
||||
<li><strong>Open-source</strong> — inspect, modify, and self-host it yourself.</li>
|
||||
</ul>
|
||||
|
||||
<h2>Supported Boards</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Board</th><th>CPU</th><th>Emulator</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Arduino Uno</td><td>ATmega328p @ 16 MHz</td><td>avr8js</td></tr>
|
||||
<tr><td>Arduino Nano</td><td>ATmega328p @ 16 MHz</td><td>avr8js</td></tr>
|
||||
<tr><td>Arduino Mega</td><td>ATmega2560 @ 16 MHz</td><td>avr8js</td></tr>
|
||||
<tr><td>Raspberry Pi Pico</td><td>RP2040 @ 133 MHz</td><td>rp2040js</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div className="docs-callout">
|
||||
<strong>Live Demo:</strong>{' '}
|
||||
<a href="https://velxio.dev" target="_blank" rel="noopener noreferrer">velxio.dev</a>
|
||||
{' '}— no installation needed, open the editor and start simulating immediately.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const GettingStartedSection: React.FC = () => (
|
||||
<div className="docs-section">
|
||||
<span className="docs-label">// setup</span>
|
||||
<h1>Getting Started</h1>
|
||||
<p>Follow these steps to simulate your first Arduino sketch.</p>
|
||||
|
||||
<h2>Option 1: Use the Hosted Version</h2>
|
||||
<p>
|
||||
No installation needed — go to{' '}
|
||||
<a href="https://velxio.dev" target="_blank" rel="noopener noreferrer">https://velxio.dev</a>{' '}
|
||||
and start coding immediately.
|
||||
</p>
|
||||
|
||||
<h2>Option 2: Self-Host with Docker</h2>
|
||||
<p>Run a single Docker command to start a fully local instance:</p>
|
||||
<pre><code>{`docker run -d \\
|
||||
--name velxio \\
|
||||
-p 3080:80 \\
|
||||
-v $(pwd)/data:/app/data \\
|
||||
ghcr.io/davidmonterocrespo24/velxio:master`}</code></pre>
|
||||
<p>Then open <strong>http://localhost:3080</strong> in your browser.</p>
|
||||
|
||||
<h2>Option 3: Manual Setup (Development)</h2>
|
||||
<p><strong>Prerequisites:</strong> Node.js 18+, Python 3.12+, <code>arduino-cli</code></p>
|
||||
|
||||
<h3>1. Clone the repository</h3>
|
||||
<pre><code>{`git clone https://github.com/davidmonterocrespo24/velxio.git
|
||||
cd velxio`}</code></pre>
|
||||
|
||||
<h3>2. Start the backend</h3>
|
||||
<pre><code>{`cd backend
|
||||
python -m venv venv && source venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
uvicorn app.main:app --reload --port 8001`}</code></pre>
|
||||
|
||||
<h3>3. Start the frontend</h3>
|
||||
<pre><code>{`cd frontend
|
||||
npm install
|
||||
npm run dev`}</code></pre>
|
||||
<p>Open <strong>http://localhost:5173</strong>.</p>
|
||||
|
||||
<h3>4. Set up arduino-cli (first time)</h3>
|
||||
<pre><code>{`arduino-cli core update-index
|
||||
arduino-cli core install arduino:avr
|
||||
|
||||
# For Raspberry Pi Pico support:
|
||||
arduino-cli config add board_manager.additional_urls \\
|
||||
https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
|
||||
arduino-cli core install rp2040:rp2040`}</code></pre>
|
||||
|
||||
<h2>Your First Simulation</h2>
|
||||
<ol>
|
||||
<li><strong>Open the editor</strong> at <a href="https://velxio.dev/editor" target="_blank" rel="noopener noreferrer">velxio.dev/editor</a>.</li>
|
||||
<li><strong>Select a board</strong> from the toolbar (e.g., <em>Arduino Uno</em>).</li>
|
||||
<li><strong>Write Arduino code</strong> in the Monaco editor, for example:</li>
|
||||
</ol>
|
||||
<pre><code>{`void setup() {
|
||||
pinMode(13, OUTPUT);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
digitalWrite(13, HIGH);
|
||||
delay(500);
|
||||
digitalWrite(13, LOW);
|
||||
delay(500);
|
||||
}`}</code></pre>
|
||||
<ol start={4}>
|
||||
<li><strong>Click Compile</strong> — the backend calls <code>arduino-cli</code> and returns a <code>.hex</code> file.</li>
|
||||
<li><strong>Click Run</strong> — the AVR8 emulator executes the compiled program.</li>
|
||||
<li><strong>Add components</strong> using the component picker (click the <strong>+</strong> button on the canvas).</li>
|
||||
<li><strong>Connect wires</strong> by clicking a component pin and then another pin.</li>
|
||||
</ol>
|
||||
|
||||
<h2>Troubleshooting</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Problem</th><th>Solution</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>arduino-cli: command not found</code></td>
|
||||
<td>Install <code>arduino-cli</code> and add it to your PATH.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>LED doesn't blink</td>
|
||||
<td>Check the browser console for port listener errors; verify pin assignment in the component property dialog.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Serial Monitor is empty</td>
|
||||
<td>Ensure <code>Serial.begin()</code> is called inside <code>setup()</code> before any <code>Serial.print()</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Compilation errors</td>
|
||||
<td>Check the compilation console at the bottom of the editor for full <code>arduino-cli</code> output.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
|
||||
const EmulatorSection: React.FC = () => (
|
||||
<div className="docs-section">
|
||||
<span className="docs-label">// internals</span>
|
||||
<h1>Emulator Architecture</h1>
|
||||
<p>
|
||||
Velxio uses <strong>real CPU emulation</strong> rather than a simplified model.
|
||||
This document describes how each layer of the simulation works.
|
||||
</p>
|
||||
|
||||
<h2>High-Level Data Flow</h2>
|
||||
<pre><code>{`User Code (Monaco Editor)
|
||||
│
|
||||
▼
|
||||
Zustand Store (useEditorStore)
|
||||
│
|
||||
▼
|
||||
FastAPI Backend ──► arduino-cli ──► .hex / .uf2 file
|
||||
│
|
||||
▼
|
||||
AVRSimulator / RP2040Simulator
|
||||
│ loadHex()
|
||||
▼
|
||||
CPU execution loop (~60 FPS via requestAnimationFrame)
|
||||
│
|
||||
▼
|
||||
Port listeners (PORTB / PORTC / PORTD)
|
||||
│
|
||||
▼
|
||||
PinManager ──► Component state ──► React re-renders`}</code></pre>
|
||||
|
||||
<h2>AVR8 Emulation (Arduino Uno / Nano / Mega)</h2>
|
||||
<p>
|
||||
The AVR backend uses <a href="https://github.com/wokwi/avr8js" target="_blank" rel="noopener noreferrer">avr8js</a>,
|
||||
which implements a complete ATmega328p / ATmega2560 processor.
|
||||
</p>
|
||||
|
||||
<h3>Execution Loop</h3>
|
||||
<p>Each animation frame executes approximately 267,000 CPU cycles (16 MHz ÷ 60 FPS):</p>
|
||||
<pre><code>{`avrInstruction(cpu); // decode and execute one AVR instruction
|
||||
cpu.tick(); // advance peripheral timers and counters`}</code></pre>
|
||||
|
||||
<h3>Supported Peripherals</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Peripheral</th><th>Details</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>GPIO</td><td>PORTB (pins 8–13), PORTC (A0–A5), PORTD (pins 0–7)</td></tr>
|
||||
<tr><td>Timer0 / Timer1 / Timer2</td><td><code>millis()</code>, <code>delay()</code>, PWM via <code>analogWrite()</code></td></tr>
|
||||
<tr><td>USART</td><td>Full transmit and receive — powers the Serial Monitor</td></tr>
|
||||
<tr><td>ADC</td><td>10-bit, 5 V reference on pins A0–A5</td></tr>
|
||||
<tr><td>SPI</td><td>Hardware SPI (enables ILI9341, SD card, etc.)</td></tr>
|
||||
<tr><td>I2C (TWI)</td><td>Hardware I2C with virtual device bus</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>Pin Mapping</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Arduino Pin</th><th>AVR Port</th><th>Bit</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>0–7</td><td>PORTD</td><td>0–7</td></tr>
|
||||
<tr><td>8–13</td><td>PORTB</td><td>0–5</td></tr>
|
||||
<tr><td>A0–A5</td><td>PORTC</td><td>0–5</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>RP2040 Emulation (Raspberry Pi Pico)</h2>
|
||||
<p>
|
||||
The RP2040 backend uses <a href="https://github.com/wokwi/rp2040js" target="_blank" rel="noopener noreferrer">rp2040js</a>.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Real RP2040 emulation at 133 MHz</li>
|
||||
<li>UART0 serial output displayed in the Serial Monitor</li>
|
||||
<li>12-bit ADC on GPIO 26–29 (A0–A3) with 3.3 V reference</li>
|
||||
</ul>
|
||||
|
||||
<h2>HEX File Format</h2>
|
||||
<p>Arduino compilation produces <strong>Intel HEX</strong> format. The parser in <code>hexParser.ts</code>:</p>
|
||||
<ol>
|
||||
<li>Reads lines starting with <code>:</code></li>
|
||||
<li>Extracts the address, record type, and data bytes</li>
|
||||
<li>Returns a <code>Uint8Array</code> of program bytes</li>
|
||||
<li><code>AVRSimulator</code> converts this to a <code>Uint16Array</code> (16-bit words, little-endian)</li>
|
||||
</ol>
|
||||
|
||||
<h2>Key Source Files</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>File</th><th>Purpose</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td><code>frontend/src/simulation/AVRSimulator.ts</code></td><td>AVR8 CPU emulator wrapper</td></tr>
|
||||
<tr><td><code>frontend/src/simulation/PinManager.ts</code></td><td>Maps Arduino pins to UI components</td></tr>
|
||||
<tr><td><code>frontend/src/utils/hexParser.ts</code></td><td>Intel HEX parser</td></tr>
|
||||
<tr><td><code>frontend/src/components/simulator/SimulatorCanvas.tsx</code></td><td>Canvas rendering</td></tr>
|
||||
<tr><td><code>backend/app/services/arduino_cli.py</code></td><td>arduino-cli wrapper</td></tr>
|
||||
<tr><td><code>backend/app/api/routes/compile.py</code></td><td>Compilation API endpoint</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
|
||||
const ComponentsSection: React.FC = () => (
|
||||
<div className="docs-section">
|
||||
<span className="docs-label">// reference</span>
|
||||
<h1>Components Reference</h1>
|
||||
<p>
|
||||
Velxio ships with <strong>48+ interactive electronic components</strong> powered by{' '}
|
||||
<a href="https://github.com/wokwi/wokwi-elements" target="_blank" rel="noopener noreferrer">wokwi-elements</a>.
|
||||
All components can be placed on the simulation canvas, connected with wires, and interact with your Arduino sketch in real time.
|
||||
</p>
|
||||
|
||||
<h2>Adding Components</h2>
|
||||
<ol>
|
||||
<li>Click the <strong>+</strong> button on the simulation canvas.</li>
|
||||
<li>Use <strong>search</strong> or browse by <strong>category</strong> in the component picker.</li>
|
||||
<li>Click a component to place it on the canvas.</li>
|
||||
<li><strong>Drag</strong> to reposition; click to open the <strong>Property Dialog</strong>.</li>
|
||||
</ol>
|
||||
|
||||
<h2>Connecting Components</h2>
|
||||
<ol>
|
||||
<li>Click a <strong>pin</strong> on any component — a wire starts from that pin.</li>
|
||||
<li>Click a <strong>destination pin</strong> to complete the connection.</li>
|
||||
<li>Wires are <strong>color-coded</strong> by signal type:</li>
|
||||
</ol>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Color</th><th>Signal Type</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td><span className="wire-dot" style={{ background: '#ef4444' }} /> Red</td><td>VCC (power)</td></tr>
|
||||
<tr><td><span className="wire-dot" style={{ background: '#374151' }} /> Black</td><td>GND (ground)</td></tr>
|
||||
<tr><td><span className="wire-dot" style={{ background: '#3b82f6' }} /> Blue</td><td>Analog</td></tr>
|
||||
<tr><td><span className="wire-dot" style={{ background: '#22c55e' }} /> Green</td><td>Digital</td></tr>
|
||||
<tr><td><span className="wire-dot" style={{ background: '#a855f7' }} /> Purple</td><td>PWM</td></tr>
|
||||
<tr><td><span className="wire-dot" style={{ background: '#eab308' }} /> Gold</td><td>I2C (SDA/SCL)</td></tr>
|
||||
<tr><td><span className="wire-dot" style={{ background: '#f97316' }} /> Orange</td><td>SPI (MOSI/MISO/SCK)</td></tr>
|
||||
<tr><td><span className="wire-dot" style={{ background: '#06b6d4' }} /> Cyan</td><td>USART (TX/RX)</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>Component Categories</h2>
|
||||
|
||||
<h3>Output</h3>
|
||||
<table>
|
||||
<thead><tr><th>Component</th><th>Description</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>LED</td><td>Single LED with configurable color</td></tr>
|
||||
<tr><td>RGB LED</td><td>Three-color LED (red, green, blue channels)</td></tr>
|
||||
<tr><td>7-Segment Display</td><td>Single digit numeric display</td></tr>
|
||||
<tr><td>LCD 16×2</td><td>2-line character LCD (I2C or parallel)</td></tr>
|
||||
<tr><td>LCD 20×4</td><td>4-line character LCD</td></tr>
|
||||
<tr><td>ILI9341 TFT</td><td>240×320 color TFT display (SPI)</td></tr>
|
||||
<tr><td>Buzzer</td><td>Passive piezo buzzer</td></tr>
|
||||
<tr><td>NeoPixel</td><td>Individually addressable RGB LED strip</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>Input</h3>
|
||||
<table>
|
||||
<thead><tr><th>Component</th><th>Description</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Push Button</td><td>Momentary push button</td></tr>
|
||||
<tr><td>Slide Switch</td><td>SPDT slide switch</td></tr>
|
||||
<tr><td>Potentiometer</td><td>Analog voltage divider (ADC input)</td></tr>
|
||||
<tr><td>Rotary Encoder</td><td>Incremental rotary encoder</td></tr>
|
||||
<tr><td>Keypad 4×4</td><td>16-button matrix keypad</td></tr>
|
||||
<tr><td>Joystick</td><td>Dual-axis analog joystick</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>Sensors</h3>
|
||||
<table>
|
||||
<thead><tr><th>Component</th><th>Description</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>HC-SR04</td><td>Ultrasonic distance sensor</td></tr>
|
||||
<tr><td>DHT22</td><td>Temperature and humidity sensor</td></tr>
|
||||
<tr><td>PIR Motion</td><td>Passive infrared motion sensor</td></tr>
|
||||
<tr><td>Photoresistor</td><td>Light-dependent resistor (LDR)</td></tr>
|
||||
<tr><td>IR Receiver</td><td>38 kHz infrared receiver</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>Passive Components</h3>
|
||||
<table>
|
||||
<thead><tr><th>Component</th><th>Description</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Resistor</td><td>Standard resistor (configurable value)</td></tr>
|
||||
<tr><td>Capacitor</td><td>Electrolytic capacitor</td></tr>
|
||||
<tr><td>Inductor</td><td>Coil inductor</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>Component Properties</h2>
|
||||
<p>Each component has a <strong>Property Dialog</strong> accessible by clicking it on the canvas:</p>
|
||||
<table>
|
||||
<thead><tr><th>Property</th><th>Description</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Arduino Pin</td><td>The digital or analog pin this component is connected to</td></tr>
|
||||
<tr><td>Color</td><td>Visual color (LEDs, wires)</td></tr>
|
||||
<tr><td>Value</td><td>Component value (e.g., resistance in Ω)</td></tr>
|
||||
<tr><td>Rotation</td><td>Rotate in 90° increments</td></tr>
|
||||
<tr><td>Delete</td><td>Remove the component from the canvas</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
|
||||
const RoadmapSection: React.FC = () => (
|
||||
<div className="docs-section">
|
||||
<span className="docs-label">// future</span>
|
||||
<h1>Roadmap</h1>
|
||||
<p>Features that are implemented, in progress, and planned for future releases of Velxio.</p>
|
||||
|
||||
<h2>✅ Implemented</h2>
|
||||
<ul>
|
||||
<li>Monaco Editor with C++ syntax highlighting, autocomplete, and minimap</li>
|
||||
<li>Multi-file workspace — create, rename, delete, and switch between files</li>
|
||||
<li>Arduino compilation via <code>arduino-cli</code> (multi-file sketch support)</li>
|
||||
<li>Real ATmega328p / ATmega2560 emulation at 16 MHz via avr8js</li>
|
||||
<li>Full GPIO, Timers, USART, ADC, SPI, I2C support</li>
|
||||
<li>Real RP2040 emulation at 133 MHz via rp2040js</li>
|
||||
<li>48+ wokwi-elements components with component picker</li>
|
||||
<li>Wire creation, orthogonal routing, and segment-based editing</li>
|
||||
<li>Serial Monitor with auto baud-rate detection and send support</li>
|
||||
<li>Library Manager (browse and install Arduino libraries)</li>
|
||||
<li>Email/password and Google OAuth authentication</li>
|
||||
<li>Project save, update, delete with permanent URLs</li>
|
||||
<li>8 built-in example projects</li>
|
||||
<li>Single-container Docker image published to GHCR + Docker Hub</li>
|
||||
</ul>
|
||||
|
||||
<h2>🔄 In Progress</h2>
|
||||
<ul>
|
||||
<li>Functional wire connections — electrical signal routing and validation</li>
|
||||
<li>Wire connection error handling — detect short circuits and invalid connections</li>
|
||||
</ul>
|
||||
|
||||
<h2>🗓 Planned — Near-Term</h2>
|
||||
<ul>
|
||||
<li>Undo / redo for code edits and canvas changes</li>
|
||||
<li>Export / import projects as <code>.zip</code> files</li>
|
||||
<li>More boards — ESP32, Arduino Leonardo</li>
|
||||
<li>Breadboard — place components with automatic wire routing</li>
|
||||
</ul>
|
||||
|
||||
<h2>🗓 Planned — Mid-Term</h2>
|
||||
<ul>
|
||||
<li>TypeDoc API documentation — auto-generated from source code</li>
|
||||
<li>GitHub Pages docs site — automatic deployment on push to <code>main</code></li>
|
||||
<li>More sensor simulations — HC-SR04, DHT22, IR receiver</li>
|
||||
<li>EEPROM emulation — persistent read/write across simulation restarts</li>
|
||||
<li>Oscilloscope component — plot analog pin voltages over time</li>
|
||||
</ul>
|
||||
|
||||
<h2>🗓 Planned — Long-Term</h2>
|
||||
<ul>
|
||||
<li>Multiplayer — share and co-edit simulations in real time</li>
|
||||
<li>Embedded tutorial system — step-by-step guided projects inside the editor</li>
|
||||
<li>Custom component SDK — define new components with a JSON/TypeScript API</li>
|
||||
<li>Mobile / tablet support — responsive layout for touch devices</li>
|
||||
</ul>
|
||||
|
||||
<div className="docs-callout">
|
||||
<strong>Want to contribute?</strong>{' '}
|
||||
Feature requests, bug reports, and pull requests are welcome at{' '}
|
||||
<a href={GITHUB_URL} target="_blank" rel="noopener noreferrer">github.com/davidmonterocrespo24/velxio</a>.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const SECTION_MAP: Record<SectionId, React.FC> = {
|
||||
intro: IntroSection,
|
||||
'getting-started': GettingStartedSection,
|
||||
emulator: EmulatorSection,
|
||||
components: ComponentsSection,
|
||||
roadmap: RoadmapSection,
|
||||
};
|
||||
|
||||
/* ── Page ─────────────────────────────────────────────── */
|
||||
export const DocsPage: React.FC = () => {
|
||||
const [activeSection, setActiveSection] = useState<SectionId>('intro');
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
const user = useAuthStore((s) => s.user);
|
||||
|
||||
const ActiveContent = SECTION_MAP[activeSection];
|
||||
|
||||
return (
|
||||
<div className="docs-page">
|
||||
{/* Nav */}
|
||||
<nav className="docs-nav">
|
||||
<Link to="/" className="docs-nav-brand">
|
||||
<IcoChip />
|
||||
<span>Velxio</span>
|
||||
</Link>
|
||||
<span className="docs-nav-divider">/</span>
|
||||
<span className="docs-nav-section">Docs</span>
|
||||
<div className="docs-nav-links">
|
||||
<Link to="/examples" className="docs-nav-link">Examples</Link>
|
||||
<Link to="/editor" className="docs-nav-link">Editor</Link>
|
||||
<a href={GITHUB_URL} target="_blank" rel="noopener noreferrer" className="docs-nav-link">
|
||||
<IcoGitHub /> GitHub
|
||||
</a>
|
||||
{user ? (
|
||||
<Link to={`/${user.username}`} className="docs-nav-btn">My Projects</Link>
|
||||
) : (
|
||||
<Link to="/login" className="docs-nav-btn">Sign in</Link>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
className="docs-sidebar-toggle"
|
||||
onClick={() => setSidebarOpen((v) => !v)}
|
||||
aria-label="Toggle sidebar"
|
||||
>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
||||
<line x1="3" y1="6" x2="21" y2="6" />
|
||||
<line x1="3" y1="12" x2="21" y2="12" />
|
||||
<line x1="3" y1="18" x2="21" y2="18" />
|
||||
</svg>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<div className="docs-body">
|
||||
{/* Sidebar */}
|
||||
<aside className={`docs-sidebar${sidebarOpen ? ' docs-sidebar--open' : ''}`}>
|
||||
<div className="docs-sidebar-title">Documentation</div>
|
||||
<nav className="docs-sidebar-nav">
|
||||
{NAV_ITEMS.map((item) => (
|
||||
<button
|
||||
key={item.id}
|
||||
className={`docs-sidebar-item${activeSection === item.id ? ' docs-sidebar-item--active' : ''}`}
|
||||
onClick={() => { setActiveSection(item.id); setSidebarOpen(false); }}
|
||||
>
|
||||
{item.label}
|
||||
</button>
|
||||
))}
|
||||
</nav>
|
||||
<div className="docs-sidebar-footer">
|
||||
<a href={GITHUB_URL} target="_blank" rel="noopener noreferrer" className="docs-sidebar-gh">
|
||||
<IcoGitHub /> View on GitHub
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
{/* Main content */}
|
||||
<main className="docs-main">
|
||||
<ActiveContent />
|
||||
|
||||
{/* Prev / Next navigation */}
|
||||
<div className="docs-pagination">
|
||||
{NAV_ITEMS.findIndex((i) => i.id === activeSection) > 0 && (
|
||||
<button
|
||||
className="docs-pagination-btn docs-pagination-btn--prev"
|
||||
onClick={() => {
|
||||
const idx = NAV_ITEMS.findIndex((i) => i.id === activeSection);
|
||||
setActiveSection(NAV_ITEMS[idx - 1].id);
|
||||
window.scrollTo(0, 0);
|
||||
}}
|
||||
>
|
||||
← {NAV_ITEMS[NAV_ITEMS.findIndex((i) => i.id === activeSection) - 1].label}
|
||||
</button>
|
||||
)}
|
||||
{NAV_ITEMS.findIndex((i) => i.id === activeSection) < NAV_ITEMS.length - 1 && (
|
||||
<button
|
||||
className="docs-pagination-btn docs-pagination-btn--next"
|
||||
onClick={() => {
|
||||
const idx = NAV_ITEMS.findIndex((i) => i.id === activeSection);
|
||||
setActiveSection(NAV_ITEMS[idx + 1].id);
|
||||
window.scrollTo(0, 0);
|
||||
}}
|
||||
>
|
||||
{NAV_ITEMS[NAV_ITEMS.findIndex((i) => i.id === activeSection) + 1].label} →
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Loading…
Reference in New Issue