diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml
index 1b3a7cc..945e762 100644
--- a/.github/workflows/docker-publish.yml
+++ b/.github/workflows/docker-publish.yml
@@ -56,6 +56,12 @@ jobs:
cache-from: type=gha
cache-to: type=gha,mode=max
+ - name: Ping search engines with sitemap
+ if: success()
+ run: |
+ curl -s "https://www.google.com/ping?sitemap=https%3A%2F%2Fvelxio.dev%2Fsitemap.xml" -o /dev/null -w "Google ping: %{http_code}\n"
+ curl -s "https://www.bing.com/ping?sitemap=https%3A%2F%2Fvelxio.dev%2Fsitemap.xml" -o /dev/null -w "Bing ping: %{http_code}\n"
+
- name: Update Docker Hub description
uses: peter-evans/dockerhub-description@v4
with:
diff --git a/frontend/package.json b/frontend/package.json
index 3add610..849420d 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -8,9 +8,10 @@
"generate:metadata": "cd .. && npx tsx scripts/generate-component-metadata.ts",
"generate:favicons": "node ../scripts/generate-favicons.mjs",
"generate:og-image": "node ../scripts/generate-og-image.mjs",
+ "generate:sitemap": "cd .. && npx tsx scripts/generate-sitemap.ts",
"dev": "npm run generate:metadata && vite",
- "build": "npm run generate:metadata && tsc -b && vite build",
- "build:docker": "vite build",
+ "build": "npm run generate:metadata && npm run generate:sitemap && tsc -b && vite build",
+ "build:docker": "npm run generate:sitemap && vite build",
"lint": "eslint .",
"preview": "vite preview",
"test": "vitest run",
diff --git a/frontend/public/sitemap.xml b/frontend/public/sitemap.xml
index 8448192..03c1201 100644
--- a/frontend/public/sitemap.xml
+++ b/frontend/public/sitemap.xml
@@ -2,192 +2,162 @@
-
https://velxio.dev/
2026-03-23
weekly
- 1.0
+ 1
-
https://velxio.dev/editor
2026-03-23
weekly
0.9
-
https://velxio.dev/examples
2026-03-23
weekly
0.8
-
-
https://velxio.dev/docs
2026-03-23
monthly
0.8
-
https://velxio.dev/docs/intro
2026-03-23
monthly
0.8
-
https://velxio.dev/docs/getting-started
2026-03-23
monthly
0.8
-
https://velxio.dev/docs/emulator
2026-03-23
monthly
0.7
-
https://velxio.dev/docs/esp32-emulation
2026-03-23
monthly
0.7
-
https://velxio.dev/docs/riscv-emulation
2026-03-23
monthly
0.7
-
https://velxio.dev/docs/rp2040-emulation
2026-03-23
monthly
0.7
-
https://velxio.dev/docs/raspberry-pi3-emulation
2026-03-23
monthly
0.7
-
https://velxio.dev/docs/components
2026-03-23
monthly
0.7
-
https://velxio.dev/docs/architecture
2026-03-23
monthly
0.7
-
https://velxio.dev/docs/wokwi-libs
2026-03-23
monthly
0.7
-
https://velxio.dev/docs/mcp
2026-03-23
monthly
0.7
-
https://velxio.dev/docs/setup
2026-03-23
monthly
0.6
-
https://velxio.dev/docs/roadmap
2026-03-23
monthly
0.6
-
-
https://velxio.dev/arduino-simulator
2026-03-23
monthly
0.9
-
https://velxio.dev/arduino-emulator
2026-03-23
monthly
0.9
-
https://velxio.dev/atmega328p-simulator
2026-03-23
monthly
0.85
-
https://velxio.dev/arduino-mega-simulator
2026-03-23
monthly
0.85
-
https://velxio.dev/esp32-simulator
2026-03-23
monthly
0.9
-
https://velxio.dev/esp32-s3-simulator
2026-03-23
monthly
0.85
-
https://velxio.dev/esp32-c3-simulator
2026-03-23
monthly
0.85
-
https://velxio.dev/raspberry-pi-pico-simulator
2026-03-23
monthly
0.9
-
https://velxio.dev/raspberry-pi-simulator
2026-03-23
monthly
0.85
-
-
https://velxio.dev/v2
2026-03-23
@@ -195,6 +165,4 @@
0.9
-
-
diff --git a/frontend/src/pages/Velxio2Page.css b/frontend/src/pages/Velxio2Page.css
index fca0133..6c8c80b 100644
--- a/frontend/src/pages/Velxio2Page.css
+++ b/frontend/src/pages/Velxio2Page.css
@@ -233,6 +233,64 @@
background: #484848;
}
+/* ── Repository cards ────────────────────────────────── */
+.v2-repos {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
+ gap: 10px;
+}
+
+.v2-repo-card {
+ display: flex;
+ align-items: flex-start;
+ gap: 12px;
+ background: #121214;
+ border: 1px solid #1c1c1e;
+ border-radius: 10px;
+ padding: 1rem 1.15rem;
+ text-decoration: none;
+ transition: border-color 0.2s, transform 0.15s;
+}
+
+.v2-repo-card:hover {
+ border-color: #333;
+ transform: translateY(-1px);
+}
+
+.v2-repo-card > svg {
+ flex-shrink: 0;
+ margin-top: 2px;
+ color: #8b949e;
+ fill: #8b949e;
+}
+
+.v2-repo-card h3 {
+ font-size: 0.85rem;
+ font-weight: 600;
+ color: #e6edf3;
+ margin: 0 0 3px;
+}
+
+.v2-repo-card p {
+ font-size: 0.78rem;
+ color: #8b949e;
+ margin: 0;
+ line-height: 1.5;
+}
+
+.v2-repo-card--primary {
+ border-color: rgba(0, 122, 204, 0.3);
+ background: rgba(0, 122, 204, 0.06);
+}
+
+.v2-repo-card--primary:hover {
+ border-color: #007acc;
+}
+
+.v2-repo-card--primary h3 {
+ color: #007acc;
+}
+
/* ── Bottom community ────────────────────────────────── */
.v2-bottom-community {
display: flex;
diff --git a/frontend/src/pages/Velxio2Page.tsx b/frontend/src/pages/Velxio2Page.tsx
index 24dfb5f..3cf416b 100644
--- a/frontend/src/pages/Velxio2Page.tsx
+++ b/frontend/src/pages/Velxio2Page.tsx
@@ -118,7 +118,7 @@ const JSON_LD: object[] = [
operatingSystem: 'Any (browser-based)',
softwareVersion: '2.0.0',
description:
- 'Velxio 2.0 — a free, open-source multi-board embedded systems simulator. 19 boards, 5 CPU architectures, QEMU-based ESP32 emulation, sensor simulation, 68+ examples. Runs in your browser.',
+ 'Velxio 2.0 — simulate Arduino, ESP32, Raspberry Pi Pico, and Raspberry Pi 3 in your browser. 19 boards, 68+ examples, realistic sensor simulation. Free and open-source.',
url: 'https://velxio.dev/v2',
offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' },
author: { '@type': 'Person', name: 'David Montero Crespo' },
@@ -236,7 +236,7 @@ export const Velxio2Page: React.FC = () => {
useSEO({
title: 'Velxio 2.0 — Multi-Board Embedded Simulator | ESP32, Raspberry Pi, Arduino, RISC-V',
description:
- 'Velxio 2.0 is here. 19 boards, 5 CPU architectures, QEMU-based ESP32 emulation, realistic sensor simulation, 68+ examples. A free, open-source multi-platform embedded systems simulator.',
+ 'Velxio 2.0 is here. Simulate Arduino, ESP32, Raspberry Pi Pico, and Raspberry Pi 3 in your browser. 19 boards, 68+ examples, realistic sensor simulation. Free and open-source.',
url: 'https://velxio.dev/v2',
jsonLd: JSON_LD,
});
@@ -255,9 +255,9 @@ export const Velxio2Page: React.FC = () => {
Multi-Platform Embedded Simulator
- 19 boards across 5 CPU architectures — AVR8, RP2040, RISC-V, Xtensa, and ARM Linux.
- QEMU-based ESP32 emulation, realistic sensor simulation, 68+ ready-to-run examples.
- Free, open-source, runs in your browser.
+ Simulate Arduino, ESP32, Raspberry Pi Pico, and Raspberry Pi 3 in your browser.
+ 19 boards, 68+ ready-to-run examples, realistic sensor simulation.
+ Free, open-source, no install needed.
@@ -479,6 +479,72 @@ export const Velxio2Page: React.FC = () => {
+ {/* ── Open-source libraries ── */}
+
+ Built on open-source
+
+ Velxio is powered by these open-source projects. Without them, none of this would be possible.
+
+
+
+
+
+
avr8js
+
AVR8 CPU emulator in JavaScript — powers Arduino Uno, Nano, Mega simulation
+
+
+
+
+
+
rp2040js
+
RP2040 emulator — powers Raspberry Pi Pico and Pico W simulation
+
+
+
+
+
+
wokwi-elements
+
Web Components for electronic parts — LEDs, buttons, sensors, displays, and more
+
+
+
+
+
+
wokwi-boards
+
SVG board definitions for Arduino, ESP32, Raspberry Pi Pico, and other boards
+
+
+
+
+
+
QEMU (lcgamboa fork)
+
QEMU fork with ESP32 Xtensa LX6/LX7 emulation support
+
+
+
+
+
+
QEMU (Espressif)
+
Official Espressif QEMU fork for ESP32 development and testing
+
+
+
+
+
+
wokwi-features
+
Feature tracking and component specifications for the Wokwi ecosystem
+
+
+
+
+
+
Velxio
+
This project — free, open-source multi-board embedded simulator
+
+
+
+
+
{/* ── Bottom CTA ── */}
Try Velxio 2.0 now
diff --git a/frontend/src/seoRoutes.ts b/frontend/src/seoRoutes.ts
new file mode 100644
index 0000000..42d282a
--- /dev/null
+++ b/frontend/src/seoRoutes.ts
@@ -0,0 +1,59 @@
+/**
+ * Single source of truth for all public, indexable routes.
+ * Used by:
+ * 1. scripts/generate-sitemap.ts → builds sitemap.xml at build time
+ * 2. Any component that needs the canonical URL list
+ *
+ * Routes with `noindex: true` are excluded from the sitemap.
+ */
+
+export interface SeoRoute {
+ path: string;
+ /** 0.0 – 1.0 (default 0.5) */
+ priority?: number;
+ changefreq?: 'daily' | 'weekly' | 'monthly' | 'yearly';
+ /** If true, excluded from sitemap */
+ noindex?: boolean;
+}
+
+export const SEO_ROUTES: SeoRoute[] = [
+ // ── Main pages
+ { path: '/', priority: 1.0, changefreq: 'weekly' },
+ { path: '/editor', priority: 0.9, changefreq: 'weekly' },
+ { path: '/examples', priority: 0.8, changefreq: 'weekly' },
+
+ // ── Documentation
+ { path: '/docs', priority: 0.8, changefreq: 'monthly' },
+ { path: '/docs/intro', priority: 0.8, changefreq: 'monthly' },
+ { path: '/docs/getting-started', priority: 0.8, changefreq: 'monthly' },
+ { path: '/docs/emulator', priority: 0.7, changefreq: 'monthly' },
+ { path: '/docs/esp32-emulation', priority: 0.7, changefreq: 'monthly' },
+ { path: '/docs/riscv-emulation', priority: 0.7, changefreq: 'monthly' },
+ { path: '/docs/rp2040-emulation', priority: 0.7, changefreq: 'monthly' },
+ { path: '/docs/raspberry-pi3-emulation', priority: 0.7, changefreq: 'monthly' },
+ { path: '/docs/components', priority: 0.7, changefreq: 'monthly' },
+ { path: '/docs/architecture', priority: 0.7, changefreq: 'monthly' },
+ { path: '/docs/wokwi-libs', priority: 0.7, changefreq: 'monthly' },
+ { path: '/docs/mcp', priority: 0.7, changefreq: 'monthly' },
+ { path: '/docs/setup', priority: 0.6, changefreq: 'monthly' },
+ { path: '/docs/roadmap', priority: 0.6, changefreq: 'monthly' },
+
+ // ── SEO keyword landing pages
+ { path: '/arduino-simulator', priority: 0.9, changefreq: 'monthly' },
+ { path: '/arduino-emulator', priority: 0.9, changefreq: 'monthly' },
+ { path: '/atmega328p-simulator', priority: 0.85, changefreq: 'monthly' },
+ { path: '/arduino-mega-simulator', priority: 0.85, changefreq: 'monthly' },
+ { path: '/esp32-simulator', priority: 0.9, changefreq: 'monthly' },
+ { path: '/esp32-s3-simulator', priority: 0.85, changefreq: 'monthly' },
+ { path: '/esp32-c3-simulator', priority: 0.85, changefreq: 'monthly' },
+ { path: '/raspberry-pi-pico-simulator', priority: 0.9, changefreq: 'monthly' },
+ { path: '/raspberry-pi-simulator', priority: 0.85, changefreq: 'monthly' },
+
+ // ── Release pages
+ { path: '/v2', priority: 0.9, changefreq: 'monthly' },
+
+ // ── Auth / admin (noindex)
+ { path: '/login', noindex: true },
+ { path: '/register', noindex: true },
+ { path: '/admin', noindex: true },
+];
diff --git a/scripts/generate-sitemap.ts b/scripts/generate-sitemap.ts
new file mode 100644
index 0000000..3c7c6c1
--- /dev/null
+++ b/scripts/generate-sitemap.ts
@@ -0,0 +1,59 @@
+/**
+ * Auto-generates frontend/public/sitemap.xml from seoRoutes.ts
+ * Run: npx tsx scripts/generate-sitemap.ts
+ * Integrated into: npm run build (via generate:sitemap)
+ */
+
+import { writeFileSync } from 'fs';
+import { resolve } from 'path';
+
+// Import the single source of truth
+import { SEO_ROUTES } from '../frontend/src/seoRoutes';
+
+const DOMAIN = 'https://velxio.dev';
+const TODAY = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
+
+const indexableRoutes = SEO_ROUTES.filter((r) => !r.noindex);
+
+const xml = `
+
+${indexableRoutes
+ .map(
+ (r) => `
+
+ ${DOMAIN}${r.path}
+ ${TODAY}
+ ${r.changefreq ?? 'monthly'}
+ ${r.priority ?? 0.5}
+ `
+ )
+ .join('')}
+
+
+`;
+
+const outPath = resolve(__dirname, '../frontend/public/sitemap.xml');
+writeFileSync(outPath, xml.trimStart(), 'utf-8');
+console.log(`sitemap.xml generated → ${indexableRoutes.length} URLs (${TODAY})`);
+
+// Also ping Google & Bing sitemap endpoints (non-blocking, best-effort)
+const SITEMAP_URL = `${DOMAIN}/sitemap.xml`;
+const PING_URLS = [
+ `https://www.google.com/ping?sitemap=${encodeURIComponent(SITEMAP_URL)}`,
+ `https://www.bing.com/ping?sitemap=${encodeURIComponent(SITEMAP_URL)}`,
+];
+
+if (process.argv.includes('--ping')) {
+ console.log('Pinging search engines...');
+ Promise.allSettled(
+ PING_URLS.map(async (url) => {
+ try {
+ const res = await fetch(url);
+ console.log(` ${res.ok ? 'OK' : 'FAIL'} ${url.split('?')[0]}`);
+ } catch (e: any) {
+ console.log(` FAIL ${url.split('?')[0]}: ${e.message}`);
+ }
+ })
+ );
+}