diff --git a/frontend/public/components-metadata.json b/frontend/public/components-metadata.json index 2ae8a80f..9f79f76a 100644 --- a/frontend/public/components-metadata.json +++ b/frontend/public/components-metadata.json @@ -1,6 +1,6 @@ { "version": "1.0.0", - "generatedAt": "2026-04-16T03:35:24.515Z", + "generatedAt": "2026-04-16T04:07:07.823Z", "components": [ { "thumbnail": "\n \n \n DIODE-1N4007\n \n ", @@ -815,6 +815,162 @@ "ili9341" ] }, + { + "id": "lcd1602", + "tagName": "wokwi-lcd1602", + "name": "LCD1602", + "category": "displays", + "thumbnail": "\n \n \n LCD1602\n \n ", + "properties": [ + { + "name": "color", + "type": "string", + "defaultValue": "black", + "control": "text" + }, + { + "name": "background", + "type": "string", + "defaultValue": "green", + "control": "text" + }, + { + "name": "characters", + "type": "number", + "defaultValue": { + "0": 0, + "1": 0, + "2": 0, + "3": 0, + "4": 0, + "5": 0, + "6": 0, + "7": 0, + "8": 0, + "9": 0, + "10": 0, + "11": 0, + "12": 0, + "13": 0, + "14": 0, + "15": 0, + "16": 0, + "17": 0, + "18": 0, + "19": 0, + "20": 0, + "21": 0, + "22": 0, + "23": 0, + "24": 0, + "25": 0, + "26": 0, + "27": 0, + "28": 0, + "29": 0, + "30": 0, + "31": 0 + }, + "control": "range" + }, + { + "name": "font", + "type": "string", + "control": "text" + }, + { + "name": "cursor", + "type": "string", + "defaultValue": false, + "control": "text" + }, + { + "name": "blink", + "type": "string", + "defaultValue": false, + "control": "text" + }, + { + "name": "cursorX", + "type": "string", + "defaultValue": 0, + "control": "text" + }, + { + "name": "cursorY", + "type": "string", + "defaultValue": 0, + "control": "text" + }, + { + "name": "backlight", + "type": "string", + "defaultValue": true, + "control": "text" + }, + { + "name": "pins", + "type": "string", + "defaultValue": "full", + "control": "text" + }, + { + "name": "screenOnly", + "type": "string", + "defaultValue": false, + "control": "text" + } + ], + "defaultValues": { + "color": "black", + "background": "green", + "characters": { + "0": 0, + "1": 0, + "2": 0, + "3": 0, + "4": 0, + "5": 0, + "6": 0, + "7": 0, + "8": 0, + "9": 0, + "10": 0, + "11": 0, + "12": 0, + "13": 0, + "14": 0, + "15": 0, + "16": 0, + "17": 0, + "18": 0, + "19": 0, + "20": 0, + "21": 0, + "22": 0, + "23": 0, + "24": 0, + "25": 0, + "26": 0, + "27": 0, + "28": 0, + "29": 0, + "30": 0, + "31": 0 + }, + "cursor": false, + "blink": false, + "cursorX": 0, + "cursorY": 0, + "backlight": true, + "pins": "full", + "screenOnly": false + }, + "pinCount": 21, + "tags": [ + "lcd1602" + ] + }, { "id": "lcd2004", "tagName": "wokwi-lcd2004", @@ -1748,6 +1904,57 @@ "servo" ] }, + { + "id": "stepper-motor", + "tagName": "wokwi-stepper-motor", + "name": "Stepper Motor", + "category": "motors", + "thumbnail": "\n \n \n STEPPER-MOTOR\n \n ", + "properties": [ + { + "name": "angle", + "type": "string", + "defaultValue": 0, + "control": "text" + }, + { + "name": "arrow", + "type": "string", + "defaultValue": "", + "control": "text" + }, + { + "name": "value", + "type": "string", + "defaultValue": "", + "control": "text" + }, + { + "name": "units", + "type": "string", + "defaultValue": "", + "control": "text" + }, + { + "name": "size", + "type": "string", + "control": "text" + } + ], + "defaultValues": { + "angle": 0, + "arrow": "", + "value": "", + "units": "" + }, + "pinCount": 4, + "tags": [ + "stepper-motor", + "stepper motor", + "stepper", + "motor" + ] + }, { "id": "7segment", "tagName": "wokwi-7segment", diff --git a/frontend/src/__tests__/examples-circuits.test.ts b/frontend/src/__tests__/examples-circuits.test.ts index 89f6ae2b..c34ff74b 100644 --- a/frontend/src/__tests__/examples-circuits.test.ts +++ b/frontend/src/__tests__/examples-circuits.test.ts @@ -23,11 +23,9 @@ describe('circuitExamples integration', () => { expect(dupes).toEqual([]); }); - it('circuit examples cover all expected categories', () => { - const cats = new Set(circuitExamples.map((e) => e.category)); - expect(cats.has('basics')).toBe(true); - expect(cats.has('sensors')).toBe(true); - expect(cats.has('robotics')).toBe(true); + it('all circuit examples use the circuits category', () => { + const nonCircuits = circuitExamples.filter((e) => e.category !== 'circuits'); + expect(nonCircuits.map((e) => e.id)).toEqual([]); }); it('every example has valid required fields', () => { @@ -35,7 +33,7 @@ describe('circuitExamples integration', () => { expect(e.id, `missing id: ${JSON.stringify(e)}`).toBeTypeOf('string'); expect(e.title).toBeTypeOf('string'); expect(e.description).toBeTypeOf('string'); - expect(e.category).toMatch(/^(basics|sensors|displays|communication|games|robotics)$/); + expect(e.category).toMatch(/^(basics|sensors|displays|communication|games|robotics|circuits)$/); expect(e.difficulty).toMatch(/^(beginner|intermediate|advanced)$/); expect(e.code).toBeTypeOf('string'); expect(Array.isArray(e.components)).toBe(true); diff --git a/frontend/src/components/editor/EditorToolbar.tsx b/frontend/src/components/editor/EditorToolbar.tsx index 5a4e8178..d0b68160 100644 --- a/frontend/src/components/editor/EditorToolbar.tsx +++ b/frontend/src/components/editor/EditorToolbar.tsx @@ -150,7 +150,10 @@ export const EditorToolbar = ({ consoleOpen, setConsoleOpen, compileLogs: _compi addLog({ timestamp: new Date(), type: 'info', message: `Starting compilation for ${boardLabel} (${fqbn})...` }); try { - const sketchFiles = files.map((f) => ({ name: f.name, content: f.content })); + const groupFiles = activeBoard?.activeFileGroupId + ? useEditorStore.getState().getGroupFiles(activeBoard.activeFileGroupId) + : files; + const sketchFiles = (groupFiles.length > 0 ? groupFiles : files).map((f) => ({ name: f.name, content: f.content })); const result = await compileCode(sketchFiles, fqbn); const resultLogs = parseCompileResult(result, boardLabel); @@ -524,14 +527,9 @@ export const EditorToolbar = ({ consoleOpen, setConsoleOpen, compileLogs: _compi {/* Run */} @@ -553,7 +551,7 @@ export const EditorToolbar = ({ consoleOpen, setConsoleOpen, compileLogs: _compi {/* Reset */} diff --git a/frontend/src/components/examples/ExamplesGallery.tsx b/frontend/src/components/examples/ExamplesGallery.tsx index a78cb3c3..162b3f6b 100644 --- a/frontend/src/components/examples/ExamplesGallery.tsx +++ b/frontend/src/components/examples/ExamplesGallery.tsx @@ -123,6 +123,11 @@ export const ExamplesGallery: React.FC = ({ onLoadExample ), + circuits: ( + + + + ), }; return icons[category]; }; @@ -167,7 +172,7 @@ export const ExamplesGallery: React.FC = ({ onLoadExample Category: - {(['all', 'basics', 'sensors', 'displays', 'communication', 'games', 'robotics'] as const).map((cat) => ( + {(['all', 'basics', 'sensors', 'displays', 'communication', 'games', 'robotics', 'circuits'] as const).map((cat) => ( ({ type: 'wokwi-led', id: `led${i}`, x: 450, y: 60+i*50, properties: { color: ['red','yellow','green','blue','white'][i] } })), ], wires: [ - ...Array.from({length:5}, (_,i) => w(`wa${i}`, ['uno',`${i+2}`], [`r${i}`,'1'])), + ...Array.from({length:5}, (_,i) => w(`wa${i}`, ['arduino-uno',`${i+2}`], [`r${i}`,'1'])), ...Array.from({length:5}, (_,i) => w(`wb${i}`, [`r${i}`,'2'], [`led${i}`,'A'])), - ...Array.from({length:5}, (_,i) => w(`wc${i}`, [`led${i}`,'C'], ['uno','GND'], '#000000')), + ...Array.from({length:5}, (_,i) => w(`wc${i}`, [`led${i}`,'C'], ['arduino-uno','GND'], '#000000')), ], }, @@ -274,7 +274,7 @@ void loop() { id: 'capacitor-charge-curve', title: 'Capacitor Charging Curve', description: 'Charge a capacitor through a resistor, read the exponential V(t) via ADC.', - category: 'basics', difficulty: 'intermediate', + category: 'circuits', difficulty: 'intermediate', code: `// RC Charging — observe exponential curve // tau = R*C = 10k * 100uF = 1 second void setup() { @@ -292,9 +292,9 @@ void loop() { { type: 'wokwi-resistor', id: 'r1', x: 380, y: 100, properties: { value: '10000' } }, ], wires: [ - w('w1', ['uno','8'], ['r1','1'], '#00aaff'), - w('w2', ['r1','2'], ['uno','A0'], '#ffaa00'), - w('w3', ['r1','2'], ['uno','GND'], '#000000'), + w('w1', ['arduino-uno','8'], ['r1','1'], '#00aaff'), + w('w2', ['r1','2'], ['arduino-uno','A0'], '#ffaa00'), + w('w3', ['r1','2'], ['arduino-uno','GND'], '#000000'), ], }, @@ -306,7 +306,7 @@ void loop() { id: 'npn-led-switch', title: 'NPN Transistor LED Switch', description: '2N2222 NPN switches a high-current LED from a low-current MCU pin.', - category: 'basics', difficulty: 'intermediate', + category: 'circuits', difficulty: 'intermediate', code: `// NPN switch — pin 9 drives base through 1k, collector drives LED void setup() { pinMode(9, OUTPUT); } void loop() { @@ -320,10 +320,10 @@ void loop() { { type: 'wokwi-led', id: 'led1', x: 480, y: 160, properties: { color: 'green' } }, ], wires: [ - w('w1', ['uno','9'], ['rb','1']), - w('w2', ['uno','5V'], ['rc','1'], '#ff0000'), + w('w1', ['arduino-uno','9'], ['rb','1']), + w('w2', ['arduino-uno','5V'], ['rc','1'], '#ff0000'), w('w3', ['rc','2'], ['led1','A']), - w('w4', ['led1','C'], ['uno','GND'], '#000000'), + w('w4', ['led1','C'], ['arduino-uno','GND'], '#000000'), ], }, @@ -331,7 +331,7 @@ void loop() { id: 'pnp-high-side-switch', title: 'PNP High-Side Switch', description: '2N3906 PNP switches a load to Vcc when base is pulled LOW.', - category: 'basics', difficulty: 'intermediate', + category: 'circuits', difficulty: 'intermediate', code: `// PNP high-side switch // Pin 9 LOW = load ON, Pin 9 HIGH = load OFF void setup() { pinMode(9, OUTPUT); } @@ -346,9 +346,9 @@ void loop() { { type: 'wokwi-led', id: 'led1', x: 480, y: 280, properties: { color: 'red' } }, ], wires: [ - w('w1', ['uno','9'], ['rb','1']), + w('w1', ['arduino-uno','9'], ['rb','1']), w('w2', ['rl','2'], ['led1','A']), - w('w3', ['led1','C'], ['uno','GND'], '#000000'), + w('w3', ['led1','C'], ['arduino-uno','GND'], '#000000'), ], }, @@ -356,7 +356,7 @@ void loop() { id: 'mosfet-pwm-led', title: 'MOSFET PWM LED Dimmer', description: '2N7000 N-MOSFET driven by PWM. Vgs=3.3V fully enhances the FET.', - category: 'basics', difficulty: 'intermediate', + category: 'circuits', difficulty: 'intermediate', code: `// MOSFET PWM LED dimmer void setup() { pinMode(9, OUTPUT); } void loop() { @@ -369,9 +369,9 @@ void loop() { { type: 'wokwi-led', id: 'led1', x: 420, y: 160, properties: { color: 'white' } }, ], wires: [ - w('w1', ['uno','5V'], ['rl','1'], '#ff0000'), + w('w1', ['arduino-uno','5V'], ['rl','1'], '#ff0000'), w('w2', ['rl','2'], ['led1','A']), - w('w3', ['led1','C'], ['uno','GND'], '#000000'), + w('w3', ['led1','C'], ['arduino-uno','GND'], '#000000'), ], }, @@ -379,7 +379,7 @@ void loop() { id: 'diode-rectifier', title: 'Half-Wave Rectifier', description: 'Diode passes only positive half-cycles. Read rectified output on ADC.', - category: 'basics', difficulty: 'intermediate', + category: 'circuits', difficulty: 'intermediate', code: `// Half-wave rectifier — observe on Serial plotter void setup() { Serial.begin(115200); } void loop() { @@ -392,8 +392,8 @@ void loop() { { type: 'wokwi-resistor', id: 'rl', x: 420, y: 200, properties: { value: '1000' } }, ], wires: [ - w('w1', ['rl','2'], ['uno','GND'], '#000000'), - w('w2', ['rl','1'], ['uno','A0'], '#ffaa00'), + w('w1', ['rl','2'], ['arduino-uno','GND'], '#000000'), + w('w2', ['rl','1'], ['arduino-uno','A0'], '#ffaa00'), ], }, @@ -401,7 +401,7 @@ void loop() { id: 'zener-regulator', title: 'Zener Voltage Regulator', description: '5.1V Zener clamps output. Even if input varies, output stays at 5.1V.', - category: 'basics', difficulty: 'intermediate', + category: 'circuits', difficulty: 'intermediate', code: `// Zener 5.1V regulator // Input = 9V battery, Rs = 220 ohm, Zener clamps to 5.1V void setup() { Serial.begin(9600); } @@ -415,8 +415,8 @@ void loop() { { type: 'wokwi-resistor', id: 'rs', x: 380, y: 100, properties: { value: '220' } }, ], wires: [ - w('w1', ['rs','2'], ['uno','A0'], '#ffaa00'), - w('w2', ['rs','2'], ['uno','GND'], '#000000'), + w('w1', ['rs','2'], ['arduino-uno','A0'], '#ffaa00'), + w('w2', ['rs','2'], ['arduino-uno','GND'], '#000000'), ], }, @@ -424,7 +424,7 @@ void loop() { id: 'schottky-reverse-protection', title: 'Reverse Polarity Protection', description: 'Schottky diode protects circuit from accidental reverse battery connection.', - category: 'basics', difficulty: 'beginner', + category: 'circuits', difficulty: 'beginner', code: `// Schottky reverse-polarity protection // 1N5817: low Vf = 0.3V, minimal power loss void setup() { Serial.begin(9600); } @@ -440,7 +440,7 @@ void loop() { id: 'bjt-common-emitter', title: 'Common-Emitter Amplifier', description: 'NPN BJT amplifies a small AC signal. Gain = -Rc/Re.', - category: 'basics', difficulty: 'advanced', + category: 'circuits', difficulty: 'advanced', code: `// Common-emitter amplifier // Biased at Vcc/2, gain ~ -Rc/Re = -4.7 void setup() { Serial.begin(115200); } @@ -457,12 +457,12 @@ void loop() { { type: 'wokwi-resistor', id: 're', x: 450, y: 280, properties: { value: '1000' } }, ], wires: [ - w('w1', ['uno','5V'], ['rb1','1'], '#ff0000'), - w('w2', ['uno','5V'], ['rc','1'], '#ff0000'), + w('w1', ['arduino-uno','5V'], ['rb1','1'], '#ff0000'), + w('w2', ['arduino-uno','5V'], ['rc','1'], '#ff0000'), w('w3', ['rb1','2'], ['rb2','1']), - w('w4', ['rb2','2'], ['uno','GND'], '#000000'), - w('w5', ['re','2'], ['uno','GND'], '#000000'), - w('w6', ['rc','2'], ['uno','A0'], '#ffaa00'), + w('w4', ['rb2','2'], ['arduino-uno','GND'], '#000000'), + w('w5', ['re','2'], ['arduino-uno','GND'], '#000000'), + w('w6', ['rc','2'], ['arduino-uno','A0'], '#ffaa00'), ], }, @@ -470,7 +470,7 @@ void loop() { id: 'darlington-high-current', title: 'Darlington Pair (High Current)', description: 'Two NPN BJTs cascaded for beta-squared current gain. Drives heavy loads from MCU.', - category: 'basics', difficulty: 'advanced', + category: 'circuits', difficulty: 'advanced', code: `// Darlington pair — drives a high-current load void setup() { pinMode(9, OUTPUT); } void loop() { @@ -483,9 +483,9 @@ void loop() { { type: 'wokwi-resistor', id: 'rl', x: 480, y: 100, properties: { value: '100' } }, ], wires: [ - w('w1', ['uno','9'], ['rb','1']), - w('w2', ['uno','5V'], ['rl','1'], '#ff0000'), - w('w3', ['rl','2'], ['uno','GND'], '#000000'), + w('w1', ['arduino-uno','9'], ['rb','1']), + w('w2', ['arduino-uno','5V'], ['rl','1'], '#ff0000'), + w('w3', ['rl','2'], ['arduino-uno','GND'], '#000000'), ], }, @@ -497,7 +497,7 @@ void loop() { id: 'opamp-inverting', title: 'Inverting Amplifier (LM358)', description: 'Vout = -(Rf/Rin) * Vin. Gain=-10 with Rin=1k, Rf=10k.', - category: 'basics', difficulty: 'intermediate', + category: 'circuits', difficulty: 'intermediate', code: `// Inverting amplifier — gain = -Rf/Rin = -10 void setup() { Serial.begin(9600); } void loop() { @@ -514,8 +514,8 @@ void loop() { ], wires: [ w('w1', ['rin','2'], ['rf','1']), - w('w2', ['rf','2'], ['uno','A1'], '#ffaa00'), - w('w3', ['rin','1'], ['uno','A0'], '#ffaa00'), + w('w2', ['rf','2'], ['arduino-uno','A1'], '#ffaa00'), + w('w3', ['rin','1'], ['arduino-uno','A0'], '#ffaa00'), ], }, @@ -523,7 +523,7 @@ void loop() { id: 'opamp-voltage-follower', title: 'Voltage Follower (Buffer)', description: 'Op-amp with 100% feedback. Vout = Vin. High Z input, low Z output.', - category: 'basics', difficulty: 'beginner', + category: 'circuits', difficulty: 'beginner', code: `// Voltage follower — Vout tracks Vin exactly void setup() { Serial.begin(9600); } void loop() { @@ -538,10 +538,10 @@ void loop() { { type: 'wokwi-potentiometer', id: 'pot', x: 350, y: 160, properties: {} }, ], wires: [ - w('w1', ['uno','5V'], ['pot','VCC'], '#ff0000'), - w('w2', ['pot','GND'], ['uno','GND'], '#000000'), - w('w3', ['pot','SIG'], ['uno','A0'], '#ffaa00'), - w('w4', ['pot','SIG'], ['uno','A1'], '#ffaa00'), + w('w1', ['arduino-uno','5V'], ['pot','VCC'], '#ff0000'), + w('w2', ['pot','GND'], ['arduino-uno','GND'], '#000000'), + w('w3', ['pot','SIG'], ['arduino-uno','A0'], '#ffaa00'), + w('w4', ['pot','SIG'], ['arduino-uno','A1'], '#ffaa00'), ], }, @@ -549,7 +549,7 @@ void loop() { id: 'opamp-comparator', title: 'Comparator with LED', description: 'Op-amp compares pot voltage vs 2.5V reference. LED indicates which is higher.', - category: 'basics', difficulty: 'intermediate', + category: 'circuits', difficulty: 'intermediate', code: `// Comparator — LED lights when pot > 2.5V void setup() { Serial.begin(9600); } void loop() { @@ -565,11 +565,11 @@ void loop() { { type: 'wokwi-resistor', id: 'rl', x: 480, y: 120, properties: { value: '220' } }, ], wires: [ - w('w1', ['uno','5V'], ['pot','VCC'], '#ff0000'), - w('w2', ['pot','GND'], ['uno','GND'], '#000000'), - w('w3', ['pot','SIG'], ['uno','A0'], '#ffaa00'), + w('w1', ['arduino-uno','5V'], ['pot','VCC'], '#ff0000'), + w('w2', ['pot','GND'], ['arduino-uno','GND'], '#000000'), + w('w3', ['pot','SIG'], ['arduino-uno','A0'], '#ffaa00'), w('w4', ['rl','2'], ['led1','A']), - w('w5', ['led1','C'], ['uno','GND'], '#000000'), + w('w5', ['led1','C'], ['arduino-uno','GND'], '#000000'), ], }, @@ -577,7 +577,7 @@ void loop() { id: 'opamp-difference', title: 'Difference Amplifier', description: 'Vout = Gain * (V2 - V1). Useful for bridge sensors and differential signals.', - category: 'sensors', difficulty: 'advanced', + category: 'circuits', difficulty: 'advanced', code: `// Difference amplifier — Gain=10, Vout = 10*(V2-V1) void setup() { Serial.begin(9600); } void loop() { @@ -597,10 +597,10 @@ void loop() { { type: 'wokwi-resistor', id: 'r4', x: 350, y: 320, properties: { value: '100000' } }, ], wires: [ - w('w1', ['r1','1'], ['uno','A0'], '#ffaa00'), - w('w2', ['r3','1'], ['uno','A1'], '#ffaa00'), + w('w1', ['r1','1'], ['arduino-uno','A0'], '#ffaa00'), + w('w2', ['r3','1'], ['arduino-uno','A1'], '#ffaa00'), w('w3', ['r1','2'], ['r2','1']), - w('w4', ['r2','2'], ['uno','A2'], '#ffaa00'), + w('w4', ['r2','2'], ['arduino-uno','A2'], '#ffaa00'), ], }, @@ -608,7 +608,7 @@ void loop() { id: 'opamp-schmitt-trigger', title: 'Schmitt Trigger', description: 'Op-amp with positive feedback creates hysteresis. Cleans up noisy signals.', - category: 'basics', difficulty: 'advanced', + category: 'circuits', difficulty: 'advanced', code: `// Schmitt trigger — cleans noisy input void setup() { Serial.begin(9600); } void loop() { @@ -624,12 +624,12 @@ void loop() { { type: 'wokwi-resistor', id: 'rfb', x: 450, y: 200, properties: { value: '100000' } }, ], wires: [ - w('w1', ['uno','5V'], ['pot','VCC'], '#ff0000'), - w('w2', ['pot','GND'], ['uno','GND'], '#000000'), + w('w1', ['arduino-uno','5V'], ['pot','VCC'], '#ff0000'), + w('w2', ['pot','GND'], ['arduino-uno','GND'], '#000000'), w('w3', ['pot','SIG'], ['rin','1']), w('w4', ['rin','2'], ['rfb','1']), - w('w5', ['rfb','2'], ['uno','A1'], '#ffaa00'), - w('w6', ['pot','SIG'], ['uno','A0'], '#ffaa00'), + w('w5', ['rfb','2'], ['arduino-uno','A1'], '#ffaa00'), + w('w6', ['pot','SIG'], ['arduino-uno','A0'], '#ffaa00'), ], }, @@ -641,7 +641,7 @@ void loop() { id: 'and-gate-alarm', title: 'AND Gate Alarm', description: 'Buzzer sounds only when BOTH buttons are pressed (AND logic).', - category: 'basics', difficulty: 'beginner', + category: 'circuits', difficulty: 'beginner', code: `// AND gate alarm — both buttons must be pressed void setup() { pinMode(2, INPUT_PULLUP); pinMode(3, INPUT_PULLUP); pinMode(8, OUTPUT); } void loop() { @@ -657,13 +657,13 @@ void loop() { { type: 'wokwi-resistor', id: 'rl', x: 480, y: 60, properties: { value: '220' } }, ], wires: [ - w('w1', ['uno','2'], ['btn1','1.l']), - w('w2', ['btn1','2.l'], ['uno','GND'], '#000000'), - w('w3', ['uno','3'], ['btn2','1.l']), - w('w4', ['btn2','2.l'], ['uno','GND'], '#000000'), - w('w5', ['uno','8'], ['rl','1']), + w('w1', ['arduino-uno','2'], ['btn1','1.l']), + w('w2', ['btn1','2.l'], ['arduino-uno','GND'], '#000000'), + w('w3', ['arduino-uno','3'], ['btn2','1.l']), + w('w4', ['btn2','2.l'], ['arduino-uno','GND'], '#000000'), + w('w5', ['arduino-uno','8'], ['rl','1']), w('w6', ['rl','2'], ['led1','A']), - w('w7', ['led1','C'], ['uno','GND'], '#000000'), + w('w7', ['led1','C'], ['arduino-uno','GND'], '#000000'), ], }, @@ -671,7 +671,7 @@ void loop() { id: 'xor-toggle-detector', title: 'XOR Toggle Detector', description: 'XOR gate detects when two switches are in different positions.', - category: 'basics', difficulty: 'beginner', + category: 'circuits', difficulty: 'beginner', code: `// XOR — LED on when switches differ void setup() { pinMode(2,INPUT_PULLUP); pinMode(3,INPUT_PULLUP); pinMode(13,OUTPUT); } void loop() { @@ -684,10 +684,10 @@ void loop() { { type: 'wokwi-pushbutton', id: 'sw2', x: 350, y: 180, properties: {} }, ], wires: [ - w('w1', ['uno','2'], ['sw1','1.l']), - w('w2', ['sw1','2.l'], ['uno','GND'], '#000000'), - w('w3', ['uno','3'], ['sw2','1.l']), - w('w4', ['sw2','2.l'], ['uno','GND'], '#000000'), + w('w1', ['arduino-uno','2'], ['sw1','1.l']), + w('w2', ['sw1','2.l'], ['arduino-uno','GND'], '#000000'), + w('w3', ['arduino-uno','3'], ['sw2','1.l']), + w('w4', ['sw2','2.l'], ['arduino-uno','GND'], '#000000'), ], }, @@ -695,7 +695,7 @@ void loop() { id: 'nand-sr-latch', title: 'NAND SR Latch', description: 'Two cross-coupled NAND gates form a Set-Reset latch. Memory without a clock!', - category: 'basics', difficulty: 'intermediate', + category: 'circuits', difficulty: 'intermediate', code: `// Software NAND SR latch simulation bool q = false; void setup() { Serial.begin(9600); pinMode(2,INPUT_PULLUP); pinMode(3,INPUT_PULLUP); pinMode(13,OUTPUT); } @@ -716,13 +716,13 @@ void loop() { { type: 'wokwi-resistor', id: 'rl', x: 480, y: 60, properties: { value: '220' } }, ], wires: [ - w('w1', ['uno','2'], ['setBtn','1.l']), - w('w2', ['setBtn','2.l'], ['uno','GND'], '#000000'), - w('w3', ['uno','3'], ['rstBtn','1.l']), - w('w4', ['rstBtn','2.l'], ['uno','GND'], '#000000'), - w('w5', ['uno','13'], ['rl','1']), + w('w1', ['arduino-uno','2'], ['setBtn','1.l']), + w('w2', ['setBtn','2.l'], ['arduino-uno','GND'], '#000000'), + w('w3', ['arduino-uno','3'], ['rstBtn','1.l']), + w('w4', ['rstBtn','2.l'], ['arduino-uno','GND'], '#000000'), + w('w5', ['arduino-uno','13'], ['rl','1']), w('w6', ['rl','2'], ['qled','A']), - w('w7', ['qled','C'], ['uno','GND'], '#000000'), + w('w7', ['qled','C'], ['arduino-uno','GND'], '#000000'), ], }, @@ -730,7 +730,7 @@ void loop() { id: 'full-adder', title: 'Full Adder (1-bit)', description: 'Sum = A XOR B XOR Cin, Cout = (A AND B) OR (Cin AND (A XOR B)).', - category: 'basics', difficulty: 'intermediate', + category: 'circuits', difficulty: 'intermediate', code: `// 1-bit full adder in software void setup() { Serial.begin(9600); pinMode(2,INPUT_PULLUP); pinMode(3,INPUT_PULLUP); pinMode(4,INPUT_PULLUP); } void loop() { @@ -751,12 +751,12 @@ void loop() { { type: 'wokwi-led', id: 'coutLed', x: 480, y: 200, properties: { color: 'red' } }, ], wires: [ - w('w1', ['uno','2'], ['bA','1.l']), - w('w2', ['bA','2.l'], ['uno','GND'], '#000000'), - w('w3', ['uno','3'], ['bB','1.l']), - w('w4', ['bB','2.l'], ['uno','GND'], '#000000'), - w('w5', ['uno','4'], ['bCin','1.l']), - w('w6', ['bCin','2.l'], ['uno','GND'], '#000000'), + w('w1', ['arduino-uno','2'], ['bA','1.l']), + w('w2', ['bA','2.l'], ['arduino-uno','GND'], '#000000'), + w('w3', ['arduino-uno','3'], ['bB','1.l']), + w('w4', ['bB','2.l'], ['arduino-uno','GND'], '#000000'), + w('w5', ['arduino-uno','4'], ['bCin','1.l']), + w('w6', ['bCin','2.l'], ['arduino-uno','GND'], '#000000'), ], }, @@ -764,7 +764,7 @@ void loop() { id: 'binary-counter-leds', title: '4-bit Binary Counter', description: 'Count from 0 to 15 displayed on 4 LEDs. Each LED = one bit.', - category: 'basics', difficulty: 'beginner', + category: 'circuits', difficulty: 'beginner', code: `// 4-bit binary counter on LEDs int count = 0; void setup() { for(int i=2;i<=5;i++) pinMode(i,OUTPUT); } @@ -779,9 +779,9 @@ void loop() { ...Array.from({length:4}, (_,i) => ({ type: 'wokwi-led', id: `led${i}`, x: 460, y: 60+i*60, properties: { color: ['red','yellow','green','blue'][i] } })), ], wires: [ - ...Array.from({length:4}, (_,i) => w(`wa${i}`, ['uno',`${i+2}`], [`r${i}`,'1'])), + ...Array.from({length:4}, (_,i) => w(`wa${i}`, ['arduino-uno',`${i+2}`], [`r${i}`,'1'])), ...Array.from({length:4}, (_,i) => w(`wb${i}`, [`r${i}`,'2'], [`led${i}`,'A'])), - ...Array.from({length:4}, (_,i) => w(`wc${i}`, [`led${i}`,'C'], ['uno','GND'], '#000000')), + ...Array.from({length:4}, (_,i) => w(`wc${i}`, [`led${i}`,'C'], ['arduino-uno','GND'], '#000000')), ], }, @@ -789,7 +789,7 @@ void loop() { id: 'logic-probe', title: 'Logic Probe (HIGH/LOW/FLOATING)', description: 'Read any digital pin state and show on 3 LEDs: green=HIGH, red=LOW, yellow=floating.', - category: 'basics', difficulty: 'intermediate', + category: 'circuits', difficulty: 'intermediate', code: `// Logic probe — tests pin 7 void setup() { pinMode(10,OUTPUT); pinMode(11,OUTPUT); pinMode(12,OUTPUT); // R,Y,G @@ -811,12 +811,12 @@ void loop() { { type: 'wokwi-resistor', id: 'rr', x: 400, y: 90, properties: { value: '220' } }, ], wires: [ - w('w1', ['uno','12'], ['rg','1']), + w('w1', ['arduino-uno','12'], ['rg','1']), w('w2', ['rg','2'], ['gLed','A']), - w('w3', ['gLed','C'], ['uno','GND'], '#000000'), - w('w4', ['uno','10'], ['rr','1']), + w('w3', ['gLed','C'], ['arduino-uno','GND'], '#000000'), + w('w4', ['arduino-uno','10'], ['rr','1']), w('w5', ['rr','2'], ['rLed','A']), - w('w6', ['rLed','C'], ['uno','GND'], '#000000'), + w('w6', ['rLed','C'], ['arduino-uno','GND'], '#000000'), ], }, @@ -828,7 +828,7 @@ void loop() { id: 'relay-led-switch', title: 'Relay-Controlled LED', description: 'NPN transistor drives a relay. Relay switches an LED connected to a separate supply.', - category: 'robotics', difficulty: 'intermediate', + category: 'circuits', difficulty: 'intermediate', code: `// Relay control via NPN transistor void setup() { pinMode(9, OUTPUT); } void loop() { @@ -842,9 +842,9 @@ void loop() { { type: 'wokwi-resistor', id: 'rl', x: 500, y: 120, properties: { value: '220' } }, ], wires: [ - w('w1', ['uno','9'], ['rb','1']), + w('w1', ['arduino-uno','9'], ['rb','1']), w('w2', ['rl','2'], ['led1','A']), - w('w3', ['led1','C'], ['uno','GND'], '#000000'), + w('w3', ['led1','C'], ['arduino-uno','GND'], '#000000'), ], }, @@ -852,7 +852,7 @@ void loop() { id: 'optocoupler-signal', title: 'Optocoupler Signal Isolation', description: '4N25 optocoupler isolates MCU from a higher-voltage circuit.', - category: 'communication', difficulty: 'intermediate', + category: 'circuits', difficulty: 'intermediate', code: `// Optocoupler 4N25 — MCU drives LED side, reads phototransistor side void setup() { pinMode(9,OUTPUT); Serial.begin(9600); } void loop() { @@ -869,9 +869,9 @@ void loop() { { type: 'wokwi-resistor', id: 'rpull', x: 500, y: 80, properties: { value: '10000' } }, ], wires: [ - w('w1', ['uno','9'], ['rled','1']), - w('w2', ['uno','5V'], ['rpull','1'], '#ff0000'), - w('w3', ['rpull','2'], ['uno','A0'], '#ffaa00'), + w('w1', ['arduino-uno','9'], ['rled','1']), + w('w2', ['arduino-uno','5V'], ['rpull','1'], '#ff0000'), + w('w3', ['rpull','2'], ['arduino-uno','A0'], '#ffaa00'), ], }, @@ -879,7 +879,7 @@ void loop() { id: 'l293d-motor-control', title: 'DC Motor Control (L293D)', description: 'L293D H-bridge drives a DC motor forward, reverse, and brake.', - category: 'robotics', difficulty: 'intermediate', + category: 'circuits', difficulty: 'intermediate', code: `// L293D motor control — forward, reverse, brake #define EN 9 #define IN1 7 @@ -899,7 +899,7 @@ void loop() { { type: 'wokwi-resistor', id: 'rm', x: 450, y: 200, properties: { value: '10' } }, ], wires: [ - w('w1', ['rm','2'], ['uno','GND'], '#000000'), + w('w1', ['rm','2'], ['arduino-uno','GND'], '#000000'), ], }, @@ -907,7 +907,7 @@ void loop() { id: 'l293d-speed-pwm', title: 'Motor Speed Control (PWM)', description: 'Potentiometer controls motor speed via PWM on L293D enable pin.', - category: 'robotics', difficulty: 'intermediate', + category: 'circuits', difficulty: 'intermediate', code: `// Motor speed via potentiometer + L293D #define EN 9 #define IN1 7 @@ -926,9 +926,9 @@ void loop() { { type: 'wokwi-potentiometer', id: 'pot', x: 350, y: 200, properties: {} }, ], wires: [ - w('w1', ['uno','5V'], ['pot','VCC'], '#ff0000'), - w('w2', ['pot','GND'], ['uno','GND'], '#000000'), - w('w3', ['pot','SIG'], ['uno','A0'], '#ffaa00'), + w('w1', ['arduino-uno','5V'], ['pot','VCC'], '#ff0000'), + w('w2', ['pot','GND'], ['arduino-uno','GND'], '#000000'), + w('w3', ['pot','SIG'], ['arduino-uno','A0'], '#ffaa00'), ], }, @@ -940,7 +940,7 @@ void loop() { id: 'power-supply-7805', title: '7805 Regulated Power Supply', description: '9V battery → 7805 → stable 5V for the Arduino. Classic linear regulator.', - category: 'basics', difficulty: 'beginner', + category: 'circuits', difficulty: 'beginner', code: `// 7805 power supply — regulated 5V from 9V battery // The 7805 provides stable 5V regardless of battery voltage (7-12V range) void setup() { Serial.begin(9600); } @@ -954,8 +954,8 @@ void loop() { { type: 'wokwi-resistor', id: 'rload', x: 420, y: 160, properties: { value: '1000' } }, ], wires: [ - w('w1', ['rload','1'], ['uno','A0'], '#ffaa00'), - w('w2', ['rload','2'], ['uno','GND'], '#000000'), + w('w1', ['rload','1'], ['arduino-uno','A0'], '#ffaa00'), + w('w2', ['rload','2'], ['arduino-uno','GND'], '#000000'), ], }, @@ -963,7 +963,7 @@ void loop() { id: 'lm317-adjustable-psu', title: 'LM317 Adjustable PSU', description: 'LM317 with R1/R2 divider. Vout = 1.25 * (1 + R2/R1). Set any voltage 1.25-37V.', - category: 'basics', difficulty: 'intermediate', + category: 'circuits', difficulty: 'intermediate', code: `// LM317 adjustable regulator // R1 = 240, R2 = 720 -> Vout = 1.25 * (1 + 720/240) = 5.0V void setup() { Serial.begin(9600); } @@ -979,8 +979,8 @@ void loop() { ], wires: [ w('w1', ['r1','2'], ['r2','1']), - w('w2', ['r2','2'], ['uno','GND'], '#000000'), - w('w3', ['r1','1'], ['uno','A0'], '#ffaa00'), + w('w2', ['r2','2'], ['arduino-uno','GND'], '#000000'), + w('w3', ['r1','1'], ['arduino-uno','A0'], '#ffaa00'), ], }, @@ -988,7 +988,7 @@ void loop() { id: 'battery-voltage-monitor', title: 'Battery Voltage Monitor', description: 'Voltage divider scales 9V battery down to 0-5V range for ADC measurement.', - category: 'sensors', difficulty: 'beginner', + category: 'circuits', difficulty: 'beginner', code: `// Battery voltage monitor // R1=20k + R2=10k divider: V_adc = V_bat * 10k / 30k // V_bat = V_adc * 3 @@ -1007,8 +1007,8 @@ void loop() { ], wires: [ w('w1', ['r1','2'], ['r2','1']), - w('w2', ['r2','2'], ['uno','GND'], '#000000'), - w('w3', ['r1','2'], ['uno','A0'], '#ffaa00'), + w('w2', ['r2','2'], ['arduino-uno','GND'], '#000000'), + w('w3', ['r1','2'], ['arduino-uno','A0'], '#ffaa00'), ], }, @@ -1020,7 +1020,7 @@ void loop() { id: 'esp32-dual-adc', title: 'ESP32 Dual ADC Reader', description: 'ESP32 reads two analog channels (GPIO34, GPIO35) simultaneously at 12-bit resolution.', - category: 'sensors', difficulty: 'beginner', + category: 'circuits', difficulty: 'beginner', boardType: 'esp32', code: `// ESP32 dual ADC — 12-bit, 3.3V reference void setup() { @@ -1054,7 +1054,7 @@ void loop() { id: 'mega-multi-led', title: 'Arduino Mega 16-LED Bar', description: 'Arduino Mega drives 16 LEDs from pins 22-37. Knight Rider scanner effect.', - category: 'basics', difficulty: 'beginner', + category: 'circuits', difficulty: 'beginner', boardType: 'arduino-mega', code: `// Arduino Mega — 16-LED Knight Rider void setup() { for(int i=22;i<=37;i++) pinMode(i,OUTPUT); } @@ -1067,8 +1067,8 @@ void loop() { ...Array.from({length:8}, (_,i) => ({ type: 'wokwi-led', id: `led${i}`, x: 400+i*30, y: 300, properties: { color: 'red' } })), ], wires: [ - ...Array.from({length:8}, (_,i) => w(`wl${i}`, ['mega',`${22+i}`], [`led${i}`,'A'])), - ...Array.from({length:8}, (_,i) => w(`wg${i}`, [`led${i}`,'C'], ['mega','GND'], '#000000')), + ...Array.from({length:8}, (_,i) => w(`wl${i}`, ['arduino-mega',`${22+i}`], [`led${i}`,'A'])), + ...Array.from({length:8}, (_,i) => w(`wg${i}`, [`led${i}`,'C'], ['arduino-mega','GND'], '#000000')), ], }, @@ -1076,7 +1076,7 @@ void loop() { id: 'nano-sensor-station', title: 'Arduino Nano Sensor Station', description: 'Compact weather station: NTC + photoresistor on Nano. Reads temp and light.', - category: 'sensors', difficulty: 'beginner', + category: 'circuits', difficulty: 'beginner', boardType: 'arduino-nano', code: `// Nano sensor station — NTC + LDR #define NTC_PIN A0 @@ -1092,21 +1092,21 @@ void loop() { delay(1000); }`, components: [ - { type: 'wokwi-arduino-nano', id: 'nano', x: 100, y: 100, properties: {} }, + { type: 'wokwi-arduino-nano', id: 'arduino-nano', x: 100, y: 100, properties: {} }, { type: 'wokwi-ntc-temperature-sensor', id: 'ntc', x: 350, y: 80, properties: { temperature: '22' } }, { type: 'wokwi-resistor', id: 'rntc', x: 350, y: 160, properties: { value: '10000' } }, { type: 'wokwi-photoresistor-sensor', id: 'ldr', x: 350, y: 240, properties: { lux: '300' } }, { type: 'wokwi-resistor', id: 'rldr', x: 350, y: 320, properties: { value: '10000' } }, ], wires: [ - w('w1', ['nano','5V'], ['ntc','1'], '#ff0000'), + w('w1', ['arduino-nano','5V'], ['ntc','1'], '#ff0000'), w('w2', ['ntc','2'], ['rntc','1']), - w('w3', ['rntc','2'], ['nano','GND'], '#000000'), - w('w4', ['ntc','2'], ['nano','A0'], '#ffaa00'), - w('w5', ['nano','5V'], ['ldr','VCC'], '#ff0000'), + w('w3', ['rntc','2'], ['arduino-nano','GND'], '#000000'), + w('w4', ['ntc','2'], ['arduino-nano','A0'], '#ffaa00'), + w('w5', ['arduino-nano','5V'], ['ldr','VCC'], '#ff0000'), w('w6', ['ldr','SIG'], ['rldr','1']), - w('w7', ['rldr','2'], ['nano','GND'], '#000000'), - w('w8', ['ldr','SIG'], ['nano','A1'], '#ffaa00'), + w('w7', ['rldr','2'], ['arduino-nano','GND'], '#000000'), + w('w8', ['ldr','SIG'], ['arduino-nano','A1'], '#ffaa00'), ], }, @@ -1114,7 +1114,7 @@ void loop() { id: 'esp32-pwm-led-rgb', title: 'ESP32 LEDC PWM RGB', description: 'ESP32 LEDC peripheral drives RGB LED with independent PWM channels.', - category: 'basics', difficulty: 'intermediate', + category: 'circuits', difficulty: 'intermediate', boardType: 'esp32', code: `// ESP32 LEDC PWM — RGB LED color cycling #define R_PIN 16 diff --git a/frontend/src/data/examples.ts b/frontend/src/data/examples.ts index b07f0983..4f8dd171 100644 --- a/frontend/src/data/examples.ts +++ b/frontend/src/data/examples.ts @@ -22,7 +22,7 @@ export interface ExampleProject { id: string; title: string; description: string; - category: 'basics' | 'sensors' | 'displays' | 'communication' | 'games' | 'robotics'; + category: 'basics' | 'sensors' | 'displays' | 'communication' | 'games' | 'robotics' | 'circuits'; difficulty: 'beginner' | 'intermediate' | 'advanced'; /** Target board — defaults to 'arduino-uno' if omitted. Ignored when boards[] is set. */ boardType?: 'arduino-uno' | 'arduino-nano' | 'arduino-mega' | 'raspberry-pi-pico' | 'esp32' | 'esp32-c3'; diff --git a/frontend/src/services/compilation.ts b/frontend/src/services/compilation.ts index f557986d..0ec1b9ef 100644 --- a/frontend/src/services/compilation.ts +++ b/frontend/src/services/compilation.ts @@ -31,7 +31,7 @@ export async function compileCode( const response = await axios.post( `${API_BASE}/compile/`, { files, board_fqbn: board }, - { withCredentials: true } + { withCredentials: true, timeout: 180000 } ); console.log('Compilation response status:', response.status); diff --git a/frontend/src/utils/loadExample.ts b/frontend/src/utils/loadExample.ts index 3a852f21..6f5a7af2 100644 --- a/frontend/src/utils/loadExample.ts +++ b/frontend/src/utils/loadExample.ts @@ -64,6 +64,7 @@ export async function loadExample( const { setComponents, setWires, setBoardType, activeBoardId, boards, addBoard, removeBoard, setActiveBoardId, + recalculateAllWirePositions, } = useSimulatorStore.getState(); if (example.boards && example.boards.length > 0) { @@ -138,6 +139,7 @@ export async function loadExample( waypoints: [], })), ); + recalculateAllWirePositions(); } else { // ── Single-board loading ───────────────────────────────────────────── const targetBoard = example.boardType || 'arduino-uno'; @@ -172,5 +174,6 @@ export async function loadExample( waypoints: [], })), ); + recalculateAllWirePositions(); } }