diff --git a/README.md b/README.md
index f9993b7..fb3846d 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,14 @@
Local Arduino emulator with code editor and visual simulator.
+## Support This Project
+
+If you find this project helpful, please consider giving it a star! Your support helps the project grow and motivates continued development.
+
+[](https://github.com/yourusername/wokwi_clon/stargazers)
+
+Every star counts and helps make this project better!
+
## Features
- ✅ Code editor with syntax highlighting (Monaco Editor)
@@ -16,11 +24,11 @@ Local Arduino emulator with code editor and visual simulator.
## Screenshots
-
+
*Arduino emulator with Monaco code editor and visual simulator with wokwi-elements*
-
+
*Interactive component properties dialog and segment-based wire editing*
diff --git a/frontend/src/App.css b/frontend/src/App.css
index 4dfe18f..96736bf 100644
--- a/frontend/src/App.css
+++ b/frontend/src/App.css
@@ -22,6 +22,23 @@ body {
border-bottom: 2px solid #007acc;
}
+.header-content {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.header-title h1 {
+ font-size: 24px;
+ margin-bottom: 5px;
+ color: #007acc;
+}
+
+.header-title p {
+ font-size: 14px;
+ color: #aaa;
+}
+
.app-header h1 {
font-size: 24px;
margin-bottom: 5px;
@@ -33,6 +50,26 @@ body {
color: #aaa;
}
+.examples-link {
+ padding: 10px 20px;
+ background-color: #007acc;
+ color: #fff;
+ text-decoration: none;
+ border-radius: 6px;
+ font-size: 14px;
+ font-weight: 500;
+ transition: all 0.2s;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.examples-link:hover {
+ background-color: #005a9e;
+ transform: translateY(-2px);
+ box-shadow: 0 4px 12px rgba(0, 122, 204, 0.3);
+}
+
.app-container {
flex: 1;
display: flex;
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index a5d541f..31ca039 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,27 +1,16 @@
-import { CodeEditor } from './components/editor/CodeEditor';
-import { EditorToolbar } from './components/editor/EditorToolbar';
-import { SimulatorCanvas } from './components/simulator/SimulatorCanvas';
+import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
+import { EditorPage } from './pages/EditorPage';
+import { ExamplesPage } from './pages/ExamplesPage';
import './App.css';
function App() {
return (
-
+
+
+ } />
+ } />
+
+
);
}
diff --git a/frontend/src/components/examples/ExamplesGallery.css b/frontend/src/components/examples/ExamplesGallery.css
new file mode 100644
index 0000000..316780b
--- /dev/null
+++ b/frontend/src/components/examples/ExamplesGallery.css
@@ -0,0 +1,241 @@
+/**
+ * Examples Gallery Styles
+ */
+
+.examples-gallery {
+ min-height: 100vh;
+ background-color: #1e1e1e;
+ color: #fff;
+ padding: 40px 20px;
+}
+
+.examples-nav {
+ max-width: 1200px;
+ margin: 0 auto 20px auto;
+}
+
+.back-link {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ padding: 8px 16px;
+ background-color: #2d2d2d;
+ color: #fff;
+ text-decoration: none;
+ border-radius: 6px;
+ border: 1px solid #444;
+ font-size: 14px;
+ transition: all 0.2s;
+}
+
+.back-link:hover {
+ background-color: #3d3d3d;
+ border-color: #007acc;
+ color: #007acc;
+}
+
+.examples-header {
+ text-align: center;
+ margin-bottom: 40px;
+}
+
+.examples-header h1 {
+ font-size: 48px;
+ margin: 0 0 10px 0;
+ font-weight: 300;
+}
+
+.examples-header p {
+ font-size: 20px;
+ color: #aaa;
+ margin: 0;
+}
+
+/* Filters */
+.examples-filters {
+ max-width: 1200px;
+ margin: 0 auto 40px auto;
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.filter-group {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+}
+
+.filter-group label {
+ font-size: 14px;
+ color: #aaa;
+ min-width: 80px;
+}
+
+.filter-buttons {
+ display: flex;
+ gap: 10px;
+ flex-wrap: wrap;
+}
+
+.filter-button {
+ padding: 8px 16px;
+ border: 1px solid #444;
+ background-color: #2d2d2d;
+ color: #fff;
+ border-radius: 6px;
+ cursor: pointer;
+ font-size: 14px;
+ transition: all 0.2s;
+}
+
+.filter-button:hover {
+ background-color: #3d3d3d;
+ border-color: #555;
+}
+
+.filter-button.active {
+ background-color: #007acc;
+ border-color: #007acc;
+ color: #fff;
+}
+
+/* Examples Grid */
+.examples-grid {
+ max-width: 1200px;
+ margin: 0 auto;
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+ gap: 24px;
+}
+
+.example-card {
+ background-color: #2d2d2d;
+ border: 1px solid #444;
+ border-radius: 8px;
+ overflow: hidden;
+ cursor: pointer;
+ transition: all 0.3s;
+ display: flex;
+ flex-direction: column;
+}
+
+.example-card:hover {
+ transform: translateY(-4px);
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
+ border-color: #007acc;
+}
+
+.example-thumbnail {
+ width: 100%;
+ height: 200px;
+ background-color: #1e1e1e;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ overflow: hidden;
+}
+
+.example-thumbnail img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+
+.example-placeholder {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 10px;
+ width: 100%;
+ height: 100%;
+}
+
+.example-icon {
+ font-size: 64px;
+ opacity: 0.5;
+}
+
+.example-components-count {
+ font-size: 12px;
+ color: #888;
+}
+
+.example-info {
+ padding: 16px;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ flex: 1;
+}
+
+.example-title {
+ font-size: 18px;
+ font-weight: 600;
+ margin: 0;
+ color: #fff;
+}
+
+.example-description {
+ font-size: 14px;
+ color: #aaa;
+ margin: 0;
+ line-height: 1.5;
+ flex: 1;
+}
+
+.example-meta {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ margin-top: auto;
+}
+
+.example-difficulty {
+ padding: 4px 10px;
+ border-radius: 12px;
+ font-size: 11px;
+ font-weight: 600;
+ text-transform: uppercase;
+ color: #1e1e1e;
+}
+
+.example-category {
+ font-size: 12px;
+ color: #888;
+ text-transform: capitalize;
+}
+
+/* Empty State */
+.examples-empty {
+ max-width: 1200px;
+ margin: 60px auto;
+ text-align: center;
+ color: #888;
+ font-size: 16px;
+}
+
+/* Responsive */
+@media (max-width: 768px) {
+ .examples-header h1 {
+ font-size: 32px;
+ }
+
+ .examples-header p {
+ font-size: 16px;
+ }
+
+ .examples-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .filter-group {
+ flex-direction: column;
+ align-items: flex-start;
+ }
+
+ .filter-group label {
+ min-width: auto;
+ }
+}
diff --git a/frontend/src/components/examples/ExamplesGallery.tsx b/frontend/src/components/examples/ExamplesGallery.tsx
new file mode 100644
index 0000000..37922c7
--- /dev/null
+++ b/frontend/src/components/examples/ExamplesGallery.tsx
@@ -0,0 +1,167 @@
+/**
+ * Examples Gallery Component
+ *
+ * Displays a gallery of example Arduino projects that users can load and run
+ */
+
+import React, { useState } from 'react';
+import { Link } from 'react-router-dom';
+import { exampleProjects, getCategories, type ExampleProject } from '../../data/examples';
+import './ExamplesGallery.css';
+
+interface ExamplesGalleryProps {
+ onLoadExample: (example: ExampleProject) => void;
+}
+
+export const ExamplesGallery: React.FC = ({ onLoadExample }) => {
+ const [selectedCategory, setSelectedCategory] = useState(
+ 'all'
+ );
+ const [selectedDifficulty, setSelectedDifficulty] = useState<
+ ExampleProject['difficulty'] | 'all'
+ >('all');
+
+ const categories = getCategories();
+
+ // Filter examples based on selected category and difficulty
+ const filteredExamples = exampleProjects.filter((example) => {
+ const categoryMatch = selectedCategory === 'all' || example.category === selectedCategory;
+ const difficultyMatch =
+ selectedDifficulty === 'all' || example.difficulty === selectedDifficulty;
+ return categoryMatch && difficultyMatch;
+ });
+
+ const getCategoryIcon = (category: ExampleProject['category']): string => {
+ const icons: Record = {
+ basics: '💡',
+ sensors: '📡',
+ displays: '📺',
+ communication: '📶',
+ games: '🎮',
+ robotics: '🤖',
+ };
+ return icons[category];
+ };
+
+ const getDifficultyColor = (difficulty: ExampleProject['difficulty']): string => {
+ const colors: Record = {
+ beginner: '#4ade80',
+ intermediate: '#fbbf24',
+ advanced: '#f87171',
+ };
+ return colors[difficulty];
+ };
+
+ return (
+
+
+
+ ← Back to Editor
+
+
+
+
Featured Projects
+
Explore and run example Arduino projects
+
+
+ {/* Filters */}
+
+
+
+
+
+ {categories.map((category) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Examples Grid */}
+
+ {filteredExamples.map((example) => (
+
onLoadExample(example)}
+ >
+
+ {example.thumbnail ? (
+

+ ) : (
+
+ {getCategoryIcon(example.category)}
+
+ {example.components.length} component{example.components.length !== 1 ? 's' : ''}
+
+
+ )}
+
+
+
{example.title}
+
{example.description}
+
+
+ {example.difficulty}
+
+
+ {getCategoryIcon(example.category)} {example.category}
+
+
+
+
+ ))}
+
+
+ {filteredExamples.length === 0 && (
+
+
No examples found with the selected filters
+
+ )}
+
+ );
+};
diff --git a/frontend/src/data/examples.ts b/frontend/src/data/examples.ts
new file mode 100644
index 0000000..9de1c98
--- /dev/null
+++ b/frontend/src/data/examples.ts
@@ -0,0 +1,611 @@
+/**
+ * Arduino Example Projects
+ *
+ * Collection of example projects that users can load and run
+ */
+
+export interface ExampleProject {
+ id: string;
+ title: string;
+ description: string;
+ category: 'basics' | 'sensors' | 'displays' | 'communication' | 'games' | 'robotics';
+ difficulty: 'beginner' | 'intermediate' | 'advanced';
+ code: string;
+ components: Array<{
+ type: string;
+ id: string;
+ x: number;
+ y: number;
+ properties: Record;
+ }>;
+ wires: Array<{
+ id: string;
+ start: { componentId: string; pinName: string };
+ end: { componentId: string; pinName: string };
+ color: string;
+ }>;
+ thumbnail?: string;
+}
+
+export const exampleProjects: ExampleProject[] = [
+ {
+ id: 'blink-led',
+ title: 'Blink LED',
+ description: 'Classic Arduino blink example - toggle an LED on and off',
+ category: 'basics',
+ difficulty: 'beginner',
+ code: `// Blink LED Example
+// Toggles the built-in LED on pin 13
+
+void setup() {
+ pinMode(13, OUTPUT);
+}
+
+void loop() {
+ digitalWrite(13, HIGH);
+ delay(1000);
+ digitalWrite(13, LOW);
+ delay(1000);
+}`,
+ components: [
+ {
+ type: 'wokwi-arduino-uno',
+ id: 'arduino-uno',
+ x: 100,
+ y: 100,
+ properties: {},
+ },
+ ],
+ wires: [],
+ },
+ {
+ id: 'traffic-light',
+ title: 'Traffic Light',
+ description: 'Simulate a traffic light with red, yellow, and green LEDs',
+ category: 'basics',
+ difficulty: 'beginner',
+ code: `// Traffic Light Simulator
+// Red -> Yellow -> Green -> Yellow -> Red
+
+const int RED_PIN = 13;
+const int YELLOW_PIN = 12;
+const int GREEN_PIN = 11;
+
+void setup() {
+ pinMode(RED_PIN, OUTPUT);
+ pinMode(YELLOW_PIN, OUTPUT);
+ pinMode(GREEN_PIN, OUTPUT);
+}
+
+void loop() {
+ // Red light
+ digitalWrite(RED_PIN, HIGH);
+ delay(3000);
+ digitalWrite(RED_PIN, LOW);
+
+ // Yellow light
+ digitalWrite(YELLOW_PIN, HIGH);
+ delay(1000);
+ digitalWrite(YELLOW_PIN, LOW);
+
+ // Green light
+ digitalWrite(GREEN_PIN, HIGH);
+ delay(3000);
+ digitalWrite(GREEN_PIN, LOW);
+
+ // Yellow light again
+ digitalWrite(YELLOW_PIN, HIGH);
+ delay(1000);
+ digitalWrite(YELLOW_PIN, LOW);
+}`,
+ components: [
+ {
+ type: 'wokwi-arduino-uno',
+ id: 'arduino-uno',
+ x: 100,
+ y: 100,
+ properties: {},
+ },
+ {
+ type: 'wokwi-led',
+ id: 'led-red',
+ x: 400,
+ y: 100,
+ properties: { color: 'red', pin: 13 },
+ },
+ {
+ type: 'wokwi-led',
+ id: 'led-yellow',
+ x: 400,
+ y: 200,
+ properties: { color: 'yellow', pin: 12 },
+ },
+ {
+ type: 'wokwi-led',
+ id: 'led-green',
+ x: 400,
+ y: 300,
+ properties: { color: 'green', pin: 11 },
+ },
+ ],
+ wires: [
+ {
+ id: 'wire-red',
+ start: { componentId: 'arduino-uno', pinName: '13' },
+ end: { componentId: 'led-red', pinName: 'A' },
+ color: '#ff0000',
+ },
+ {
+ id: 'wire-yellow',
+ start: { componentId: 'arduino-uno', pinName: '12' },
+ end: { componentId: 'led-yellow', pinName: 'A' },
+ color: '#ffaa00',
+ },
+ {
+ id: 'wire-green',
+ start: { componentId: 'arduino-uno', pinName: '11' },
+ end: { componentId: 'led-green', pinName: 'A' },
+ color: '#00ff00',
+ },
+ ],
+ },
+ {
+ id: 'button-led',
+ title: 'Button Control',
+ description: 'Control an LED with a pushbutton',
+ category: 'basics',
+ difficulty: 'beginner',
+ code: `// Button LED Control
+// Press button to turn LED on
+
+const int BUTTON_PIN = 2;
+const int LED_PIN = 13;
+
+void setup() {
+ pinMode(BUTTON_PIN, INPUT_PULLUP);
+ pinMode(LED_PIN, OUTPUT);
+}
+
+void loop() {
+ int buttonState = digitalRead(BUTTON_PIN);
+
+ if (buttonState == LOW) {
+ digitalWrite(LED_PIN, HIGH);
+ } else {
+ digitalWrite(LED_PIN, LOW);
+ }
+}`,
+ components: [
+ {
+ type: 'wokwi-arduino-uno',
+ id: 'arduino-uno',
+ x: 100,
+ y: 100,
+ properties: {},
+ },
+ {
+ type: 'wokwi-pushbutton',
+ id: 'button-1',
+ x: 400,
+ y: 100,
+ properties: {},
+ },
+ {
+ type: 'wokwi-led',
+ id: 'led-1',
+ x: 400,
+ y: 250,
+ properties: { color: 'red', pin: 13 },
+ },
+ ],
+ wires: [
+ {
+ id: 'wire-button',
+ start: { componentId: 'arduino-uno', pinName: '2' },
+ end: { componentId: 'button-1', pinName: '1.L' },
+ color: '#00aaff',
+ },
+ {
+ id: 'wire-led',
+ start: { componentId: 'arduino-uno', pinName: '13' },
+ end: { componentId: 'led-1', pinName: 'A' },
+ color: '#ff0000',
+ },
+ ],
+ },
+ {
+ id: 'fade-led',
+ title: 'Fade LED',
+ description: 'Smoothly fade an LED using PWM',
+ category: 'basics',
+ difficulty: 'beginner',
+ code: `// Fade LED with PWM
+// Smoothly fade LED brightness
+
+const int LED_PIN = 9; // PWM pin
+
+int brightness = 0;
+int fadeAmount = 5;
+
+void setup() {
+ pinMode(LED_PIN, OUTPUT);
+}
+
+void loop() {
+ analogWrite(LED_PIN, brightness);
+
+ brightness += fadeAmount;
+
+ if (brightness <= 0 || brightness >= 255) {
+ fadeAmount = -fadeAmount;
+ }
+
+ delay(30);
+}`,
+ components: [
+ {
+ type: 'wokwi-arduino-uno',
+ id: 'arduino-uno',
+ x: 100,
+ y: 100,
+ properties: {},
+ },
+ {
+ type: 'wokwi-led',
+ id: 'led-1',
+ x: 400,
+ y: 150,
+ properties: { color: 'blue', pin: 9 },
+ },
+ ],
+ wires: [
+ {
+ id: 'wire-led',
+ start: { componentId: 'arduino-uno', pinName: '9' },
+ end: { componentId: 'led-1', pinName: 'A' },
+ color: '#0000ff',
+ },
+ ],
+ },
+ {
+ id: 'serial-hello',
+ title: 'Serial Hello World',
+ description: 'Send messages through serial communication',
+ category: 'communication',
+ difficulty: 'beginner',
+ code: `// Serial Communication Example
+// Send messages to Serial Monitor
+
+void setup() {
+ Serial.begin(9600);
+ Serial.println("Hello, Arduino!");
+ Serial.println("System initialized");
+}
+
+void loop() {
+ Serial.print("Uptime: ");
+ Serial.print(millis() / 1000);
+ Serial.println(" seconds");
+ delay(2000);
+}`,
+ components: [
+ {
+ type: 'wokwi-arduino-uno',
+ id: 'arduino-uno',
+ x: 100,
+ y: 100,
+ properties: {},
+ },
+ ],
+ wires: [],
+ },
+ {
+ id: 'rgb-led',
+ title: 'RGB LED Colors',
+ description: 'Cycle through colors with an RGB LED',
+ category: 'basics',
+ difficulty: 'intermediate',
+ code: `// RGB LED Color Cycling
+// Display different colors
+
+const int RED_PIN = 9;
+const int GREEN_PIN = 10;
+const int BLUE_PIN = 11;
+
+void setup() {
+ pinMode(RED_PIN, OUTPUT);
+ pinMode(GREEN_PIN, OUTPUT);
+ pinMode(BLUE_PIN, OUTPUT);
+}
+
+void setColor(int red, int green, int blue) {
+ analogWrite(RED_PIN, red);
+ analogWrite(GREEN_PIN, green);
+ analogWrite(BLUE_PIN, blue);
+}
+
+void loop() {
+ // Red
+ setColor(255, 0, 0);
+ delay(1000);
+
+ // Green
+ setColor(0, 255, 0);
+ delay(1000);
+
+ // Blue
+ setColor(0, 0, 255);
+ delay(1000);
+
+ // Yellow
+ setColor(255, 255, 0);
+ delay(1000);
+
+ // Cyan
+ setColor(0, 255, 255);
+ delay(1000);
+
+ // Magenta
+ setColor(255, 0, 255);
+ delay(1000);
+
+ // White
+ setColor(255, 255, 255);
+ delay(1000);
+}`,
+ components: [
+ {
+ type: 'wokwi-arduino-uno',
+ id: 'arduino-uno',
+ x: 100,
+ y: 100,
+ properties: {},
+ },
+ {
+ type: 'wokwi-rgb-led',
+ id: 'rgb-led-1',
+ x: 400,
+ y: 150,
+ properties: {},
+ },
+ ],
+ wires: [
+ {
+ id: 'wire-red',
+ start: { componentId: 'arduino-uno', pinName: '9' },
+ end: { componentId: 'rgb-led-1', pinName: 'R' },
+ color: '#ff0000',
+ },
+ {
+ id: 'wire-green',
+ start: { componentId: 'arduino-uno', pinName: '10' },
+ end: { componentId: 'rgb-led-1', pinName: 'G' },
+ color: '#00ff00',
+ },
+ {
+ id: 'wire-blue',
+ start: { componentId: 'arduino-uno', pinName: '11' },
+ end: { componentId: 'rgb-led-1', pinName: 'B' },
+ color: '#0000ff',
+ },
+ ],
+ },
+ {
+ id: 'simon-says',
+ title: 'Simon Says Game',
+ description: 'Memory game with LEDs and buttons',
+ category: 'games',
+ difficulty: 'advanced',
+ code: `// Simon Says Game
+// Memory game with 4 LEDs and buttons
+
+const int LED_PINS[] = {8, 9, 10, 11};
+const int BUTTON_PINS[] = {2, 3, 4, 5};
+const int NUM_LEDS = 4;
+
+int sequence[100];
+int sequenceLength = 0;
+int currentStep = 0;
+
+void setup() {
+ Serial.begin(9600);
+
+ for (int i = 0; i < NUM_LEDS; i++) {
+ pinMode(LED_PINS[i], OUTPUT);
+ pinMode(BUTTON_PINS[i], INPUT_PULLUP);
+ }
+
+ randomSeed(analogRead(A0));
+ newGame();
+}
+
+void newGame() {
+ sequenceLength = 1;
+ currentStep = 0;
+ addToSequence();
+ playSequence();
+}
+
+void addToSequence() {
+ sequence[sequenceLength - 1] = random(0, NUM_LEDS);
+}
+
+void playSequence() {
+ for (int i = 0; i < sequenceLength; i++) {
+ flashLED(sequence[i]);
+ delay(500);
+ }
+}
+
+void flashLED(int led) {
+ digitalWrite(LED_PINS[led], HIGH);
+ delay(300);
+ digitalWrite(LED_PINS[led], LOW);
+}
+
+void loop() {
+ for (int i = 0; i < NUM_LEDS; i++) {
+ if (digitalRead(BUTTON_PINS[i]) == LOW) {
+ flashLED(i);
+
+ if (i == sequence[currentStep]) {
+ currentStep++;
+ if (currentStep == sequenceLength) {
+ delay(1000);
+ sequenceLength++;
+ currentStep = 0;
+ addToSequence();
+ playSequence();
+ }
+ } else {
+ // Wrong button - game over
+ for (int j = 0; j < 3; j++) {
+ for (int k = 0; k < NUM_LEDS; k++) {
+ digitalWrite(LED_PINS[k], HIGH);
+ }
+ delay(200);
+ for (int k = 0; k < NUM_LEDS; k++) {
+ digitalWrite(LED_PINS[k], LOW);
+ }
+ delay(200);
+ }
+ newGame();
+ }
+
+ delay(300);
+ while (digitalRead(BUTTON_PINS[i]) == LOW);
+ }
+ }
+}`,
+ components: [
+ {
+ type: 'wokwi-arduino-uno',
+ id: 'arduino-uno',
+ x: 100,
+ y: 100,
+ properties: {},
+ },
+ {
+ type: 'wokwi-led',
+ id: 'led-red',
+ x: 450,
+ y: 100,
+ properties: { color: 'red', pin: 8 },
+ },
+ {
+ type: 'wokwi-led',
+ id: 'led-green',
+ x: 550,
+ y: 100,
+ properties: { color: 'green', pin: 9 },
+ },
+ {
+ type: 'wokwi-led',
+ id: 'led-blue',
+ x: 450,
+ y: 200,
+ properties: { color: 'blue', pin: 10 },
+ },
+ {
+ type: 'wokwi-led',
+ id: 'led-yellow',
+ x: 550,
+ y: 200,
+ properties: { color: 'yellow', pin: 11 },
+ },
+ {
+ type: 'wokwi-pushbutton',
+ id: 'button-red',
+ x: 450,
+ y: 300,
+ properties: {},
+ },
+ {
+ type: 'wokwi-pushbutton',
+ id: 'button-green',
+ x: 550,
+ y: 300,
+ properties: {},
+ },
+ {
+ type: 'wokwi-pushbutton',
+ id: 'button-blue',
+ x: 450,
+ y: 400,
+ properties: {},
+ },
+ {
+ type: 'wokwi-pushbutton',
+ id: 'button-yellow',
+ x: 550,
+ y: 400,
+ properties: {},
+ },
+ ],
+ wires: [
+ {
+ id: 'wire-led-red',
+ start: { componentId: 'arduino-uno', pinName: '8' },
+ end: { componentId: 'led-red', pinName: 'A' },
+ color: '#ff0000',
+ },
+ {
+ id: 'wire-led-green',
+ start: { componentId: 'arduino-uno', pinName: '9' },
+ end: { componentId: 'led-green', pinName: 'A' },
+ color: '#00ff00',
+ },
+ {
+ id: 'wire-led-blue',
+ start: { componentId: 'arduino-uno', pinName: '10' },
+ end: { componentId: 'led-blue', pinName: 'A' },
+ color: '#0000ff',
+ },
+ {
+ id: 'wire-led-yellow',
+ start: { componentId: 'arduino-uno', pinName: '11' },
+ end: { componentId: 'led-yellow', pinName: 'A' },
+ color: '#ffaa00',
+ },
+ {
+ id: 'wire-button-red',
+ start: { componentId: 'arduino-uno', pinName: '2' },
+ end: { componentId: 'button-red', pinName: '1.L' },
+ color: '#00aaff',
+ },
+ {
+ id: 'wire-button-green',
+ start: { componentId: 'arduino-uno', pinName: '3' },
+ end: { componentId: 'button-green', pinName: '1.L' },
+ color: '#00aaff',
+ },
+ {
+ id: 'wire-button-blue',
+ start: { componentId: 'arduino-uno', pinName: '4' },
+ end: { componentId: 'button-blue', pinName: '1.L' },
+ color: '#00aaff',
+ },
+ {
+ id: 'wire-button-yellow',
+ start: { componentId: 'arduino-uno', pinName: '5' },
+ end: { componentId: 'button-yellow', pinName: '1.L' },
+ color: '#00aaff',
+ },
+ ],
+ },
+];
+
+// Get examples by category
+export function getExamplesByCategory(category: ExampleProject['category']): ExampleProject[] {
+ return exampleProjects.filter((example) => example.category === category);
+}
+
+// Get example by ID
+export function getExampleById(id: string): ExampleProject | undefined {
+ return exampleProjects.find((example) => example.id === id);
+}
+
+// Get all categories
+export function getCategories(): ExampleProject['category'][] {
+ return ['basics', 'sensors', 'displays', 'communication', 'games', 'robotics'];
+}
diff --git a/frontend/src/pages/EditorPage.tsx b/frontend/src/pages/EditorPage.tsx
new file mode 100644
index 0000000..bfeb389
--- /dev/null
+++ b/frontend/src/pages/EditorPage.tsx
@@ -0,0 +1,41 @@
+/**
+ * Editor Page Component
+ *
+ * Main editor and simulator page
+ */
+
+import React from 'react';
+import { Link } from 'react-router-dom';
+import { CodeEditor } from '../components/editor/CodeEditor';
+import { EditorToolbar } from '../components/editor/EditorToolbar';
+import { SimulatorCanvas } from '../components/simulator/SimulatorCanvas';
+import '../App.css';
+
+export const EditorPage: React.FC = () => {
+ return (
+
+
+
+
+
Arduino Emulator
+
Local Arduino IDE & Simulator
+
+
+ 📚 Browse Examples
+
+
+
+
+
+ );
+};
diff --git a/frontend/src/pages/ExamplesPage.tsx b/frontend/src/pages/ExamplesPage.tsx
new file mode 100644
index 0000000..c96f758
--- /dev/null
+++ b/frontend/src/pages/ExamplesPage.tsx
@@ -0,0 +1,66 @@
+/**
+ * Examples Page Component
+ *
+ * Displays the examples gallery
+ */
+
+import React from 'react';
+import { useNavigate } from 'react-router-dom';
+import { ExamplesGallery } from '../components/examples/ExamplesGallery';
+import { useEditorStore } from '../store/useEditorStore';
+import { useSimulatorStore } from '../store/useSimulatorStore';
+import type { ExampleProject } from '../data/examples';
+
+export const ExamplesPage: React.FC = () => {
+ const navigate = useNavigate();
+ const { setCode } = useEditorStore();
+ const { setComponents, setWires } = useSimulatorStore();
+
+ const handleLoadExample = (example: ExampleProject) => {
+ console.log('Loading example:', example.title);
+
+ // Load the code into the editor
+ setCode(example.code);
+
+ // Load components into the simulator
+ // Convert component type to metadataId (e.g., 'wokwi-led' -> 'led')
+ setComponents(
+ example.components.map((comp) => ({
+ id: comp.id,
+ metadataId: comp.type.replace('wokwi-', ''),
+ x: comp.x,
+ y: comp.y,
+ properties: comp.properties,
+ }))
+ );
+
+ // Load wires (need to convert to full wire format with positions)
+ // For now, just set empty wires - wire positions will be calculated when components are loaded
+ const wiresWithPositions = example.wires.map((wire) => ({
+ id: wire.id,
+ start: {
+ componentId: wire.start.componentId,
+ pinName: wire.start.pinName,
+ x: 0, // Will be calculated by SimulatorCanvas
+ y: 0,
+ },
+ end: {
+ componentId: wire.end.componentId,
+ pinName: wire.end.pinName,
+ x: 0,
+ y: 0,
+ },
+ color: wire.color,
+ controlPoints: [],
+ isValid: true,
+ signalType: 'digital' as const,
+ }));
+
+ setWires(wiresWithPositions);
+
+ // Navigate to the editor
+ navigate('/');
+ };
+
+ return ;
+};
diff --git a/frontend/src/store/useSimulatorStore.ts b/frontend/src/store/useSimulatorStore.ts
index 81b3ee6..e0c54cb 100644
--- a/frontend/src/store/useSimulatorStore.ts
+++ b/frontend/src/store/useSimulatorStore.ts
@@ -44,12 +44,14 @@ interface SimulatorState {
removeComponent: (id: string) => void;
updateComponent: (id: string, updates: Partial) => void;
updateComponentState: (id: string, state: boolean) => void;
+ setComponents: (components: Component[]) => void;
// Wire management (Phase 1)
addWire: (wire: Wire) => void;
removeWire: (wireId: string) => void;
updateWire: (wireId: string, updates: Partial) => void;
setSelectedWire: (wireId: string | null) => void;
+ setWires: (wires: Wire[]) => void;
// Wire creation (Phase 2)
startWireCreation: (endpoint: WireEndpoint) => void;
@@ -220,6 +222,10 @@ export const useSimulatorStore = create((set, get) => {
}));
},
+ setComponents: (components) => {
+ set({ components });
+ },
+
// Wire management actions
addWire: (wire) => {
set((state) => ({
@@ -246,6 +252,10 @@ export const useSimulatorStore = create((set, get) => {
set({ selectedWireId: wireId });
},
+ setWires: (wires) => {
+ set({ wires });
+ },
+
// Wire creation actions (Phase 2)
startWireCreation: (endpoint) => {
set({