feat: add Arduino Mega 2560, Arduino, and ATmega328P simulator pages with SEO optimization

- Implemented ArduinoMegaSimulatorPage with detailed specifications, FAQs, and JSON-LD for SEO.
- Created ArduinoSimulatorPage featuring interactive components and a comprehensive FAQ section.
- Developed AtmegaSimulatorPage to simulate ATmega328P with full AVR8 emulation and included relevant FAQs.
- Introduced shared SEOPage.css for consistent styling across all simulator pages.
- Added useSEO utility for managing SEO metadata dynamically across pages.
pull/52/head
David Montero Crespo 2026-03-23 13:32:15 -03:00
parent 1cbeed1296
commit 24cce1174f
13 changed files with 1186 additions and 3 deletions

View File

@ -240,6 +240,10 @@
<nav style="margin-top:.75rem;">
<a href="/editor" style="color:#58a6ff;margin-right:1.5rem;">Editor</a>
<a href="/examples" style="color:#58a6ff;margin-right:1.5rem;">Examples</a>
<a href="/arduino-simulator" style="color:#58a6ff;margin-right:1.5rem;">Arduino Simulator</a>
<a href="/arduino-emulator" style="color:#58a6ff;margin-right:1.5rem;">Arduino Emulator</a>
<a href="/atmega328p-simulator" style="color:#58a6ff;margin-right:1.5rem;">ATmega328P Simulator</a>
<a href="/arduino-mega-simulator" style="color:#58a6ff;margin-right:1.5rem;">Arduino Mega Simulator</a>
<a href="https://github.com/davidmonterocrespo24/velxio" style="color:#58a6ff;margin-right:1.5rem;">GitHub</a>
<a href="https://discord.gg/rCScB9cG" style="color:#58a6ff;">Discord</a>
<a href="/docs/intro" style="color:#58a6ff;margin-right:1.5rem;">Documentation</a>
@ -297,8 +301,58 @@
<dt>Is Velxio a Wokwi alternative?</dt>
<dd>Yes. Velxio is a free, self-hosted alternative to Wokwi. It uses the same avr8js and wokwi-elements open-source libraries but runs on your own machine.</dd>
<dt>What boards are supported?</dt>
<dd>Arduino Uno (ATmega328p / AVR8) and Raspberry Pi Pico (RP2040). More boards are planned.</dd>
<dd>Arduino Uno (ATmega328p / AVR8), Arduino Nano, Arduino Mega 2560, Raspberry Pi Pico (RP2040), ESP32-C3 (RISC-V), and more. 17 boards in total.</dd>
</dl>
<!-- SEO landing pages — keyword content for crawlers -->
<section>
<h2>Free Online Arduino Simulator</h2>
<p>Velxio is a free online Arduino simulator with real AVR8 emulation at 16 MHz. Simulate Arduino code with 48+ interactive electronic components directly in your browser — no install, no account required. <a href="/arduino-simulator">Open Arduino Simulator →</a></p>
<ul>
<li>Arduino Uno (ATmega328P) simulation at 16 MHz</li>
<li>48+ visual components: LEDs, sensors, displays, servos</li>
<li>Serial Monitor with auto baud-rate detection</li>
<li>Multi-file sketch support (.ino, .h, .cpp)</li>
<li>Free and open-source (GNU AGPLv3)</li>
</ul>
</section>
<section>
<h2>Arduino Emulator — Real AVR8 &amp; RP2040 Emulation</h2>
<p>Velxio is a cycle-accurate Arduino emulator built on avr8js and rp2040js. Every AVR opcode is faithfully emulated at 16 MHz — the same silicon behavior as real hardware. <a href="/arduino-emulator">Open Arduino Emulator →</a></p>
<ul>
<li>All 135 AVR8 instructions emulated</li>
<li>Hardware timers (Timer0/1/2) with PWM, CTC, and overflow interrupts</li>
<li>10-bit ADC, full USART0 (TX/RX), SPI, I2C</li>
<li>RP2040 dual-core ARM Cortex-M0+ via rp2040js</li>
<li>RISC-V RV32IMC (ESP32-C3) emulation in browser</li>
</ul>
</section>
<section>
<h2>ATmega328P Simulator</h2>
<p>Simulate ATmega328P firmware exactly as it runs on Arduino Uno and Nano. Full AVR8 emulation: PORTB, PORTC, PORTD, Timer0/1/2, ADC, USART0, and all interrupt vectors. <a href="/atmega328p-simulator">Open ATmega328P Simulator →</a></p>
<ul>
<li>ATmega328P: 32 KB flash, 2 KB SRAM, 16 MHz</li>
<li>GPIO: PORTB (pins 813), PORTC (A0A5), PORTD (07)</li>
<li>Timer0 (8-bit), Timer1 (16-bit), Timer2 (8-bit) — all PWM modes</li>
<li>10-bit ADC, 6 analog channels (A0A5)</li>
<li>USART0 with configurable baud rate</li>
</ul>
</section>
<section>
<h2>Arduino Mega 2560 Simulator</h2>
<p>Simulate Arduino Mega 2560 (ATmega2560) code for free. 256 KB flash, 54 digital pins, 16 analog inputs, 4 hardware serial ports (Serial, Serial1, Serial2, Serial3), and 6 hardware timers. <a href="/arduino-mega-simulator">Open Mega 2560 Simulator →</a></p>
<ul>
<li>ATmega2560: 256 KB flash, 8 KB SRAM, 16 MHz</li>
<li>54 digital I/O pins (PORTA through PORTL)</li>
<li>16 analog input channels (A0A15), 10-bit ADC</li>
<li>4 hardware USART channels: Serial03</li>
<li>6 hardware timers: Timer05 (including three 16-bit)</li>
<li>15 PWM output pins</li>
</ul>
</section>
</main>
</div>
<script type="module" src="/src/main.tsx"></script>

View File

@ -95,11 +95,40 @@
<url>
<loc>https://velxio.dev/examples</loc>
<lastmod>2026-03-15</lastmod>
<lastmod>2026-03-23</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<!-- SEO keyword landing pages -->
<url>
<loc>https://velxio.dev/arduino-simulator</loc>
<lastmod>2026-03-23</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://velxio.dev/arduino-emulator</loc>
<lastmod>2026-03-23</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://velxio.dev/atmega328p-simulator</loc>
<lastmod>2026-03-23</lastmod>
<changefreq>monthly</changefreq>
<priority>0.85</priority>
</url>
<url>
<loc>https://velxio.dev/arduino-mega-simulator</loc>
<lastmod>2026-03-23</lastmod>
<changefreq>monthly</changefreq>
<priority>0.85</priority>
</url>
<url>
<loc>https://velxio.dev/login</loc>
<lastmod>2026-03-06</lastmod>

