diff --git a/CLAUDE.md b/CLAUDE.md
index 2063761..19f51c0 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -243,6 +243,14 @@ Wire positions auto-update when components move via `updateWirePositions()`.
- [frontend/src/pages/UserProfilePage.tsx](frontend/src/pages/UserProfilePage.tsx) - Profile with project grid
- [frontend/src/pages/ProjectPage.tsx](frontend/src/pages/ProjectPage.tsx) - Loads project into editor
+### Frontend - SEO & Public Files
+- `frontend/index.html` — Full SEO meta tags, OG, Twitter Card, JSON-LD. **Domain is `https://velxio.dev`** — update if domain changes.
+- `frontend/public/favicon.svg` — SVG chip favicon (scales to all sizes)
+- `frontend/public/og-image.svg` — 1200×630 social preview image (OG/Twitter). Export as PNG for max compatibility.
+- `frontend/public/robots.txt` — Allow all crawlers, points to sitemap
+- `frontend/public/sitemap.xml` — All public routes with priorities
+- `frontend/public/manifest.webmanifest` — PWA manifest, theme color `#007acc`
+
### Docker & CI
- [Dockerfile.standalone](Dockerfile.standalone) - Multi-stage Docker build
- [.github/workflows/docker-publish.yml](.github/workflows/docker-publish.yml) - Publishes to GHCR + Docker Hub on push to master
diff --git a/frontend/index.html b/frontend/index.html
index 072a57e..1178b48 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -2,9 +2,206 @@
-
- frontend
+
+
+ Velxio — Free Local Arduino Emulator | AVR8 · RP2040 · 48+ Components
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/package.json b/frontend/package.json
index 29817ab..cbf2afe 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -5,6 +5,7 @@
"type": "module",
"scripts": {
"generate:metadata": "cd .. && npx tsx scripts/generate-component-metadata.ts",
+ "generate:favicons": "node ../scripts/generate-favicons.mjs",
"dev": "npm run generate:metadata && vite",
"build": "npm run generate:metadata && tsc -b && vite build",
"build:docker": "vite build",
diff --git a/frontend/public/android-chrome-192.png b/frontend/public/android-chrome-192.png
new file mode 100644
index 0000000..6298f3d
Binary files /dev/null and b/frontend/public/android-chrome-192.png differ
diff --git a/frontend/public/android-chrome-512.png b/frontend/public/android-chrome-512.png
new file mode 100644
index 0000000..07dd305
Binary files /dev/null and b/frontend/public/android-chrome-512.png differ
diff --git a/frontend/public/apple-touch-icon.png b/frontend/public/apple-touch-icon.png
new file mode 100644
index 0000000..96d47c6
Binary files /dev/null and b/frontend/public/apple-touch-icon.png differ
diff --git a/frontend/public/favicon-16x16.png b/frontend/public/favicon-16x16.png
new file mode 100644
index 0000000..59bdac4
Binary files /dev/null and b/frontend/public/favicon-16x16.png differ
diff --git a/frontend/public/favicon-32x32.png b/frontend/public/favicon-32x32.png
new file mode 100644
index 0000000..7d10170
Binary files /dev/null and b/frontend/public/favicon-32x32.png differ
diff --git a/frontend/public/favicon-48x48.png b/frontend/public/favicon-48x48.png
new file mode 100644
index 0000000..ffb1f6f
Binary files /dev/null and b/frontend/public/favicon-48x48.png differ
diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico
new file mode 100644
index 0000000..ca07804
Binary files /dev/null and b/frontend/public/favicon.ico differ
diff --git a/frontend/public/favicon.svg b/frontend/public/favicon.svg
new file mode 100644
index 0000000..43c9633
--- /dev/null
+++ b/frontend/public/favicon.svg
@@ -0,0 +1,17 @@
+
diff --git a/frontend/public/manifest.webmanifest b/frontend/public/manifest.webmanifest
new file mode 100644
index 0000000..39618e4
--- /dev/null
+++ b/frontend/public/manifest.webmanifest
@@ -0,0 +1,51 @@
+{
+ "name": "Velxio — Arduino Emulator",
+ "short_name": "Velxio",
+ "description": "Free local Arduino emulator with real AVR8 CPU emulation, 48+ electronic components, Monaco Editor, and Serial Monitor. No cloud, no latency.",
+ "start_url": "/editor",
+ "scope": "/",
+ "display": "standalone",
+ "orientation": "landscape",
+ "background_color": "#0d0d0f",
+ "theme_color": "#007acc",
+ "categories": ["developer", "education", "productivity"],
+ "lang": "en",
+ "icons": [
+ {
+ "src": "/favicon-16x16.png",
+ "sizes": "16x16",
+ "type": "image/png"
+ },
+ {
+ "src": "/favicon-32x32.png",
+ "sizes": "32x32",
+ "type": "image/png"
+ },
+ {
+ "src": "/android-chrome-192.png",
+ "sizes": "192x192",
+ "type": "image/png",
+ "purpose": "any"
+ },
+ {
+ "src": "/android-chrome-512.png",
+ "sizes": "512x512",
+ "type": "image/png",
+ "purpose": "any maskable"
+ },
+ {
+ "src": "/favicon.svg",
+ "sizes": "any",
+ "type": "image/svg+xml",
+ "purpose": "any maskable"
+ }
+ ],
+ "screenshots": [
+ {
+ "src": "/og-image.svg",
+ "sizes": "1200x630",
+ "type": "image/svg+xml",
+ "label": "Velxio Arduino Emulator"
+ }
+ ]
+}
diff --git a/frontend/public/og-image.svg b/frontend/public/og-image.svg
new file mode 100644
index 0000000..e4a8f89
--- /dev/null
+++ b/frontend/public/og-image.svg
@@ -0,0 +1,142 @@
+
diff --git a/frontend/public/robots.txt b/frontend/public/robots.txt
new file mode 100644
index 0000000..25208a3
--- /dev/null
+++ b/frontend/public/robots.txt
@@ -0,0 +1,5 @@
+User-agent: *
+Allow: /
+
+# Sitemap
+Sitemap: https://velxio.dev/sitemap.xml
diff --git a/frontend/public/sitemap.xml b/frontend/public/sitemap.xml
new file mode 100644
index 0000000..964b4eb
--- /dev/null
+++ b/frontend/public/sitemap.xml
@@ -0,0 +1,40 @@
+
+
+
+
+ https://velxio.dev/
+ 2026-03-06
+ weekly
+ 1.0
+
+
+
+ https://velxio.dev/editor
+ 2026-03-06
+ weekly
+ 0.9
+
+
+
+ https://velxio.dev/examples
+ 2026-03-06
+ monthly
+ 0.7
+
+
+
+ https://velxio.dev/login
+ 2026-03-06
+ yearly
+ 0.3
+
+
+
+ https://velxio.dev/register
+ 2026-03-06
+ yearly
+ 0.3
+
+
+
diff --git a/scripts/generate-favicons.mjs b/scripts/generate-favicons.mjs
new file mode 100644
index 0000000..491e17c
--- /dev/null
+++ b/scripts/generate-favicons.mjs
@@ -0,0 +1,77 @@
+/**
+ * Favicon generator — converts favicon.svg into all required sizes.
+ * Run from project root: node scripts/generate-favicons.mjs
+ *
+ * Generates:
+ * frontend/public/favicon-16x16.png
+ * frontend/public/favicon-32x32.png
+ * frontend/public/favicon-48x48.png
+ * frontend/public/apple-touch-icon.png (180x180)
+ * frontend/public/android-chrome-192.png
+ * frontend/public/android-chrome-512.png
+ * frontend/public/favicon.ico (16+32+48 multi-size)
+ */
+
+import { readFileSync, writeFileSync } from 'fs';
+import { join, dirname } from 'path';
+import { fileURLToPath } from 'url';
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+const ROOT = join(__dirname, '..');
+const PUBLIC = join(ROOT, 'frontend', 'public');
+
+// ── install deps on the fly if missing ─────────────────────────────
+import { createRequire } from 'module';
+const require = createRequire(import.meta.url);
+
+async function ensureDep(pkg) {
+ try { return await import(pkg); } catch {}
+ console.log(`Installing ${pkg}…`);
+ const { execSync } = await import('child_process');
+ execSync(`npm install --no-save ${pkg}`, { stdio: 'inherit', cwd: ROOT });
+ return await import(pkg);
+}
+
+const { Resvg } = await ensureDep('@resvg/resvg-js');
+const pngToIcoMod = await ensureDep('png-to-ico');
+const pngToIco = pngToIcoMod.default ?? pngToIcoMod;
+
+// ── render helper ───────────────────────────────────────────────────
+const svgSrc = readFileSync(join(PUBLIC, 'favicon.svg'));
+
+function renderPng(size) {
+ const resvg = new Resvg(svgSrc, {
+ fitTo: { mode: 'width', value: size },
+ font: { loadSystemFonts: false },
+ });
+ return resvg.render().asPng();
+}
+
+// ── generate PNGs ───────────────────────────────────────────────────
+const sizes = [
+ { name: 'favicon-16x16.png', size: 16 },
+ { name: 'favicon-32x32.png', size: 32 },
+ { name: 'favicon-48x48.png', size: 48 },
+ { name: 'apple-touch-icon.png', size: 180 },
+ { name: 'android-chrome-192.png', size: 192 },
+ { name: 'android-chrome-512.png', size: 512 },
+];
+
+const pngBuffers = {};
+for (const { name, size } of sizes) {
+ const buf = renderPng(size);
+ writeFileSync(join(PUBLIC, name), buf);
+ pngBuffers[size] = buf;
+ console.log(`✓ ${name} (${size}x${size})`);
+}
+
+// ── generate favicon.ico (16 + 32 + 48) ────────────────────────────
+const icoBuffer = await pngToIco([
+ pngBuffers[16],
+ pngBuffers[32],
+ pngBuffers[48],
+]);
+writeFileSync(join(PUBLIC, 'favicon.ico'), icoBuffer);
+console.log('✓ favicon.ico (16+32+48)');
+
+console.log('\nAll favicon assets generated in frontend/public/');