View File

@ -10,6 +10,10 @@ import { UserProfilePage } from './pages/UserProfilePage';
import { ProjectPage } from './pages/ProjectPage';
import { ProjectByIdPage } from './pages/ProjectByIdPage';
import { AdminPage } from './pages/AdminPage';
import { ArduinoSimulatorPage } from './pages/ArduinoSimulatorPage';
import { ArduinoEmulatorPage } from './pages/ArduinoEmulatorPage';
import { AtmegaSimulatorPage } from './pages/AtmegaSimulatorPage';
import { ArduinoMegaSimulatorPage } from './pages/ArduinoMegaSimulatorPage';
import { useAuthStore } from './store/useAuthStore';
import './App.css';
@ -31,6 +35,11 @@ function App() {
<Route path="/register" element={<RegisterPage />} />
<Route path="/admin" element={<AdminPage />} />
<Route path="/docs/:section" element={<DocsPage />} />
{/* SEO landing pages — keyword-targeted */}
<Route path="/arduino-simulator" element={<ArduinoSimulatorPage />} />
<Route path="/arduino-emulator" element={<ArduinoEmulatorPage />} />
<Route path="/atmega328p-simulator" element={<AtmegaSimulatorPage />} />
<Route path="/arduino-mega-simulator" element={<ArduinoMegaSimulatorPage />} />
{/* Canonical project URL by ID */}
<Route path="/project/:id" element={<ProjectByIdPage />} />
{/* Legacy slug route — redirects to /project/:id */}

View File

@ -0,0 +1,185 @@
/**
* /arduino-emulator SEO landing page
* Target keywords: "arduino emulator"
*/
import React from 'react';
import { Link } from 'react-router-dom';
import { AppHeader } from '../components/layout/AppHeader';
import { useSEO } from '../utils/useSEO';
import './SEOPage.css';
const FAQ_ITEMS = [
{
q: 'What is an Arduino emulator?',
a: 'An Arduino emulator reproduces the behavior of a physical Arduino microcontroller in software — CPU instruction execution, peripheral registers (GPIO, USART, ADC, timers, PWM), and interrupts — with no hardware required.',
},
{
q: 'How accurate is Velxio\'s Arduino emulation?',
a: 'Velxio uses avr8js, which provides cycle-accurate AVR8 instruction emulation. Every AVR opcode is faithfully emulated at 16 MHz, making it reliable for developing and debugging real firmware before flashing to hardware.',
},
{
q: 'Which Arduino boards can Velxio emulate?',
a: 'Arduino Uno (ATmega328P), Arduino Nano, Arduino Mega 2560 (ATmega2560), ATtiny85 (AVR), Raspberry Pi Pico (RP2040), and multiple ESP32/RISC-V boards. 17 boards across 5 CPU architectures.',
},
{
q: 'What peripherals are emulated?',
a: 'GPIO ports (PORTB, PORTC, PORTD), hardware timers (Timer0, Timer1, Timer2), 8/16-bit PWM, USART serial, 10-bit ADC (analog inputs), SPI, and I2C. All standard Arduino library functions work correctly.',
},
{
q: 'How is Velxio different from Wokwi?',
a: 'Velxio is fully self-hosted and open-source under GNU AGPLv3. It uses the same avr8js emulation library as Wokwi but runs entirely on your own machine — no cloud dependency, no registration, no subscription.',
},
];
const JSON_LD: object[] = [
{
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: 'Velxio Arduino Emulator',
applicationCategory: 'DeveloperApplication',
operatingSystem: 'Any (browser-based)',
description:
'Free, open-source Arduino emulator with cycle-accurate AVR8 emulation at 16 MHz. Emulate Arduino Uno, Nano, Mega and Raspberry Pi Pico in your browser — no cloud, no install.',
url: 'https://velxio.dev/arduino-emulator',
offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' },
author: { '@type': 'Person', name: 'David Montero Crespo' },
license: 'https://www.gnu.org/licenses/agpl-3.0.html',
},
{
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: FAQ_ITEMS.map(({ q, a }) => ({
'@type': 'Question',
name: q,
acceptedAnswer: { '@type': 'Answer', text: a },
})),
},
{
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: [
{ '@type': 'ListItem', position: 1, name: 'Velxio', item: 'https://velxio.dev/' },
{ '@type': 'ListItem', position: 2, name: 'Arduino Emulator', item: 'https://velxio.dev/arduino-emulator' },
],
},
];
export const ArduinoEmulatorPage: React.FC = () => {
useSEO({
title: 'Arduino Emulator — Real AVR8 & RP2040 Emulation, Free | Velxio',
description:
'Free, open-source Arduino emulator with cycle-accurate AVR8 emulation at 16 MHz. Emulate Arduino Uno, Nano, Mega and Raspberry Pi Pico in your browser — no cloud, no install.',
url: 'https://velxio.dev/arduino-emulator',
jsonLd: JSON_LD,
});
return (
<div className="seo-page">
<AppHeader />
<main>
{/* Hero */}
<section className="seo-hero">
<h1>
Arduino Emulator<br />
<span className="accent">Real AVR8 &amp; RP2040 Emulation, Free</span>
</h1>
<p className="subtitle">
Velxio is a cycle-accurate Arduino emulator running entirely in your browser. Every AVR opcode is faithfully
executed at 16 MHz the same silicon behavior as real hardware, without buying hardware.
</p>
<div className="seo-cta-group">
<Link to="/editor" className="seo-btn-primary">Open Emulator </Link>
<Link to="/docs/emulator" className="seo-btn-secondary">Emulation Details</Link>
</div>
<p className="seo-trust">Free &amp; open-source · Built on avr8js &amp; rp2040js · No signup required</p>
</section>
{/* Emulation accuracy */}
<section className="seo-section">
<h2>Emulation accuracy</h2>
<p className="lead">
Velxio uses <strong style={{ color: '#e6edf3' }}>avr8js</strong> for AVR8 and <strong style={{ color: '#e6edf3' }}>rp2040js</strong> for RP2040 open-source libraries developed by the Wokwi team that provide genuine hardware fidelity.
</p>
<div className="seo-grid">
<div className="seo-card">
<h3>AVR8 Instruction Set</h3>
<p>All 135 AVR instructions emulated including MUL, MULSU, FMUL, LPM, SPM, and all branch/skip instructions. 16 MHz clock.</p>
</div>
<div className="seo-card">
<h3>Hardware Timers</h3>
<p>Timer0, Timer1, Timer2 with prescaler support, overflow interrupts, and Output Compare enabling <code>delay()</code>, <code>millis()</code>, and PWM.</p>
</div>
<div className="seo-card">
<h3>USART Serial</h3>
<p>Full USART emulation with configurable baud rate and TX/RX interrupts. <code>Serial.print()</code> works exactly as on real Arduino hardware.</p>
</div>
<div className="seo-card">
<h3>10-bit ADC</h3>
<p>Analog-to-digital converter emulation with analog reference support. <code>analogRead()</code> returns accurate values from simulated sensors.</p>
</div>
<div className="seo-card">
<h3>RP2040 Dual-Core ARM</h3>
<p>Cortex-M0+ emulation via rp2040js. Runs Arduino-pico and PlatformIO sketches for Raspberry Pi Pico and Pico W.</p>
</div>
<div className="seo-card">
<h3>RISC-V (ESP32-C3)</h3>
<p>Browser-native RV32IMC emulation for ESP32-C3 no backend server required, compiled to WebAssembly, runs at 160 MHz.</p>
</div>
</div>
</section>
{/* Supported boards */}
<section className="seo-section">
<h2>Supported boards</h2>
<p className="lead">17 boards across 5 CPU architectures AVR, ARM Cortex-M0+, RISC-V, Xtensa LX6/LX7, and ARM Cortex-A53.</p>
<div className="seo-grid">
<div className="seo-card">
<h3>AVR8 avr8js</h3>
<p>Arduino Uno, Arduino Nano, Arduino Mega 2560, ATtiny85, Arduino Leonardo, Arduino Pro Mini.</p>
</div>
<div className="seo-card">
<h3>RP2040 rp2040js</h3>
<p>Raspberry Pi Pico, Raspberry Pi Pico W dual ARM Cortex-M0+ at 133 MHz.</p>
</div>
<div className="seo-card">
<h3>RISC-V Browser</h3>
<p>ESP32-C3 DevKit, XIAO ESP32-C3, ESP32-C3 SuperMini, CH32V003 RV32IMC at 160 MHz.</p>
</div>
<div className="seo-card">
<h3>Xtensa QEMU</h3>
<p>ESP32 DevKit V1, ESP32 DevKit C V4, ESP32-CAM, ESP32-S3 Xtensa LX6/LX7 at 240 MHz.</p>
</div>
</div>
</section>
{/* FAQ */}
<section className="seo-section">
<h2>Frequently Asked Questions</h2>
<dl className="seo-faq">
{FAQ_ITEMS.map(({ q, a }) => (
<React.Fragment key={q}>
<dt>{q}</dt>
<dd>{a}</dd>
</React.Fragment>
))}
</dl>
</section>
{/* Bottom CTA */}
<div className="seo-bottom">
<h2>Start emulating Arduino today</h2>
<p>Open the editor and execute your firmware against a real emulated CPU no hardware purchase, no cloud, no limits.</p>
<Link to="/editor" className="seo-btn-primary">Launch Emulator </Link>
<div className="seo-internal-links">
<Link to="/arduino-simulator">Arduino Simulator</Link>
<Link to="/atmega328p-simulator">ATmega328P Simulator</Link>
<Link to="/arduino-mega-simulator">Mega 2560 Simulator</Link>
<Link to="/docs/emulator">Emulator Architecture</Link>
<Link to="/examples">Example Projects</Link>
</div>
</div>
</main>
</div>
);
};

View File

@ -0,0 +1,186 @@
/**
* /arduino-mega-simulator SEO landing page
* Target keywords: "arduino mega", "mega 2560", "arduino mega 2560"
*/
import React from 'react';
import { Link } from 'react-router-dom';
import { AppHeader } from '../components/layout/AppHeader';
import { useSEO } from '../utils/useSEO';
import './SEOPage.css';
const FAQ_ITEMS = [
{
q: 'What is the Arduino Mega 2560?',
a: 'The Arduino Mega 2560 is a microcontroller board based on the ATmega2560. It offers 256 KB flash memory, 8 KB SRAM, 54 digital I/O pins (15 PWM), 16 analog inputs, and 4 hardware USART channels — making it the go-to board for large, complex Arduino projects.',
},
{
q: 'Can I simulate Arduino Mega 2560 code in my browser?',
a: 'Yes. Velxio provides full ATmega2560 AVR8 emulation. Select "Arduino Mega 2560" in the board picker, write your sketch, compile, and simulate — with all 54 digital pins and 16 analog inputs available.',
},
{
q: 'Is the Arduino Mega 2560 emulation accurate?',
a: 'Velxio uses avr8js for cycle-accurate AVR8 instruction emulation. The ATmega2560 shares the same AVR8 core as the ATmega328P but with extended memory, more ports (PORTAPORTL), and additional timers (Timer3, Timer4, Timer5) — all emulated.',
},
{
q: 'What additional features does the Mega have over Arduino Uno?',
a: 'Arduino Mega 2560 adds: 8× more flash (256 KB vs 32 KB), 4× more SRAM (8 KB vs 2 KB), 40 extra digital pins, 10 extra analog inputs, 3 extra hardware serial ports (Serial1, Serial2, Serial3), and 3 extra 16-bit timers (Timer3, Timer4, Timer5).',
},
{
q: 'Does the Mega simulator support multiple Serial ports?',
a: 'Yes. Serial (USART0), Serial1 (USART1), Serial2 (USART2), and Serial3 (USART3) are all emulated. Each appears in the Serial Monitor tab so you can monitor multi-serial communication projects.',
},
];
const JSON_LD: object[] = [
{
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: 'Arduino Mega 2560 Simulator — Velxio',
applicationCategory: 'DeveloperApplication',
operatingSystem: 'Any (browser-based)',
description:
'Free online Arduino Mega 2560 simulator. Emulate ATmega2560 with 256 KB flash, 54 digital pins, 16 analog inputs, and 4 serial ports — full AVR8 emulation in your browser.',
url: 'https://velxio.dev/arduino-mega-simulator',
offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' },
author: { '@type': 'Person', name: 'David Montero Crespo' },
license: 'https://www.gnu.org/licenses/agpl-3.0.html',
},
{
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: FAQ_ITEMS.map(({ q, a }) => ({
'@type': 'Question',
name: q,
acceptedAnswer: { '@type': 'Answer', text: a },
})),
},
{
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: [
{ '@type': 'ListItem', position: 1, name: 'Velxio', item: 'https://velxio.dev/' },
{ '@type': 'ListItem', position: 2, name: 'Arduino Mega 2560 Simulator', item: 'https://velxio.dev/arduino-mega-simulator' },
],
},
];
export const ArduinoMegaSimulatorPage: React.FC = () => {
useSEO({
title: 'Arduino Mega 2560 Simulator — Free Online AVR8 Emulator | Velxio',
description:
'Simulate Arduino Mega 2560 (ATmega2560) code for free in your browser. 256 KB flash, 54 digital pins, 16 analog inputs, 4 serial ports — full AVR8 emulation with 48+ components.',
url: 'https://velxio.dev/arduino-mega-simulator',
jsonLd: JSON_LD,
});
return (
<div className="seo-page">
<AppHeader />
<main>
{/* Hero */}
<section className="seo-hero">
<h1>
Arduino Mega 2560 Simulator<br />
<span className="accent">Free Online AVR8 Emulation</span>
</h1>
<p className="subtitle">
Simulate Arduino Mega 2560 sketches in your browser with full ATmega2560 emulation 256 KB flash, 54 digital
pins, 16 analog inputs, 4 serial ports, and 6 timers. Free and open-source.
</p>
<div className="seo-cta-group">
<Link to="/editor" className="seo-btn-primary">Open Mega 2560 Simulator </Link>
<Link to="/examples" className="seo-btn-secondary">Browse Examples</Link>
</div>
<p className="seo-trust">Free &amp; open-source · No signup required · Full ATmega2560 emulation</p>
</section>
{/* ATmega2560 specs */}
<section className="seo-section">
<h2>Arduino Mega 2560 full spec emulation</h2>
<p className="lead">
The ATmega2560 is the most capable AVR8 microcontroller in the Arduino lineup. Velxio emulates its complete
peripheral set so every Mega-specific feature works in the simulator.
</p>
<div className="seo-grid">
<div className="seo-card">
<h3>256 KB Flash</h3>
<p>8× more program storage than Arduino Uno. Run large sketches, complex state machines, and data-heavy applications without storage constraints.</p>
</div>
<div className="seo-card">
<h3>54 Digital Pins</h3>
<p>Full PORTA through PORTL emulation. 40 extra I/O pins compared to the Uno ideal for multiplexed displays, large button matrices, and multi-module projects.</p>
</div>
<div className="seo-card">
<h3>16 Analog Inputs</h3>
<p>10-bit ADC with 16 channels (A0A15). Connect multiple sensors, potentiometers, and analog components simultaneously in the simulation.</p>
</div>
<div className="seo-card">
<h3>4 Hardware Serial</h3>
<p>Serial (USART03) all emulated. Serial1, Serial2, Serial3 appear in the Serial Monitor test multi-device serial communication projects.</p>
</div>
<div className="seo-card">
<h3>6 Hardware Timers</h3>
<p>Timer0/1/2/3/4/5. Three extra 16-bit timers (Timer3, Timer4, Timer5) compared to Uno more PWM outputs and precise timing channels.</p>
</div>
<div className="seo-card">
<h3>15 PWM Outputs</h3>
<p>15 pins with hardware PWM support via analogWrite(). Ideal for motor control, servo arrays, LED dimming, and audio output projects.</p>
</div>
</div>
</section>
{/* Use cases */}
<section className="seo-section">
<h2>What the Mega 2560 is used for</h2>
<p className="lead">The Arduino Mega 2560 is the preferred board for complex makers projects. Simulate them all without hardware.</p>
<div className="seo-grid">
<div className="seo-card">
<h3>3D Printer Firmware</h3>
<p>Marlin and RAMPS 1.4 shields run on ATmega2560. Prototype and debug printer control logic in the simulator.</p>
</div>
<div className="seo-card">
<h3>CNC &amp; Robotics</h3>
<p>GRBL CNC controller and multi-servo robot arms benefit from the Mega's extra I/O pins and timers.</p>
</div>
<div className="seo-card">
<h3>Large LED Matrices</h3>
<p>Driving 8×8 or 16×16 LED matrices requires many pins. The Mega's 54 digital outputs make it ideal.</p>
</div>
<div className="seo-card">
<h3>Multi-Sensor Systems</h3>
<p>16 analog inputs allow simultaneous reading from temperature, pressure, humidity, and light sensors without multiplexing.</p>
</div>
</div>
</section>
{/* FAQ */}
<section className="seo-section">
<h2>Frequently Asked Questions</h2>
<dl className="seo-faq">
{FAQ_ITEMS.map(({ q, a }) => (
<React.Fragment key={q}>
<dt>{q}</dt>
<dd>{a}</dd>
</React.Fragment>
))}
</dl>
</section>
{/* Bottom CTA */}
<div className="seo-bottom">
<h2>Simulate your Arduino Mega project</h2>
<p>Select the Mega 2560 board in the editor and start simulating full ATmega2560 emulation, no hardware purchase needed.</p>
<Link to="/editor" className="seo-btn-primary">Launch Mega 2560 Simulator </Link>
<div className="seo-internal-links">
<Link to="/arduino-simulator">Arduino Simulator</Link>
<Link to="/arduino-emulator">Arduino Emulator</Link>
<Link to="/atmega328p-simulator">ATmega328P (Uno/Nano)</Link>
<Link to="/examples">Example Projects</Link>
<Link to="/docs/intro">Documentation</Link>
</div>
</div>
</main>
</div>
);
};

View File

@ -0,0 +1,185 @@
/**
* /arduino-simulator SEO landing page
* Target keywords: "arduino simulator", "arduino simulator free"
*/
import React from 'react';
import { Link } from 'react-router-dom';
import { AppHeader } from '../components/layout/AppHeader';
import { useSEO } from '../utils/useSEO';
import './SEOPage.css';
const FAQ_ITEMS = [
{
q: 'Is this Arduino simulator free?',
a: 'Yes. Velxio is completely free and open-source (GNU AGPLv3). No account, no payment, no cloud subscription — run it in your browser or self-host it with one Docker command.',
},
{
q: 'Does the Arduino simulator work without installing anything?',
a: 'The simulation engine runs entirely in your browser. Compiling code requires the arduino-cli backend, which you can run locally or via Docker. No IDE installation is needed.',
},
{
q: 'What Arduino boards can I simulate?',
a: 'Arduino Uno (ATmega328P), Arduino Nano, Arduino Mega 2560, ATtiny85, Raspberry Pi Pico (RP2040), ESP32-C3 (RISC-V), ESP32 (Xtensa via QEMU), and more — 17 boards across 5 CPU architectures.',
},
{
q: 'Can I simulate LEDs, sensors, and displays?',
a: 'Yes. Velxio includes 48+ interactive wokwi-elements: LEDs, resistors, buttons, servo motors, ultrasonic sensors, ILI9341 TFT displays, LCD, NeoPixel strips, buzzers, DHT22, and more.',
},
{
q: 'Is Velxio a Wokwi alternative?',
a: 'Yes. Velxio is a free, self-hosted alternative to Wokwi. It uses the same avr8js emulation library and wokwi-elements visual components, but runs entirely on your own machine with no cloud dependency.',
},
];
const JSON_LD: object[] = [
{
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: 'Velxio — Free Online Arduino Simulator',
applicationCategory: 'DeveloperApplication',
operatingSystem: 'Any (browser-based)',
description:
'Free online Arduino simulator with real AVR8 emulation at 16 MHz. Simulate Arduino code with 48+ interactive electronic components directly in your browser — no install, no account.',
url: 'https://velxio.dev/arduino-simulator',
offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' },
author: { '@type': 'Person', name: 'David Montero Crespo' },
license: 'https://www.gnu.org/licenses/agpl-3.0.html',
},
{
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: FAQ_ITEMS.map(({ q, a }) => ({
'@type': 'Question',
name: q,
acceptedAnswer: { '@type': 'Answer', text: a },
})),
},
{
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: [
{ '@type': 'ListItem', position: 1, name: 'Velxio', item: 'https://velxio.dev/' },
{ '@type': 'ListItem', position: 2, name: 'Arduino Simulator', item: 'https://velxio.dev/arduino-simulator' },
],
},
];
export const ArduinoSimulatorPage: React.FC = () => {
useSEO({
title: 'Free Online Arduino Simulator — Run Sketches in Your Browser | Velxio',
description:
'A free online Arduino simulator with real AVR8 emulation. Write and simulate Arduino code with LEDs, sensors, and 48+ components — no install, no account, instant results.',
url: 'https://velxio.dev/arduino-simulator',
jsonLd: JSON_LD,
});
return (
<div className="seo-page">
<AppHeader />
<main>
{/* Hero */}
<section className="seo-hero">
<h1>
Free Online Arduino Simulator<br />
<span className="accent">Run Sketches in Your Browser</span>
</h1>
<p className="subtitle">
Write Arduino code and simulate it instantly real AVR8 emulation at 16 MHz with 48+ interactive
electronic components. No install, no cloud, no account required.
</p>
<div className="seo-cta-group">
<Link to="/editor" className="seo-btn-primary">Open Arduino Simulator </Link>
<Link to="/examples" className="seo-btn-secondary">Browse Examples</Link>
</div>
<p className="seo-trust">Free &amp; open-source · No signup required · Runs 100% in your browser</p>
</section>
{/* What you can simulate */}
<section className="seo-section">
<h2>What can you simulate?</h2>
<p className="lead">
Velxio simulates Arduino programs with full AVR8 CPU accuracy including GPIO ports, hardware timers,
USART, ADC, PWM, SPI, and I2C. No approximations, no shortcuts.
</p>
<div className="seo-grid">
<div className="seo-card">
<h3>Arduino Uno &amp; Nano</h3>
<p>Full ATmega328P simulation at 16 MHz. PORTB, PORTC, PORTD register emulation. All 14 digital and 6 analog pins.</p>
</div>
<div className="seo-card">
<h3>Arduino Mega 2560</h3>
<p>ATmega2560 with 256 KB flash, 54 digital pins, 16 analog inputs, and 4 hardware USART channels.</p>
</div>
<div className="seo-card">
<h3>48+ Electronic Components</h3>
<p>LEDs, resistors, buttons, buzzer, servo, ultrasonic sensor, ILI9341 TFT, 16×2 LCD, NeoPixel, DHT22, and more.</p>
</div>
<div className="seo-card">
<h3>Serial Monitor</h3>
<p>Real-time TX/RX with auto baud-rate detection. Send commands and view <code>Serial.print()</code> output live.</p>
</div>
<div className="seo-card">
<h3>Multi-file Sketches</h3>
<p>Write .ino, .h, and .cpp files in a VS Code-style Monaco editor full multi-file Arduino project support.</p>
</div>
<div className="seo-card">
<h3>Library Manager</h3>
<p>Search and install any library from the full Arduino library index directly inside the simulator.</p>
</div>
</div>
</section>
{/* How it works */}
<section className="seo-section">
<h2>How the simulator works</h2>
<p className="lead">
Velxio uses <strong style={{ color: '#e6edf3' }}>avr8js</strong> the battle-tested open-source AVR8 emulation
library to execute your compiled firmware byte-for-byte, exactly as it would run on physical hardware.
</p>
<div className="seo-grid">
<div className="seo-card">
<h3>1. Write</h3>
<p>Write your Arduino sketch in the Monaco editor with C++ syntax highlighting and autocomplete.</p>
</div>
<div className="seo-card">
<h3>2. Compile</h3>
<p>Click Compile. arduino-cli produces a real .hex file the same output as the Arduino IDE.</p>
</div>
<div className="seo-card">
<h3>3. Simulate</h3>
<p>The .hex is loaded into the AVR8 emulator. Your program executes at 16 MHz and drives the visual components.</p>
</div>
</div>
</section>
{/* FAQ */}
<section className="seo-section">
<h2>Frequently Asked Questions</h2>
<dl className="seo-faq">
{FAQ_ITEMS.map(({ q, a }) => (
<React.Fragment key={q}>
<dt>{q}</dt>
<dd>{a}</dd>
</React.Fragment>
))}
</dl>
</section>
{/* Bottom CTA */}
<div className="seo-bottom">
<h2>Ready to simulate your Arduino?</h2>
<p>Open the editor and start coding in seconds no setup, no install, no account needed.</p>
<Link to="/editor" className="seo-btn-primary">Launch Arduino Simulator </Link>
<div className="seo-internal-links">
<Link to="/examples">Example Projects</Link>
<Link to="/docs/intro">Documentation</Link>
<Link to="/arduino-emulator">Arduino Emulator</Link>
<Link to="/atmega328p-simulator">ATmega328P Simulator</Link>
<Link to="/arduino-mega-simulator">Mega 2560 Simulator</Link>
</div>
</div>
</main>
</div>
);
};

View File

@ -0,0 +1,182 @@
/**
* /atmega328p-simulator SEO landing page
* Target keywords: "atmega328p", "atmega", "atmega 328p", "atmega328p arduino"
*/
import React from 'react';
import { Link } from 'react-router-dom';
import { AppHeader } from '../components/layout/AppHeader';
import { useSEO } from '../utils/useSEO';
import './SEOPage.css';
const FAQ_ITEMS = [
{
q: 'What is the ATmega328P?',
a: 'The ATmega328P is an 8-bit AVR microcontroller by Microchip (formerly Atmel). It is the heart of the Arduino Uno and Arduino Nano, running at 16 MHz with 32 KB flash, 2 KB SRAM, and 1 KB EEPROM.',
},
{
q: 'Can I simulate ATmega328P register-level code?',
a: 'Yes. Velxio\'s AVR8 emulation faithfully executes all ATmega328P registers: DDRB/C/D, PORTB/C/D, PINB/C/D, TCCR0/1/2, OCR0/1/2, UBRR, UDR, ADCL/ADCH, and all interrupt vectors — including direct register manipulation without the Arduino abstraction layer.',
},
{
q: 'Does it emulate ATmega328P timers correctly?',
a: 'Timer0 (8-bit), Timer1 (16-bit), and Timer2 (8-bit) are all emulated with full prescaler support, PWM modes, overflow interrupts, and Output Compare Match interrupts. millis(), delay(), analogWrite(), and tone() all work correctly.',
},
{
q: 'Can I use analogRead() and analogWrite() in the simulator?',
a: 'Yes. The 10-bit ADC (analogRead) and PWM output (analogWrite on pins 3, 5, 6, 9, 10, 11) are fully emulated. You can connect simulated sensors, potentiometers, and any wokwi-elements analog component.',
},
{
q: 'Can I simulate USART / Serial on ATmega328P?',
a: 'Yes. USART0 is fully emulated. Serial.begin(), Serial.print(), Serial.println(), and Serial.read() all work. The built-in Serial Monitor shows TX output and lets you send RX data to the running program.',
},
];
const JSON_LD: object[] = [
{
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: 'ATmega328P Simulator — Velxio',
applicationCategory: 'DeveloperApplication',
operatingSystem: 'Any (browser-based)',
description:
'Free browser-based ATmega328P simulator. Full AVR8 emulation at 16 MHz — PORTB, PORTC, PORTD, Timer0/1/2, ADC, USART, PWM — with 48+ interactive components. No install required.',
url: 'https://velxio.dev/atmega328p-simulator',
offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' },
author: { '@type': 'Person', name: 'David Montero Crespo' },
license: 'https://www.gnu.org/licenses/agpl-3.0.html',
},
{
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: FAQ_ITEMS.map(({ q, a }) => ({
'@type': 'Question',
name: q,
acceptedAnswer: { '@type': 'Answer', text: a },
})),
},
{
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: [
{ '@type': 'ListItem', position: 1, name: 'Velxio', item: 'https://velxio.dev/' },
{ '@type': 'ListItem', position: 2, name: 'ATmega328P Simulator', item: 'https://velxio.dev/atmega328p-simulator' },
],
},
];
export const AtmegaSimulatorPage: React.FC = () => {
useSEO({
title: 'ATmega328P Simulator — Free Browser-Based AVR8 Emulation | Velxio',
description:
'Simulate ATmega328P code in your browser. Full AVR8 emulation at 16 MHz — PORTB, PORTC, PORTD, Timer0/1/2, ADC, USART — with 48+ interactive components. Free & open-source.',
url: 'https://velxio.dev/atmega328p-simulator',
jsonLd: JSON_LD,
});
return (
<div className="seo-page">
<AppHeader />
<main>
{/* Hero */}
<section className="seo-hero">
<h1>
ATmega328P Simulator<br />
<span className="accent">Free AVR8 Emulation in Your Browser</span>
</h1>
<p className="subtitle">
Simulate ATmega328P firmware exactly as it runs on Arduino Uno and Nano real AVR8 instruction execution at
16 MHz with full GPIO, timer, ADC, and USART emulation. No hardware, no install.
</p>
<div className="seo-cta-group">
<Link to="/editor" className="seo-btn-primary">Open ATmega328P Simulator </Link>
<Link to="/docs/emulator" className="seo-btn-secondary">Technical Details</Link>
</div>
<p className="seo-trust">Free &amp; open-source · Genuine AVR8 emulation · Runs 100% in your browser</p>
</section>
{/* ATmega328P specs */}
<section className="seo-section">
<h2>ATmega328P specification fully emulated</h2>
<p className="lead">
Everything about the ATmega328P is emulated: registers, peripherals, interrupts, and timing. Write bare-metal
firmware or use the Arduino core library both work identically in the simulator.
</p>
<div className="seo-grid">
<div className="seo-card">
<h3>CPU Core</h3>
<p>AVR8 (8-bit RISC), 16 MHz, 135 instructions, 32 general-purpose registers, 2-stage pipeline.</p>
</div>
<div className="seo-card">
<h3>Flash Memory</h3>
<p>32 KB program flash. Upload any sketch compiled by arduino-cli. Supports self-programming via SPM instruction.</p>
</div>
<div className="seo-card">
<h3>GPIO Ports</h3>
<p>PORTB (pins 813), PORTC (A0A5), PORTD (07). DDR, PORT, PIN registers all emulated. Interrupt-on-change via PCINT.</p>
</div>
<div className="seo-card">
<h3>Timers 0 / 1 / 2</h3>
<p>8-bit Timer0 &amp; Timer2, 16-bit Timer1. All PWM modes. Prescaler 11024. CTC, Fast PWM, Phase-correct PWM.</p>
</div>
<div className="seo-card">
<h3>10-bit ADC</h3>
<p>6 analog input channels (A0A5). Single conversion and free-running modes. Analog voltage from simulated components.</p>
</div>
<div className="seo-card">
<h3>USART0</h3>
<p>Full duplex serial with configurable baud rate. TX, RX, and UDRE interrupts. Works with the built-in Serial Monitor.</p>
</div>
</div>
</section>
{/* Compatible boards */}
<section className="seo-section">
<h2>ATmega328P boards in Velxio</h2>
<p className="lead">The ATmega328P powers several popular Arduino boards all selectable in Velxio.</p>
<div className="seo-grid">
<div className="seo-card">
<h3>Arduino Uno R3</h3>
<p>The classic board. 14 digital I/O pins (6 PWM), 6 analog inputs, 32 KB flash. The most widely used ATmega328P board.</p>
</div>
<div className="seo-card">
<h3>Arduino Nano</h3>
<p>Same ATmega328P in a compact 45×18mm form factor with mini-USB. Same pin count as Uno.</p>
</div>
<div className="seo-card">
<h3>Arduino Pro Mini</h3>
<p>Bare-bones ATmega328P without USB chip. Available at 3.3 V/8 MHz and 5 V/16 MHz variants.</p>
</div>
</div>
</section>
{/* FAQ */}
<section className="seo-section">
<h2>Frequently Asked Questions</h2>
<dl className="seo-faq">
{FAQ_ITEMS.map(({ q, a }) => (
<React.Fragment key={q}>
<dt>{q}</dt>
<dd>{a}</dd>
</React.Fragment>
))}
</dl>
</section>
{/* Bottom CTA */}
<div className="seo-bottom">
<h2>Simulate your ATmega328P code now</h2>
<p>Open the editor, paste your sketch, and click Simulate no setup, no hardware purchase required.</p>
<Link to="/editor" className="seo-btn-primary">Launch ATmega328P Simulator </Link>
<div className="seo-internal-links">
<Link to="/arduino-simulator">Arduino Simulator</Link>
<Link to="/arduino-emulator">Arduino Emulator</Link>
<Link to="/arduino-mega-simulator">Arduino Mega 2560</Link>
<Link to="/examples">Example Sketches</Link>
<Link to="/docs/emulator">Emulator Architecture</Link>
</div>
</div>
</main>
</div>
);
};

View File

@ -3,6 +3,7 @@
*/
import React, { useRef, useState, useCallback, useEffect, lazy, Suspense } from 'react';
import { useSEO } from '../utils/useSEO';
import { CodeEditor } from '../components/editor/CodeEditor';
import { EditorToolbar } from '../components/editor/EditorToolbar';
import { FileTabs } from '../components/editor/FileTabs';
@ -45,6 +46,13 @@ const resizeHandleStyle: React.CSSProperties = {
};
export const EditorPage: React.FC = () => {
useSEO({
title: 'Arduino Simulator Online Editor — Velxio',
description:
'Write, compile and simulate Arduino code directly in your browser. Real AVR8 emulation at 16 MHz with 48+ interactive components. Free and open-source.',
url: 'https://velxio.dev/editor',
});
const [editorWidthPct, setEditorWidthPct] = useState(45);
const containerRef = useRef<HTMLDivElement>(null);
const resizingRef = useRef(false);

View File

@ -8,6 +8,7 @@ import React from 'react';
import { useNavigate } from 'react-router-dom';
import { ExamplesGallery } from '../components/examples/ExamplesGallery';
import { AppHeader } from '../components/layout/AppHeader';
import { useSEO } from '../utils/useSEO';
import { useEditorStore } from '../store/useEditorStore';
import { useSimulatorStore } from '../store/useSimulatorStore';
import { useVfsStore } from '../store/useVfsStore';
@ -16,6 +17,13 @@ import type { ExampleProject } from '../data/examples';
import type { BoardKind } from '../types/board';
export const ExamplesPage: React.FC = () => {
useSEO({
title: 'Arduino Simulator Examples — Run 18+ Sketches Instantly | Velxio',
description:
'Explore 18+ interactive Arduino examples with LEDs, sensors, displays, and games. Runs entirely in your browser — free, no install, no account required.',
url: 'https://velxio.dev/examples',
});
const navigate = useNavigate();
const { setCode } = useEditorStore();
const { setComponents, setWires, setBoardType, activeBoardId, boards, addBoard, removeBoard, setActiveBoardId } = useSimulatorStore();

View File

@ -351,6 +351,15 @@
transform: scale(1.02);
}
/* Trust line under CTA buttons */
.hero-trust-line {
margin: 6px 0 0;
font-size: 11.5px;
font-weight: 400;
color: #48484a;
letter-spacing: 0.02em;
}
/* Specs strip */
.hero-specs {
margin: 0;

View File

@ -2,6 +2,7 @@ import { useState, useRef, useEffect } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { useAuthStore } from '../store/useAuthStore';
import { AppHeader } from '../components/layout/AppHeader';
import { useSEO } from '../utils/useSEO';
import raspberryPi3Svg from '../assets/Raspberry_Pi_3_illustration.svg';
import './LandingPage.css';
@ -434,6 +435,13 @@ const UserMenu: React.FC = () => {
/* ── Component ────────────────────────────────────────── */
export const LandingPage: React.FC = () => {
useSEO({
title: 'Velxio — Free Local Arduino Emulator | AVR8 · RP2040 · 48+ Components',
description:
'Velxio is a free, open-source Arduino emulator that runs entirely in your browser. Real AVR8 emulation at 16 MHz, 48+ electronic components, Monaco Editor, Serial Monitor, and Library Manager — no cloud, no latency.',
url: 'https://velxio.dev/',
});
return (
<div className="landing">
<AppHeader />
@ -451,13 +459,14 @@ export const LandingPage: React.FC = () => {
<div className="hero-ctas">
<Link to="/editor" className="cta-primary">
<IcoZap />
Launch Editor
Try Simulator Free
</Link>
<a href={GITHUB_URL} target="_blank" rel="noopener noreferrer" className="cta-secondary">
<IcoGitHub />
View on GitHub
</a>
</div>
<p className="hero-trust-line">No signup required · Runs 100% in your browser · Free &amp; open-source</p>
</div>
<div className="hero-right">

View File

@ -0,0 +1,231 @@
/* ── SEOPage.css — Shared layout for keyword-targeted landing pages ── */
.seo-page {
min-height: 100vh;
background: #0d0d0f;
color: #e6edf3;
font-family: 'Inter', system-ui, -apple-system, sans-serif;
-webkit-font-smoothing: antialiased;
}
/* ── Hero ─────────────────────────────────────────────── */
.seo-hero {
max-width: 820px;
margin: 0 auto;
padding: 72px 2rem 56px;
text-align: center;
}
.seo-hero h1 {
font-size: clamp(1.75rem, 4.5vw, 2.75rem);
font-weight: 700;
line-height: 1.15;
color: #ffffff;
margin: 0 0 1rem;
letter-spacing: -0.5px;
}
.seo-hero h1 .accent {
color: #007acc;
}
.seo-hero .subtitle {
font-size: 1.1rem;
color: #8b949e;
max-width: 600px;
margin: 0 auto 2rem;
line-height: 1.65;
}
.seo-cta-group {
display: flex;
gap: 12px;
justify-content: center;
flex-wrap: wrap;
}
/* Reuse brand CTA style consistent with LandingPage */
.seo-btn-primary {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 12px 26px;
background: #007acc;
color: #fff;
text-decoration: none;
font-size: 15px;
font-weight: 500;
border-radius: 9999px;
transition: filter 0.2s, transform 0.2s;
border: none;
cursor: pointer;
letter-spacing: -0.1px;
}
.seo-btn-primary:hover {
filter: brightness(1.14);
transform: scale(1.02);
}
.seo-btn-secondary {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 12px 26px;
background: #2c2c2e;
color: #e6edf3;
text-decoration: none;
font-size: 15px;
font-weight: 500;
border-radius: 9999px;
transition: background 0.2s, transform 0.2s;
border: none;
cursor: pointer;
}
.seo-btn-secondary:hover {
background: #3a3a3c;
transform: scale(1.02);
}
.seo-trust {
font-size: 0.78rem;
color: #484848;
margin-top: 1rem;
letter-spacing: 0.02em;
}
/* ── Section wrapper ──────────────────────────────────── */
.seo-section {
max-width: 820px;
margin: 0 auto;
padding: 48px 2rem;
border-top: 1px solid #1c1c1e;
}
.seo-section h2 {
font-size: 1.4rem;
font-weight: 700;
color: #fff;
margin: 0 0 0.5rem;
letter-spacing: -0.3px;
}
.seo-section .lead {
color: #8b949e;
font-size: 0.95rem;
margin: 0 0 1.75rem;
line-height: 1.6;
}
/* ── Feature grid ─────────────────────────────────────── */
.seo-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
gap: 12px;
}
.seo-card {
background: #121214;
border: 1px solid #1c1c1e;
border-radius: 10px;
padding: 1.2rem 1.25rem;
}
.seo-card h3 {
font-size: 0.88rem;
font-weight: 600;
color: #007acc;
margin: 0 0 0.35rem;
letter-spacing: -0.1px;
}
.seo-card p {
font-size: 0.83rem;
color: #8b949e;
margin: 0;
line-height: 1.55;
}
/* ── FAQ ──────────────────────────────────────────────── */
.seo-faq {
display: flex;
flex-direction: column;
gap: 0;
}
.seo-faq dt {
font-weight: 600;
color: #e6edf3;
font-size: 0.9rem;
margin: 1.2rem 0 0.25rem;
}
.seo-faq dd {
margin: 0;
color: #8b949e;
font-size: 0.875rem;
line-height: 1.6;
padding-left: 1rem;
border-left: 2px solid #1c1c1e;
}
/* ── Bottom CTA ───────────────────────────────────────── */
.seo-bottom {
text-align: center;
padding: 64px 2rem 72px;
border-top: 1px solid #1c1c1e;
max-width: 600px;
margin: 0 auto;
}
.seo-bottom h2 {
font-size: 1.55rem;
font-weight: 700;
color: #fff;
margin: 0 0 0.75rem;
letter-spacing: -0.3px;
}
.seo-bottom p {
color: #8b949e;
font-size: 0.95rem;
margin: 0 0 2rem;
line-height: 1.6;
}
/* ── Internal links ───────────────────────────────────── */
.seo-internal-links {
display: flex;
gap: 1.25rem;
justify-content: center;
flex-wrap: wrap;
margin-top: 2rem;
font-size: 0.82rem;
}
.seo-internal-links a {
color: #007acc;
text-decoration: none;
transition: color 0.15s;
}
.seo-internal-links a:hover {
color: #3b9ae8;
text-decoration: underline;
}
/* ── Responsive ───────────────────────────────────────── */
@media (max-width: 600px) {
.seo-hero {
padding: 48px 1.25rem 40px;
}
.seo-section {
padding: 36px 1.25rem;
}
.seo-grid {
grid-template-columns: 1fr;
}
}

View File

@ -0,0 +1,88 @@
import { useEffect, useRef } from 'react';
export interface SEOMeta {
title: string;
description: string;
url: string;
ogImage?: string;
/** Module-level constant: injected once on mount, removed on unmount. */
jsonLd?: object | object[];
}
function qs(selector: string): HTMLMetaElement | null {
return document.querySelector(selector) as HTMLMetaElement | null;
}
/**
* Updates document.title, meta description, OG/Twitter tags, and canonical
* to reflect the current page. Restores originals on unmount.
*
* jsonLd (if provided) is injected as a <script type="application/ld+json">
* once on mount and removed on unmount. Pass a module-level constant to avoid
* unnecessary re-injection.
*/
export function useSEO({ title, description, url, ogImage, jsonLd }: SEOMeta) {
const scriptRef = useRef<HTMLScriptElement | null>(null);
useEffect(() => {
const origTitle = document.title;
const descEl = qs('meta[name="description"]');
const ogTitleEl = qs('meta[property="og:title"]');
const ogDescEl = qs('meta[property="og:description"]');
const ogUrlEl = qs('meta[property="og:url"]');
const ogImgEl = qs('meta[property="og:image"]');
const twTitleEl = qs('meta[name="twitter:title"]');
const twDescEl = qs('meta[name="twitter:description"]');
const canonicalEl = document.querySelector('link[rel="canonical"]') as HTMLLinkElement | null;
const get = (el: HTMLMetaElement | null) => el?.getAttribute('content') ?? '';
const set = (el: HTMLMetaElement | null, v: string) => el?.setAttribute('content', v);
const origDesc = get(descEl);
const origOgTitle = get(ogTitleEl);
const origOgDesc = get(ogDescEl);
const origOgUrl = get(ogUrlEl);
const origOgImg = get(ogImgEl);
const origTwTitle = get(twTitleEl);
const origTwDesc = get(twDescEl);
const origCanonical = canonicalEl?.getAttribute('href') ?? '';
// Apply
document.title = title;
set(descEl, description);
set(ogTitleEl, title);
set(ogDescEl, description);
set(ogUrlEl, url);
if (ogImage) set(ogImgEl, ogImage);
set(twTitleEl, title);
set(twDescEl, description);
canonicalEl?.setAttribute('href', url);
// Inject JSON-LD once (module-level constants don't change)
if (jsonLd && !scriptRef.current) {
const script = document.createElement('script');
script.type = 'application/ld+json';
script.setAttribute('data-seo-page', '1');
script.textContent = JSON.stringify(Array.isArray(jsonLd) ? jsonLd : [jsonLd]);
document.head.appendChild(script);
scriptRef.current = script;
}
return () => {
document.title = origTitle;
set(descEl, origDesc);
set(ogTitleEl, origOgTitle);
set(ogDescEl, origOgDesc);
set(ogUrlEl, origOgUrl);
if (ogImage) set(ogImgEl, origOgImg);
set(twTitleEl, origTwTitle);
set(twDescEl, origTwDesc);
canonicalEl?.setAttribute('href', origCanonical);
if (scriptRef.current) {
document.head.removeChild(scriptRef.current);
scriptRef.current = null;
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [title, description, url, ogImage]);
}