openvibers/openvibe.sites Commits
Sites: openvibe.bot leaves the frozen set (Bot serves its front page, robots.txt and release.json since Bot#34); its legal pages stay. (#9)
Changes
@@@ -1,6 +1,6 @@# OpenVibe.Sites--OpenVibe.Sites serves static notices for three addresses during the domain handoff. It no longer builds product placeholders. `notices.json` is the build input; `frozen.json` records the 32 product domains whose existing `dist/<domain>/index.html` and nginx vhosts remain in place until their owners complete the DNS and nginx cutover. OpenVibe.Bot owns its own vhost.++OpenVibe.Sites serves static notices for three addresses during the domain handoff. It no longer builds product placeholders. `notices.json` is the build input; `frozen.json` records the 31 product domains whose existing `dist/<domain>/index.html` and nginx vhosts remain in place until their owners complete the DNS and nginx cutover. OpenVibe.Bot serves its own front page, robots.txt, release.json and status.json (OpenVibe.Bot#34, 2026-10-07), so Sites keeps only its legal pages, 404 page, sitemap and manifest there.## Remaining notices@@@ -14,7 +14,7 @@ All three are `noindex`. The existing page presentation is held in `notice-pages## Frozen product pages--`frozen.json` lists all 32 product domains, including OpenVibe.Actor and OpenVibe.Bot. Their committed front pages remain available as static files with their original indexing, status, and sitemaps. The build does not regenerate them. `node build.js --check` verifies that each frozen domain still has an index page and a Sites vhost where Sites owns one, while checking that notice outputs are current. The repository facts snapshot is historical data, not a build input.++`frozen.json` lists all 31 product domains, including OpenVibe.Actor. Their committed front pages remain available as static files with their original indexing, status, and sitemaps. The build does not regenerate them. `node build.js --check` verifies that each frozen domain still has an index page and a Sites vhost, while checking that notice outputs are current. The repository facts snapshot is historical data, not a build input.## Product catalog@@@ -42,7 +42,7 @@"deployed": true,"deployment": "Deployed with `sudo ovhost deploy sites --restart` (OpenVibe.Host strategy static-build since the 2026-09-27 cutover): /opt/openvibe.sites, nginx serves dist/<domain>/ through deploy/nginx/<domain>.conf; no unit, no port, no env file","features": [-- "three generated notices and 32 frozen product domains",++ "three generated notices and 31 frozen product domains","sites.json generated from the OpenVibe.Contracts product catalog","notice pages use preserved presentation; product pages are no longer generated","the pinned OpenVibe Frame served from dist/_shared/",@@@ -50,5 +50,5 @@"generated notice vhosts and preserved product vhosts","a release.json per domain and host.release.published on deploy"],-- "updated": "2026-10-03"++ "updated": "2026-10-07"}@@@ -200,9 +200,7 @@ function verifyFrozen() {let missing = 0;for (const domain of frozen) {if (noticeDomains.has(domain)) { console.error(`frozen domain is also a notice: ${domain}`); missing++; }-- // Bot's own repository supplies its vhost; Sites keeps only its frozen files.-- const files = [`dist/${domain}/index.html`, ...(domain === 'openvibe.bot' ? [] : [`deploy/nginx/${domain}.conf`])];-- for (const file of files) {++ for (const file of [`dist/${domain}/index.html`, `deploy/nginx/${domain}.conf`]) {if (!fs.existsSync(path.join(ROOT, file))) { console.error(`missing frozen file: ${file}`); missing++; }}}ddeleted file mode 100644@@@ -1,398 +0,0 @@--<!DOCTYPE html>--<html lang="en">--<head>--<meta charset="utf-8">--<meta name="viewport" content="width=device-width, initial-scale=1">--<title>OpenVibe.Bot — Get your robot online in minutes.</title>--<meta name="description" content="OpenVibe.Bot is an open control panel for robots. Add a robot, pair it with one command or a QR code, and drive it from any browser with live video, real controls and a stop button that always works. Buy a ready-made bot or bring your own: a Raspberry Pi robot, an ESP32, a ROS 2 robot, a phone, or a Cozmo. Share control, automate it, hand it to your AI agent, and stream it to OpenVibe.Live or openre.stream when you want to.">--<meta name="keywords" content="robot control panel, control a robot from the browser, remote control robot online, raspberry pi robot web control, esp32 robot control, ros 2 web control, telepresence robot, stream a robot live, open source robot controller, cozmo remote control, cozmo web control, cozmo sdk alternative">--<meta name="robots" content="index, follow, max-image-preview:large">--<meta name="theme-color" content="#f472b6">--<link rel="canonical" href="https://openvibe.bot/">--<link rel="icon" type="image/svg+xml" data-ov-icon="network" href="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%22-32%20-32%2064%2064%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22ring%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%221%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2360a5fa%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%232563eb%22%2F%3E%3C%2FlinearGradient%3E%0A%3CradialGradient%20id%3D%22glow%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2360a5fa%22%20stop-opacity%3D%22.34%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%2360a5fa%22%20stop-opacity%3D%220%22%2F%3E%3C%2FradialGradient%3E%0A%3CradialGradient%20id%3D%22bg%22%20cx%3D%22.5%22%20cy%3D%22.38%22%20r%3D%22.8%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2316223a%22%2F%3E%3Cstop%20offset%3D%22.6%22%20stop-color%3D%22%230a0f1c%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23060912%22%2F%3E%3C%2FradialGradient%3E%3C%2Fdefs%3E%3Crect%20x%3D%22-32%22%20y%3D%22-32%22%20width%3D%2264%22%20height%3D%2264%22%20rx%3D%2215%22%20fill%3D%22url(%23bg)%22%2F%3E%3Cg%20transform%3D%22scale(1.22)%22%3E%0A%3Ccircle%20r%3D%2221%22%20fill%3D%22url(%23glow)%22%2F%3E%0A%3Ccircle%20r%3D%2218%22%20fill%3D%22none%22%20stroke%3D%22url(%23ring)%22%20stroke-width%3D%224%22%20opacity%3D%22.38%22%2F%3E%0A%3Cpath%20d%3D%22M0%2C-18%20A18%2C18%200%200%2C1%2017.4%2C4.6%22%20fill%3D%22none%22%20stroke%3D%22url(%23ring)%22%20stroke-width%3D%224.4%22%20stroke-linecap%3D%22round%22%2F%3E%0A%3Cpath%20d%3D%22M-9.5%2C-7%20L0%2C10%20L9.5%2C-7%22%20fill%3D%22none%22%20stroke%3D%22%23fff%22%20stroke-width%3D%224.8%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%0A%3Ccircle%20cx%3D%2217.4%22%20cy%3D%224.6%22%20r%3D%223.2%22%20fill%3D%22%23ffffff%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E">--<style id="ov-critical">html{background:#0a0f1c;color:#e6edf7;color-scheme:dark}</style><script>(function(){try{var r=localStorage.getItem('ov_theme');if(!r)return;var t=JSON.parse(r),v=t&&t.variables;if(!v)return;var e=document.documentElement;for(var k in v)if(k.charAt(0)==='-')e.style.setProperty(k,v[k]);if(v['--bg-primary'])e.style.background=v['--bg-primary'];if(v['--text-primary'])e.style.color=v['--text-primary'];if(v['--color-scheme']==='light'||v['--color-scheme']==='dark')e.style.colorScheme=v['--color-scheme'];if(t.id)e.setAttribute('data-theme',t.id)}catch(_){}})();</script>--<link rel="manifest" href="/manifest.webmanifest">--<link rel="alternate" type="text/html" hreflang="en" href="https://openvibe.bot/">--<meta property="og:type" content="website">--<meta property="og:site_name" content="OpenVibe.Bot">--<meta property="og:url" content="https://openvibe.bot/">--<meta property="og:title" content="OpenVibe.Bot — Get your robot online in minutes.">--<meta property="og:description" content="OpenVibe.Bot is an open control panel for robots. Add a robot, pair it with one command or a QR code, and drive it from any browser with live video, real controls and a stop button that always works. Buy a ready-made bot or bring your own: a Raspberry Pi robot, an ESP32, a ROS 2 robot, a phone, or a Cozmo. Share control, automate it, hand it to your AI agent, and stream it to OpenVibe.Live or openre.stream when you want to.">--<meta property="og:image" content="https://openvibe.network/assets/logo-512.png">--<meta property="og:image:alt" content="OpenVibe">--<meta name="twitter:card" content="summary">--<meta name="twitter:title" content="OpenVibe.Bot — Get your robot online in minutes.">--<meta name="twitter:description" content="OpenVibe.Bot is an open control panel for robots. Add a robot, pair it with one command or a QR code, and drive it from any browser with live video, real controls and a stop button that always works. Buy a ready-made bot or bring your own: a Raspberry Pi robot, an ESP32, a ROS 2 robot, a phone, or a Cozmo. Share control, automate it, hand it to your AI agent, and stream it to OpenVibe.Live or openre.stream when you want to.">--<meta name="twitter:image" content="https://openvibe.network/assets/logo-512.png">--<script type="application/ld+json">{"@context":"https://schema.org","@graph":[{"@type":"WebSite","@id":"https://openvibe.bot/#site","url":"https://openvibe.bot/","name":"OpenVibe.Bot","description":"OpenVibe.Bot is an open control panel for robots. Add a robot, pair it with one command or a QR code, and drive it from any browser with live video, real controls and a stop button that always works. Buy a ready-made bot or bring your own: a Raspberry Pi robot, an ESP32, a ROS 2 robot, a phone, or a Cozmo. Share control, automate it, hand it to your AI agent, and stream it to OpenVibe.Live or openre.stream when you want to.","inLanguage":"en","publisher":{"@type":"Organization","@id":"https://openvibe.network/#org","name":"OpenVibe","url":"https://openvibe.network/","logo":"https://openvibe.network/assets/logo-512.png","sameAs":["https://github.com/OpenVibers","https://discord.gg/M6MuRUaeJj"]},"isPartOf":{"@type":"WebSite","@id":"https://openvibe.network/#site","name":"OpenVibe.Network","url":"https://openvibe.network/"}},{"@type":"WebPage","@id":"https://openvibe.bot/#page","url":"https://openvibe.bot/","name":"OpenVibe.Bot — Get your robot online in minutes.","description":"OpenVibe.Bot is an open control panel for robots. Add a robot, pair it with one command or a QR code, and drive it from any browser with live video, real controls and a stop button that always works. Buy a ready-made bot or bring your own: a Raspberry Pi robot, an ESP32, a ROS 2 robot, a phone, or a Cozmo. Share control, automate it, hand it to your AI agent, and stream it to OpenVibe.Live or openre.stream when you want to.","isPartOf":{"@id":"https://openvibe.bot/#site"},"datePublished":"2026-09-17","dateModified":"2026-10-03","breadcrumb":{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"OpenVibe","item":"https://openvibe.network/"},{"@type":"ListItem","position":2,"name":"OpenVibe.Bot","item":"https://openvibe.bot/"}]}},{"@type":"FAQPage","@id":"https://openvibe.bot/#faq","mainEntity":[{"@type":"Question","name":"Do I need to open ports on my router?","acceptedAnswer":{"@type":"Answer","text":"No. The robot connects out to OpenVibe, and video and controls travel over WebRTC, so it works behind ordinary home and mobile networks."}},{"@type":"Question","name":"Is it only for streaming?","acceptedAnswer":{"@type":"Answer","text":"No. Streaming is optional. Bot is a control panel for your robot first: drive it, check on it, share it and automate it."}},{"@type":"Question","name":"Which robot comes first?","acceptedAnswer":{"@type":"Answer","text":"The Adeept 4WD Smart Car Kit for Raspberry Pi: four motors, a pan-tilt camera, distance and line sensors, lights and a buzzer. OpenVibe's device agent drives it directly, so its own open control port never has to be exposed."}},{"@type":"Question","name":"Does it work with Cozmo?","acceptedAnswer":{"@type":"Answer","text":"Yes, built in. Cozmo makes its own Wi-Fi and runs closed firmware, so the OpenVibe agent runs on a computer next to it (a Raspberry Pi or a laptop) that joins Cozmo's Wi-Fi and stays online through another connection. You get driving, the head and lift, its camera, its face display, its voice, lights and cubes, and it stops at edges on its own. No phone app needed."}},{"@type":"Question","name":"What hardware works?","acceptedAnswer":{"@type":"Answer","text":"A Raspberry Pi or another Linux board, an ESP32, a ROS 2 robot, an Android phone, or an ONVIF or RTSP camera. The curated kits list exactly what to buy."}},{"@type":"Question","name":"How does it keep the robot safe?","acceptedAnswer":{"@type":"Answer","text":"The device stops its motors by itself when commands or the connection stop. There is an emergency stop in the panel, limits on speed, range and time, and every command is logged."}},{"@type":"Question","name":"What will it cost?","acceptedAnswer":{"@type":"Answer","text":"Controlling your own robot will not cost anything. Limits and any paid extras will be published before launch."}}]}]}</script>--<script>(function(){try{var raw=localStorage.getItem('ov_theme');if(!raw)return;var t=JSON.parse(raw),v=t&&t.variables;if(!v)return;var el=document.documentElement;for(var k in v)if(k.charAt(0)==='-')el.style.setProperty(k,v[k]);if(t.id)el.setAttribute('data-theme',t.id);}catch(_){}})();</script>--<script src="/shared/theme-loader.js?v=ee4a6754d0f7" defer></script>--<link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin>--<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" media="print" onload="this.media='all'">--<noscript><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"></noscript>--<style>--*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}--:root{--bg-primary:#0a0f1c;--bg-secondary:#101828;--bg-card:#131c2e;--bg-hover:#1c2a44;--border:#1f2d47;--text-primary:#e6edf7;--text-secondary:#96a7c2;--text-muted:#7386a3;--accent:#3b82f6;--accent-light:#60a5fa;--accent-rgb:59,130,246;--on-accent:#fff;--site:#f472b6;--site-rgb:244,114,182}--html{scroll-behavior:smooth}--body{background:var(--bg-primary);color:var(--text-primary);font-family:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;min-height:100vh;display:flex;flex-direction:column;overflow-x:hidden}--main{flex:1;position:relative}--.orbs{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden}--.orbs i{position:absolute;border-radius:50%;filter:blur(90px);opacity:.16;animation:drift 26s ease-in-out infinite alternate}--.orbs i:nth-child(1){width:420px;height:420px;background:var(--site);top:-140px;left:-120px}--.orbs i:nth-child(2){width:360px;height:360px;background:var(--accent);top:40%;right:-140px;animation-delay:-9s}--.orbs i:nth-child(3){width:300px;height:300px;background:var(--site);bottom:-120px;left:38%;animation-delay:-17s}--@keyframes drift{0%{transform:translate(0,0) scale(1)}50%{transform:translate(-26px,36px) scale(1.07)}100%{transform:translate(34px,-28px) scale(.95)}}--.wrap{position:relative;z-index:1;max-width:1040px;margin:0 auto;padding:0 20px}--.hero{padding:84px 0 44px;text-align:center}--.hero .mark{display:inline-grid;place-items:center;width:84px;height:84px;border-radius:24px;background:rgba(var(--site-rgb),.12);border:1px solid rgba(var(--site-rgb),.35);color:var(--site);font-size:34px;margin-bottom:22px;box-shadow:0 20px 60px rgba(var(--site-rgb),.18);animation:rise .6s cubic-bezier(.2,.8,.2,1) both}--.hero .badge{display:inline-flex;align-items:center;gap:8px;padding:6px 14px;border-radius:999px;border:1px solid var(--border);background:var(--bg-secondary);font-size:12px;font-weight:600;color:var(--text-secondary);letter-spacing:.3px;margin-bottom:22px;animation:rise .6s .05s cubic-bezier(.2,.8,.2,1) both}--.hero .badge b{color:var(--site)}--.hero h1{font-size:clamp(34px,6vw,58px);font-weight:800;letter-spacing:-1.4px;line-height:1.08;animation:rise .6s .1s cubic-bezier(.2,.8,.2,1) both}--.hero h1 .d{color:var(--site)}--.hero h1 .tld{color:var(--text-secondary)}--.hero .tag{font-size:clamp(18px,2.6vw,24px);font-weight:600;color:var(--text-primary);margin:18px 0 10px;animation:rise .6s .16s cubic-bezier(.2,.8,.2,1) both}--.hero p.lead{color:var(--text-secondary);font-size:16px;line-height:1.65;max-width:680px;margin:0 auto;animation:rise .6s .22s cubic-bezier(.2,.8,.2,1) both}--.ctas{display:flex;flex-wrap:wrap;gap:12px;justify-content:center;margin-top:30px;animation:rise .6s .3s cubic-bezier(.2,.8,.2,1) both}--.hero .status{margin:22px auto 0;max-width:720px;font-size:12.5px;line-height:1.7;color:var(--text-muted);border:1px dashed var(--border);border-radius:12px;padding:10px 14px;background:rgba(0,0,0,.15)}--.hero .status b{color:var(--site)}--.hero .status code{font-size:12px;color:var(--text-secondary);background:var(--bg-secondary);padding:1px 6px;border-radius:6px}--.hero .status a{color:var(--text-secondary)}--.btn{display:inline-flex;align-items:center;gap:9px;padding:12px 20px;border-radius:12px;font-size:14px;font-weight:600;text-decoration:none;border:1px solid var(--border);color:var(--text-primary);background:var(--bg-secondary);transition:transform .15s,border-color .15s,box-shadow .15s}--.btn:hover{transform:translateY(-1px);border-color:var(--site);box-shadow:0 10px 30px rgba(var(--site-rgb),.15)}--.btn-primary{background:var(--site);border-color:var(--site);color:#0b0d10}--.btn-primary:hover{filter:brightness(1.08)}--@keyframes rise{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}--section{padding:36px 0}--h2{font-size:22px;font-weight:700;letter-spacing:-.3px;margin-bottom:6px}--.lead2{color:var(--text-secondary);font-size:14px;margin-bottom:20px}--.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:14px}--.card{background:var(--bg-card);border:1px solid var(--border);border-radius:16px;padding:20px;transition:transform .2s,border-color .2s,box-shadow .2s;text-decoration:none;color:inherit;display:flex;flex-direction:column;gap:8px}--a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);box-shadow:0 16px 40px rgba(0,0,0,.35)}--.card .ic{width:40px;height:40px;border-radius:11px;display:grid;place-items:center;background:rgba(var(--site-rgb),.12);color:var(--site);font-size:17px}--.card b{font-size:15px}--.card span{font-size:13px;color:var(--text-secondary);line-height:1.55}--.card .go{margin-top:auto;font-size:12.5px;font-weight:600;color:var(--site)}--.highlight .hl-card{border:1px solid rgba(var(--accent-rgb),.45);background:rgba(var(--accent-rgb),.10);border-radius:18px;padding:22px 22px 18px}--.highlight h2{margin:0 0 8px}.highlight h2 i{color:var(--accent-light)}.highlight p{margin:0 0 10px}--.highlight ul{margin:0 0 14px;padding-left:20px}.highlight li{margin:4px 0}--.faq details{border:1px solid rgba(255,255,255,.08);border-radius:12px;padding:12px 14px;margin:8px 0}--.faq summary{cursor:pointer;font-weight:600}.faq details p{margin:8px 0 0;opacity:.85}--.meanwhile .card .ic{background:rgba(var(--accent-rgb),.12);color:var(--accent-light)}--.net .card .ic{background:var(--bg-hover);color:var(--text-primary)}--.rooms{display:flex;flex-wrap:wrap;gap:8px}--.rooms a{font-size:12.5px;padding:7px 12px;border-radius:999px;border:1px solid var(--border);color:var(--text-secondary);text-decoration:none;transition:all .15s;background:var(--bg-secondary)}--.rooms a:hover{color:var(--text-primary);border-color:var(--site)}--.rooms a i{margin-right:6px;opacity:.8}--.strip{border:1px solid var(--border);border-radius:18px;background:var(--bg-secondary);padding:30px 26px;text-align:center;margin:10px 0 50px}--.strip h3{font-size:19px;font-weight:700;margin:12px 0 8px}--.strip p{font-size:14px;color:var(--text-secondary);max-width:600px;margin:0 auto 18px;line-height:1.6}--.strip .ov-mark{width:44px;height:44px}--.hero.split{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);gap:40px;align-items:center;text-align:left;padding-top:64px}--.hero.split .ctas{justify-content:flex-start}.hero.split p.lead{margin:0}--.viz{background:var(--bg-card);border:1px solid var(--border);border-radius:20px;padding:14px;box-shadow:0 30px 80px rgba(0,0,0,.45),0 0 0 1px rgba(var(--site-rgb),.08);animation:rise .7s .25s cubic-bezier(.2,.8,.2,1) both;text-align:left}--.viz figcaption{margin-top:10px;font-size:11.5px;color:var(--text-muted);text-align:center}--.viz-top{display:flex;align-items:center;gap:8px;font-size:13px;padding:2px 4px 12px}--.viz-top b{font-weight:700}.viz-top .muted{color:var(--text-muted)}--.viz-top .lat{margin-left:auto;font-size:12px;color:var(--site);background:rgba(var(--site-rgb),.1);border:1px solid rgba(var(--site-rgb),.3);padding:3px 9px;border-radius:999px}--.viz-top .dot{width:8px;height:8px;border-radius:50%;background:#22c55e;box-shadow:0 0 0 4px rgba(34,197,94,.18)}--.viz-top .av{width:26px;height:26px;border-radius:8px;display:grid;place-items:center;background:rgba(var(--site-rgb),.15);color:var(--site);font-size:13px}--.viz-video{position:relative;aspect-ratio:16/9;border-radius:14px;overflow:hidden;background:radial-gradient(120% 90% at 30% 20%,rgba(var(--site-rgb),.28),transparent 60%),linear-gradient(160deg,#1a2338,#0b1020 70%);border:1px solid var(--border)}--.viz-video::after{content:'';position:absolute;left:10%;right:10%;bottom:0;height:42%;background:linear-gradient(transparent,rgba(0,0,0,.35)),repeating-linear-gradient(90deg,rgba(255,255,255,.05) 0 1px,transparent 1px 38px);transform:perspective(220px) rotateX(58deg);transform-origin:bottom}--.viz-video .scan{position:absolute;inset:0;background:linear-gradient(transparent 0,rgba(255,255,255,.04) 50%,transparent 100%);background-size:100% 6px;opacity:.5}--.viz-video .onair{position:absolute;top:10px;left:10px;font-size:11px;font-weight:700;padding:3px 8px;border-radius:6px;background:rgba(239,68,68,.9);color:#fff}.viz-video .onair i{font-size:7px;vertical-align:2px;margin-right:3px}--.viz-video .cam{position:absolute;bottom:10px;right:10px;font-size:11px;color:#dbe4f5;background:rgba(0,0,0,.45);padding:3px 8px;border-radius:6px}--.viz-ctrl{display:flex;gap:14px;align-items:center;margin-top:12px}--.dpad{display:grid;grid-template-columns:repeat(3,34px);grid-template-rows:repeat(3,34px);gap:4px;flex:none}--.dpad span{display:grid;place-items:center;border-radius:9px;background:var(--bg-hover);color:var(--text-primary);font-size:15px;border:1px solid var(--border)}--.dpad .u{grid-area:1/2}.dpad .l{grid-area:2/1}.dpad .c{grid-area:2/2;background:rgba(var(--site-rgb),.15);border-color:rgba(var(--site-rgb),.35)}.dpad .r{grid-area:2/3}.dpad .d{grid-area:3/2}--.dpad .u{background:rgba(var(--site-rgb),.22);border-color:rgba(var(--site-rgb),.5)}--.viz-side{flex:1;min-width:0;display:grid;gap:8px}--.viz-side .keys{display:flex;flex-wrap:wrap;gap:6px}--.viz-side .keys span{font-size:11.5px;padding:5px 9px;border-radius:8px;background:var(--bg-secondary);border:1px solid var(--border);color:var(--text-secondary)}--.viz-side .meter{display:flex;align-items:center;gap:8px;font-size:11.5px;color:var(--text-muted)}--.viz-side .meter i{flex:1;height:6px;border-radius:9px;background:linear-gradient(90deg,#22c55e var(--v),var(--bg-hover) var(--v))}--.viz-side .meter b{color:var(--text-secondary);font-weight:600}--.viz-side .estop{justify-self:end;font-size:12px;font-weight:800;letter-spacing:.08em;color:#fff;background:#dc2626;border-radius:10px;padding:7px 16px;box-shadow:0 0 0 3px rgba(220,38,38,.25)}--.feed{list-style:none;display:grid;gap:8px;padding:2px}--.feed li{display:flex;align-items:flex-start;gap:10px;font-size:13.5px;line-height:1.45;padding:10px 12px;border-radius:12px;background:var(--bg-secondary);border:1px solid var(--border);color:var(--text-secondary)}--.feed li i{color:#22c55e;margin-top:3px}--.feed li.ask{flex-wrap:wrap;border-color:rgba(var(--site-rgb),.45);background:rgba(var(--site-rgb),.08);color:var(--text-primary)}.feed li.ask i{color:var(--site)}.feed li.ask>span:first-of-type{flex:1;min-width:160px}--.feed .pills{display:flex;gap:6px;margin-left:auto}.feed .pills span{font-size:12px;font-weight:600;padding:4px 11px;border-radius:999px;border:1px solid var(--border);color:var(--text-secondary)}.feed .pills .ok{background:var(--site);border-color:var(--site);color:#0b0d10}--.steps{list-style:none;display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:14px;counter-reset:s}--.steps li{position:relative;background:var(--bg-card);border:1px solid var(--border);border-radius:16px;padding:20px 20px 20px;display:flex;flex-direction:column;gap:8px}--.steps .n{width:30px;height:30px;border-radius:50%;display:grid;place-items:center;font-weight:800;font-size:14px;color:#0b0d10;background:var(--site)}--.steps b{font-size:15px}.steps span:last-child{font-size:13px;color:var(--text-secondary);line-height:1.55}--.grid.three{grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}--.viz .task{font-size:14px;line-height:1.5;padding:10px 12px;border-radius:12px;background:var(--bg-secondary);border:1px solid var(--border);color:var(--text-primary)}--.viz .modes{display:flex;flex-wrap:wrap;gap:6px;margin:10px 0}--.viz .modes span{font-size:11.5px;font-weight:600;padding:4px 10px;border-radius:999px;border:1px solid var(--border);color:var(--text-secondary)}--.viz .modes .on{background:var(--site);border-color:var(--site);color:#0b0d10}--.cands{list-style:none;display:grid;gap:6px}--.cands li{display:grid;grid-template-columns:18px minmax(0,1fr) 54px 50px 44px;align-items:center;gap:8px;font-size:12.5px;padding:8px 10px;border-radius:10px;background:var(--bg-secondary);border:1px solid var(--border);color:var(--text-secondary);position:relative}--.cands li i{color:var(--text-muted)}.cands li b{font-weight:600;color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}--.cands li span{text-align:right;font-variant-numeric:tabular-nums}--.cands li.pick{border-color:rgba(var(--site-rgb),.55);background:rgba(var(--site-rgb),.09)}.cands li.pick i{color:var(--site)}--.cands li em{position:absolute;top:-8px;right:10px;font-style:normal;font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;padding:1px 7px;border-radius:999px;background:var(--site);color:#0b0d10}--.viz .why{margin-top:10px;font-size:12.5px;line-height:1.5;color:var(--text-secondary)}.viz .why i{color:var(--site);margin-right:4px}--.choice{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:14px}--.card.big{padding:24px}.card.big b{font-size:17px}--.chips{display:flex;flex-wrap:wrap;gap:7px;margin-top:6px}--.chips span{font-size:12.5px;padding:6px 11px;border-radius:999px;border:1px solid var(--border);background:var(--bg-secondary);color:var(--text-secondary)}--.chips.big span{font-size:13.5px;padding:9px 14px;color:var(--text-primary)}.chips.big span i{color:var(--site);margin-right:8px}--.build .card{border-style:dashed;background:rgba(0,0,0,.15)}.build .card b i{color:var(--site);margin-right:6px}.build .card span a{color:var(--text-secondary)}.build .card code{font-size:12px}--@media (max-width:860px){.hero.split{grid-template-columns:1fr;text-align:center;gap:28px}.hero.split .ctas{justify-content:center}.hero.split p.lead{margin:0 auto}}--@media (max-width:600px){.hero{padding-top:56px}.ctas .btn{width:100%;justify-content:center}.viz-ctrl{flex-direction:column;align-items:stretch}.dpad{align-self:center}.cands li{grid-template-columns:14px minmax(0,1fr) 30px 40px 30px;gap:6px;font-size:12px;padding:8px}}--@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}--</style>--</head>--<body>--<div class="orbs"><i></i><i></i><i></i></div>--<div id="navbar-mount"></div>--<main class="wrap">-- <header class="hero split"><div class="hero-main">-- <div class="mark"><i class="fa-solid fa-robot" aria-hidden="true"></i></div>-- <div class="badge"><span class="ov-mark" data-size="16" data-variant="bot"></span> Part of the OpenVibe network · <b>being built</b></div>-- <h1>OpenVibe<span class="d">.</span><span class="tld">Bot</span></h1>-- <div class="tag">Get your robot online in minutes.</div>-- <p class="lead">OpenVibe.Bot is an open control panel for robots. Add a robot, pair it with one command or a QR code, and drive it from any browser with live video, real controls and a stop button that always works. Buy a ready-made bot or bring your own: a Raspberry Pi robot, an ESP32, a ROS 2 robot, a phone, or a Cozmo. Share control, automate it, hand it to your AI agent, and stream it to OpenVibe.Live or openre.stream when you want to.</p>-- <div class="ctas">-- <a class="btn btn-primary" href="https://openvibe.network/login?return=https%3A%2F%2Fopenvibe.bot%2F"><i class="fa-solid fa-right-to-bracket"></i> Sign in with OpenVibe</a>-- <a class="btn" href="https://openvibe.live"><i class="fa-solid fa-tower-broadcast"></i> Robots on Live today</a>-- <a class="btn" href="https://discord.gg/M6MuRUaeJj" rel="noopener"><i class="fa-brands fa-discord"></i> Follow the build</a>-- </div>-- </div>-- <figure class="viz" aria-label="Design preview: a robot control panel with live video, a drive pad, buttons, battery level and a stop button">-- <div class="viz-top"><span class="dot"></span><b>Rover-1</b><span class="muted">online</span><span class="lat"><i class="fa-solid fa-signal" aria-hidden="true"></i> 84 ms</span></div>-- <div class="viz-video" aria-hidden="true"><div class="scan"></div><span class="onair"><i class="fa-solid fa-circle" aria-hidden="true"></i> Streaming to openvibe.live</span><span class="cam"><i class="fa-solid fa-video" aria-hidden="true"></i> Front camera</span></div>-- <div class="viz-ctrl" aria-hidden="true">-- <div class="dpad"><span class="u"><i class="fa-solid fa-caret-up"></i></span><span class="l"><i class="fa-solid fa-caret-left"></i></span><span class="c"></span><span class="r"><i class="fa-solid fa-caret-right"></i></span><span class="d"><i class="fa-solid fa-caret-down"></i></span></div>-- <div class="viz-side">-- <div class="keys"><span><i class="fa-solid fa-lightbulb"></i> Lights</span><span><i class="fa-solid fa-bullhorn"></i> Horn</span><span><i class="fa-solid fa-comment"></i> Speak</span><span><i class="fa-solid fa-camera-rotate"></i> Camera</span></div>-- <div class="meter"><span>Battery</span><i style="--v:82%"></i><b>82%</b></div>-- <div class="estop">STOP</div>-- </div>-- </div>-- <figcaption>Design preview of the robot panel</figcaption>-- </figure>-- </header>------ <section id="what">-- <h2>Online in three steps</h2>-- <p class="lead2">No port forwarding, no stream keys, no config files.</p>-- <ol class="steps">-- <li><span class="n">1</span><b>Add a robot</b><span>Name it and pick what it is: a rover, an arm, a camera, a phone on wheels or your own design.</span></li>-- <li><span class="n">2</span><b>Pair it</b><span>Paste one command on the robot, flash a ready-made card, or scan a QR code. It gets its own key, which you can revoke any time.</span></li>-- <li><span class="n">3</span><b>Drive it</b><span>Live video and controls in any browser, phone included, with a stop button that always works.</span></li>-- </ol>-- </section>---- <section>-- <h2>Buy one or bring your own</h2>-- <p class="lead2">Start with hardware that is known to work, or use what you already have.</p>-- <div class="choice">-- <div class="card big"><div class="ic"><i class="fa-solid fa-box-open" aria-hidden="true"></i></div><b>Get a robot</b><span>Curated kits with parts lists, tested settings and build guides, and ready-made bots that arrive paired to your account. The first one on OpenVibe.Bot is the Adeept 4WD Smart Car for Raspberry Pi.</span><div class="chips"><span>Adeept 4WD Smart Car (Raspberry Pi)</span><span>Rover kits</span><span>Telepresence bots</span><span>Pan-tilt cameras</span><span>Robot arms</span></div></div>-- <div class="card big"><div class="ic"><i class="fa-solid fa-screwdriver-wrench" aria-hidden="true"></i></div><b>Bring your own</b><span>Anything with motors, a camera or sensors. Install the OpenVibe device agent on the robot, or, for robots with their own firmware like Cozmo, on a computer next to it, and your robot shows up in the panel.</span><div class="chips"><span>Raspberry Pi and Linux boards</span><span>Cozmo, through a bridge</span><span>ESP32</span><span>ROS 2</span><span>Android phones</span><span>ONVIF and RTSP cameras</span><span>Serial motor boards</span></div></div>-- </div>-- </section>---- <section>-- <h2>More than a stream</h2>-- <p class="lead2">A control panel for anything you build, whether or not anyone is watching.</p>-- <div class="grid three">-- <div class="card"><div class="ic"><i class="fa-solid fa-gamepad" aria-hidden="true"></i></div><b>Real controls</b><span>Drive pad, keyboard, touch joystick and gamepad; buttons, sliders, servos and camera pan-tilt, laid out from your robot's profile.</span></div>-- <div class="card"><div class="ic"><i class="fa-solid fa-bolt" aria-hidden="true"></i></div><b>Low latency</b><span>Video and commands over WebRTC, so driving feels direct. Works behind ordinary home and mobile networks.</span></div>-- <div class="card"><div class="ic"><i class="fa-solid fa-user-group" aria-hidden="true"></i></div><b>Share control</b><span>Invite friends as operators, or open a public queue with timed turns, cooldowns and per-role limits.</span></div>-- <div class="card"><div class="ic"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i></div><b>Safe by default</b><span>The robot stops itself when commands stop. An emergency stop, speed and range limits and time windows, all logged.</span></div>-- <div class="card"><div class="ic"><i class="fa-solid fa-diagram-project" aria-hidden="true"></i></div><b>Automate it</b><span>Schedules, triggers and webhooks, plus an API and SDKs for your own apps.</span></div>-- <div class="card"><div class="ic"><i class="fa-solid fa-user-astronaut" aria-hidden="true"></i></div><b>Hand it to your agent</b><span>Let your OpenVibe.Actor agent patrol, check on or perform with your robot, with your approval.</span></div>-- </div>-- </section>-------- <section class="meanwhile">-- <h2>Stream it, record it, connect it</h2>-- <p class="lead2">Optional, one toggle each. Your robot does not need an audience to be useful.</p>-- <div class="grid">-- <a class="card" href="https://openvibe.live"><div class="ic"><i class="fa-solid fa-tower-broadcast" aria-hidden="true"></i></div><b>Stream to OpenVibe.Live</b><span>Put the robot's camera on your channel; viewers can drive it from chat or the panel.</span><span class="go">openvibe.live →</span></a>-- <a class="card" href="https://openre.stream"><div class="ic"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i></div><b>Stream through openre.stream</b><span>Low-latency ingest and restreaming to other platforms from the same camera.</span><span class="go">openre.stream →</span></a>-- <a class="card" href="https://openvibe.media"><div class="ic"><i class="fa-solid fa-photo-film" aria-hidden="true"></i></div><b>Record to OpenVibe.Media</b><span>Keep every run as a video and cut clips from it.</span><span class="go">openvibe.media →</span></a>-- <a class="card" href="https://openvibe.codes"><div class="ic"><i class="fa-solid fa-code" aria-hidden="true"></i></div><b>Build on it</b><span>The API, SDKs and examples.</span><span class="go">openvibe.codes →</span></a>-- </div>-- </section>---- <section id="questions" class="faq">-- <h2>Questions</h2>-- <details><summary>Do I need to open ports on my router?</summary><p>No. The robot connects out to OpenVibe, and video and controls travel over WebRTC, so it works behind ordinary home and mobile networks.</p></details>-- <details><summary>Is it only for streaming?</summary><p>No. Streaming is optional. Bot is a control panel for your robot first: drive it, check on it, share it and automate it.</p></details>-- <details><summary>Which robot comes first?</summary><p>The Adeept 4WD Smart Car Kit for Raspberry Pi: four motors, a pan-tilt camera, distance and line sensors, lights and a buzzer. OpenVibe's device agent drives it directly, so its own open control port never has to be exposed.</p></details>-- <details><summary>Does it work with Cozmo?</summary><p>Yes, built in. Cozmo makes its own Wi-Fi and runs closed firmware, so the OpenVibe agent runs on a computer next to it (a Raspberry Pi or a laptop) that joins Cozmo's Wi-Fi and stays online through another connection. You get driving, the head and lift, its camera, its face display, its voice, lights and cubes, and it stops at edges on its own. No phone app needed.</p></details>-- <details><summary>What hardware works?</summary><p>A Raspberry Pi or another Linux board, an ESP32, a ROS 2 robot, an Android phone, or an ONVIF or RTSP camera. The curated kits list exactly what to buy.</p></details>-- <details><summary>How does it keep the robot safe?</summary><p>The device stops its motors by itself when commands or the connection stop. There is an emergency stop in the panel, limits on speed, range and time, and every command is logged.</p></details>-- <details><summary>What will it cost?</summary><p>Controlling your own robot will not cost anything. Limits and any paid extras will be published before launch.</p></details>-- </section>---- <section class="build">-- <div class="card">-- <b><i class="fa-solid fa-person-digging" aria-hidden="true"></i> Build status</b>-- <span>OpenVibe.Bot is being built now, starting with our own robots; stream-controlled robots already run on OpenVibe.Live. Its own service is not running yet: this page is a placeholder, nothing here is live yet. It opens with the Bot service, its device agent and the first robots paired. · as of 2026-09-29 · <a href="/status.json">status.json</a></span>-- </div>-- </section>---- <section class="net">-- <h2>The OpenVibe network</h2>-- <p class="lead2">One account for all of it. Sign in once and every site signs you in.</p>-- <div class="grid">-- <a class="card" href="https://openvibe.live"><div class="ic"><i class="fa-solid fa-tower-broadcast" aria-hidden="true"></i></div><b>OpenVibe.Live</b><span>Go live, chat, clip, restream</span><span class="go">openvibe.live →</span></a>-- <a class="card" href="https://openvibe.tools"><div class="ic"><i class="fa-solid fa-screwdriver-wrench" aria-hidden="true"></i></div><b>OpenVibe.Tools</b><span>Hundreds of online tools</span><span class="go">openvibe.tools →</span></a>-- <a class="card" href="https://openvibe.community"><div class="ic"><i class="fa-solid fa-people-group" aria-hidden="true"></i></div><b>OpenVibe.Community</b><span>Pastes, posts, people</span><span class="go">openvibe.community →</span></a>-- <a class="card" href="https://openvibe.games"><div class="ic"><i class="fa-solid fa-gamepad" aria-hidden="true"></i></div><b>OpenVibe.Games</b><span>Scraplandia and browser games</span><span class="go">openvibe.games →</span></a>-- <a class="card" href="https://openvibe.media"><div class="ic"><i class="fa-solid fa-photo-film" aria-hidden="true"></i></div><b>OpenVibe.Media</b><span>VODs, clips and files</span><span class="go">openvibe.media →</span></a>-- <a class="card" href="https://openvibe.network"><div class="ic"><i class="fa-solid fa-circle-nodes" aria-hidden="true"></i></div><b>OpenVibe.Network</b><span>One account, every site</span><span class="go">openvibe.network →</span></a>-- </div>-- <h2 style="margin-top:28px;font-size:16px">Other OpenVibe domains, not open yet</h2>-- <div class="rooms" style="margin-top:8px">-- <a href="https://openvibe.news/"><i class="fa-solid fa-newspaper" aria-hidden="true"></i>OpenVibe.News</a>-- <a href="https://openvibe.reviews/"><i class="fa-solid fa-star-half-stroke" aria-hidden="true"></i>OpenVibe.Reviews</a>-- <a href="https://openvibe.tips/"><i class="fa-solid fa-hand-holding-heart" aria-hidden="true"></i>OpenVibe.Tips</a>-- <a href="https://openvibe.vip/"><i class="fa-solid fa-crown" aria-hidden="true"></i>OpenVibe.VIP</a>-- <a href="https://openvibe.trade/"><i class="fa-solid fa-chart-line" aria-hidden="true"></i>OpenVibe.Trade</a>-- <a href="https://openvibe.host/"><i class="fa-solid fa-server" aria-hidden="true"></i>OpenVibe.Host</a>-- <a href="https://openvibe.deals/"><i class="fa-solid fa-tags" aria-hidden="true"></i>OpenVibe.Deals</a>-- <a href="https://openvibe.coupons/"><i class="fa-solid fa-ticket" aria-hidden="true"></i>OpenVibe.Coupons</a>-- <a href="https://openre.stream/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>OpenRe.Stream</a>-- <a href="https://auth.openvibe.network/"><i class="fa-solid fa-key" aria-hidden="true"></i>auth.openvibe.network</a>-- <a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>-- <a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>-- <a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>-- <a href="https://ai.openvibe.services/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.services</a>-- <a href="https://openvibe.pics/"><i class="fa-solid fa-images" aria-hidden="true"></i>OpenVibe.Pics</a>-- <a href="https://openvibe.download/"><i class="fa-solid fa-cloud-arrow-down" aria-hidden="true"></i>OpenVibe.Download</a>-- <a href="https://openvibe.space/"><i class="fa-solid fa-layer-group" aria-hidden="true"></i>OpenVibe.Space</a>-- <a href="https://openvibe.food/"><i class="fa-solid fa-utensils" aria-hidden="true"></i>OpenVibe.Food</a>-- <a href="https://openvibe.quest/"><i class="fa-solid fa-map" aria-hidden="true"></i>OpenVibe.Quest</a>-- <a href="https://openvibe.rent/"><i class="fa-solid fa-key" aria-hidden="true"></i>OpenVibe.Rent</a>-- <a href="https://openvibe.homes/"><i class="fa-solid fa-house" aria-hidden="true"></i>OpenVibe.Homes</a>-- <a href="https://openvibe.services/"><i class="fa-solid fa-server" aria-hidden="true"></i>OpenVibe.Services</a>-- <a href="https://openvibe.run/"><i class="fa-solid fa-terminal" aria-hidden="true"></i>OpenVibe.Run</a>-- <a href="https://openvibe.work/"><i class="fa-solid fa-briefcase" aria-hidden="true"></i>OpenVibe.Work</a>-- <a href="https://openvibe.zone/"><i class="fa-solid fa-box-archive" aria-hidden="true"></i>OpenVibe.Zone</a>-- <a href="https://openvibe.video/"><i class="fa-solid fa-film" aria-hidden="true"></i>OpenVibe.Video</a>-- <a href="https://openvibe.website/"><i class="fa-solid fa-globe" aria-hidden="true"></i>OpenVibe.Website</a>-- <a href="https://openvibe.help/"><i class="fa-solid fa-life-ring" aria-hidden="true"></i>OpenVibe.Help</a>-- <a href="https://openvibe.watch/"><i class="fa-solid fa-eye" aria-hidden="true"></i>OpenVibe.Watch</a>-- <a href="https://openvibe.actor/"><i class="fa-solid fa-user-astronaut" aria-hidden="true"></i>OpenVibe.Actor</a>-- <a href="https://openvibe.events/"><i class="fa-solid fa-bolt" aria-hidden="true"></i>OpenVibe.Events</a>-- </div>-- </section>---- <div class="strip">-- <span class="ov-mark" data-size="44" data-variant="bot"></span>-- <h3>Open source. Community run.</h3>-- <p>Every OpenVibe site is built in the open by the people using it — free speech within the rules, no gatekeeping, one identity that follows you everywhere.</p>-- <a class="btn" href="https://github.com/OpenVibers" rel="noopener"><i class="fa-brands fa-github"></i> OpenVibers on GitHub</a>-- </div>--</main>--<style id="ovf-css">--.ovf{background:var(--bg-secondary,#12131c);border-top:1px solid var(--border,rgba(255,255,255,.08));margin-top:40px;-- padding:clamp(24px,4vw,40px) clamp(14px,4vw,32px) calc(clamp(20px,3vw,28px) + env(safe-area-inset-bottom,0px));}--.ovf[data-variant="compact"]{margin-top:24px;padding:14px clamp(12px,3vw,24px) calc(14px + env(safe-area-inset-bottom,0px));}--.ovf-inner{max-width:1240px;margin:0 auto}--.ovf-inner--compact{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:8px 18px;text-align:center}--.ovf-cols{display:grid;gap:clamp(20px,3vw,36px);grid-template-columns:minmax(230px,1.6fr) repeat(auto-fit,minmax(120px,1fr));align-items:start}--.ovf-col{display:flex;flex-direction:column;gap:8px;min-width:0}--.ovf-col h3{margin:0 0 2px;font-size:.72rem;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--text-muted,#8b93ad)}--.ovf-col a{color:var(--text-secondary,#b6bdd2);font-size:.86rem;text-decoration:none;line-height:1.4;width:fit-content;transition:color .15s,transform .15s}--.ovf-col a:hover{color:var(--accent,#60a5fa);transform:translateX(2px)}--.ovf-more{font-weight:600;opacity:.85}.ovf-ic{flex:none;vertical-align:-.14em}.ovf-more .ovf-ic{font-size:.85em;margin-left:3px;transition:transform .15s}.ovf-more:hover .ovf-ic{transform:translateX(3px)}.ovf-social .ovf-ic{font-size:17px}.ovf-account-links .ovf-ic{font-size:1.05em;opacity:.85}--.ovf-brand{display:inline-flex;align-items:center;gap:9px;color:var(--text-primary,#f1f4fb);font-size:1.05rem;font-weight:700;text-decoration:none}--.ovf-brand--sm{font-size:.9rem}--.ovf-tagline{margin:0;font-size:.82rem;line-height:1.55;color:var(--text-muted,#8b93ad);max-width:46ch}--.ovf-social{display:flex;gap:8px;margin-top:4px}--.ovf-social a{width:36px;height:36px;border-radius:10px;display:grid;place-items:center;color:var(--text-secondary,#b6bdd2);-- background:var(--bg-tertiary,#1a1b28);border:1px solid var(--border,rgba(255,255,255,.08));font-size:.95rem;transition:color .15s,border-color .15s,transform .15s}--.ovf-social a:hover{color:var(--accent,#60a5fa);border-color:var(--accent,#60a5fa);transform:translateY(-2px)}--.ovf-account{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px 18px;-- margin-top:clamp(18px,2.5vw,26px);padding:10px 14px;border-radius:14px;-- background:color-mix(in srgb, var(--accent,#60a5fa) 8%, var(--bg-tertiary,#1a1b28));-- border:1px solid color-mix(in srgb, var(--accent,#60a5fa) 26%, var(--border,rgba(255,255,255,.08)));-- animation:ovfIn .4s ease-out both}--@keyframes ovfIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}--.ovf-account-who{display:inline-flex;align-items:center;gap:8px;font-size:.84rem;color:var(--text-secondary,#b6bdd2)}--.ovf-account-who strong{color:var(--text-primary,#f1f4fb)}--.ovf-avatar{width:24px;height:24px;border-radius:50%;overflow:hidden;display:grid;place-items:center;-- background:var(--accent,#60a5fa);color:#fff;font-size:.7rem;font-weight:800;flex:none}--.ovf-avatar img{width:100%;height:100%;object-fit:cover}--.ovf-account-links{display:flex;flex-wrap:wrap;gap:6px}--.ovf-account-links a{display:inline-flex;align-items:center;gap:6px;padding:5px 11px;border-radius:999px;font-size:.78rem;font-weight:600;-- color:var(--text-secondary,#b6bdd2);background:var(--bg-secondary,#12131c);border:1px solid var(--border,rgba(255,255,255,.08));-- text-decoration:none;transition:color .15s,border-color .15s,transform .15s}--.ovf-account-links a:hover{color:var(--accent,#60a5fa);border-color:var(--accent,#60a5fa);transform:translateY(-1px)}--.ovf-account-links i{font-size:.72rem;opacity:.8}--.ovf-bar{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px;-- margin-top:clamp(20px,3vw,30px);padding-top:16px;border-top:1px solid var(--border,rgba(255,255,255,.08));-- padding-inline:clamp(0px, calc(84px - (100vw - 1240px) / 2), 84px)}--.ovf-copy{color:var(--text-muted,#8b93ad);font-size:.78rem}--.ovf-legal-inline,.ovf-compact-links{display:flex;flex-wrap:wrap;gap:14px}--.ovf [hidden],.ovf-account[hidden]{display:none!important}--.ovf .ovf-shipped.ov-shipped-latest{font-size:.76rem;padding:4px 12px;max-width:min(520px,100%);background:transparent}--.ovf-legal-inline a,.ovf-compact-links a{color:var(--text-muted,#8b93ad);font-size:.78rem;text-decoration:none;transition:color .15s}--.ovf-legal-inline a:hover,.ovf-compact-links a:hover{color:var(--accent,#60a5fa)}--.ovf-compact-meta{color:var(--text-muted,#8b93ad);font-size:.74rem}--@media (max-width:900px){.ovf-cols{grid-template-columns:repeat(2,minmax(0,1fr))}.ovf-col--brand{grid-column:1/-1}}--@media (max-width:560px){-- .ovf{padding-bottom:calc(20px + var(--ov-footer-clearance,0px) + env(safe-area-inset-bottom,0px))}-- .ovf[data-variant="compact"]{padding-bottom:calc(14px + var(--ov-footer-clearance,0px) + env(safe-area-inset-bottom,0px))}-- .ovf-cols{gap:22px 16px}-- .ovf-bar{justify-content:center;text-align:center;padding-inline:0}-- .ovf-legal-inline{justify-content:center}-- .ovf-account{flex-direction:column;align-items:flex-start}--}--@media (prefers-reduced-motion:reduce){.ovf-account{animation:none}.ovf-col a:hover,.ovf-social a:hover,.ovf-account-links a:hover{transform:none}}--.ovf{-webkit-tap-highlight-color:transparent}--:where(.ovf) :where(a,button):active{scale:.97}--:where(.ovf) :where(a,button):focus-visible{outline:2px solid var(--accent-light,var(--accent,#3b82f6));outline-offset:2px;border-radius:4px}--@media (prefers-reduced-motion:reduce){:where(.ovf) :where(a,button):active{scale:none;opacity:.82}}</style><footer id="ov-footer" class="ovf" data-variant="full"><div class="ovf-inner">-- <div class="ovf-cols">-- <div class="ovf-col ovf-col--brand">-- <a class="ovf-brand" href="/"><span class="ov-mark" data-size="26"></span><span>OpenVibe</span></a>-- <p class="ovf-tagline">Open source and community run. Built in the open by the people using it.</p>-- <div class="ovf-social">-- <a href="https://github.com/OpenVibers" target="_blank" rel="noopener" aria-label="GitHub" title="GitHub"><svg class="ovf-ic" viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="1.800" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path fill="currentColor" stroke="none" d="M12 2.2a9.8 9.8 0 0 0-3.1 19.1c.5.1.7-.2.7-.5v-1.7c-2.7.6-3.3-1.2-3.3-1.2-.4-1.1-1.1-1.4-1.1-1.4-.9-.6.1-.6.1-.6 1 .1 1.5 1 1.5 1 .9 1.5 2.3 1.1 2.9.8.1-.6.3-1.1.6-1.3-2.2-.2-4.5-1.1-4.5-4.8 0-1.1.4-1.9 1-2.6-.1-.2-.4-1.2.1-2.6 0 0 .8-.3 2.7 1a9.3 9.3 0 0 1 4.9 0c1.9-1.3 2.7-1 2.7-1 .5 1.4.2 2.4.1 2.6.6.7 1 1.5 1 2.6 0 3.7-2.3 4.6-4.5 4.8.4.3.7.9.7 1.800v2.700c0 .3.2.6.7.5A9.8 9.8 0 0 0 12 2.200z"/></svg></a><a href="https://discord.gg/M6MuRUaeJj" target="_blank" rel="noopener" aria-label="Discord" title="Discord"><svg class="ovf-ic" viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="1.800" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path fill="currentColor" stroke="none" d="M19.3 5.300a16.5 16.5 0 0 0-4.1-1.300l-.5 1a15.3 15.3 0 0 0-5.4 0l-.5-1a16.5 16.5 0 0 0-4.1 1.300C2.1 9.2 1.4 13 1.7 16.700a16.6 16.6 0 0 0 5.1 2.600l1.1-1.800c-.6-.2-1.2-.5-1.7-.8l.4-.3a11.8 11.8 0 0 0 10.8 0l.4.3c-.5.3-1.1.6-1.7.8l1.1 1.800a16.6 16.6 0 0 0 5.1-2.600c.4-4.3-.7-8.1-3-11.400zM8.7 14.400c-1 0-1.8-.9-1.8-2.100s.8-2.1 1.8-2.1 1.9 1 1.8 2.100c0 1.2-.8 2.1-1.8 2.100zm6.6 0c-1 0-1.8-.9-1.8-2.100s.8-2.1 1.8-2.1 1.9 1 1.8 2.100c0 1.2-.8 2.1-1.8 2.100z"/></svg></a>-- <a href="/sitemap.xml" aria-label="Sitemap" title="Sitemap"><svg class="ovf-ic" viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="1.800" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect x="9" y="3.5" width="6" height="4.5" rx="1"/><rect x="3" y="16" width="6" height="4.5" rx="1"/><rect x="15" y="16" width="6" height="4.5" rx="1"/><path d="M12 8v4M6 16v-2.500h12V16"/></svg></a>-- </div>-- </div>---- <nav class="ovf-col" aria-label="The OpenVibe network">-- <h3>Network</h3>-- <a href="https://openvibe.live" title="Go live, restream and clip">Live streaming</a><a href="https://openvibe.tools" title="The whole toolbox">Online tools</a><a href="https://dev.openvibe.tools" title="Formatters, encoders, validators">Developer tools</a><a href="https://net.openvibe.tools" title="Ping, DNS, Whois, SSL">Network diagnostics</a><a href="https://img.openvibe.tools" title="Convert, resize, compress">Image converter</a><a href="https://audio.openvibe.tools" title="Convert, trim, pitch-shift">Audio converter</a>-- <a class="ovf-more" href="https://openvibe.network" target="_blank" rel="noopener">Everything else <svg class="ovf-ic" viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="1.800" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6"/></svg></a>-- </nav>---- <nav class="ovf-col" aria-label="Legal">-- <h3>Legal</h3>-- <a href="https://openvibe.live/tos">Terms of Service</a><a href="https://openvibe.live/privacy">Privacy Policy</a><a href="https://openvibe.live/dmca">DMCA</a>-- </nav>-- </div>-- <div class="ovf-account" id="ovf-account" hidden></div>-- <div class="ovf-bar">-- <span class="ovf-copy">Open source & community driven · built in the open</span>-- <a class="ovf-shipped" data-ov-shipped="latest" data-service="bot" href="https://openvibe.network/updates?site=bot" hidden></a>-- <span class="ovf-legal-inline">-- <a href="https://openvibe.network/updates?site=bot">Updates</a>-- <a href="https://openvibe.live/tos">Terms</a><a href="https://openvibe.live/privacy">Privacy</a><a href="https://openvibe.live/dmca">DMCA</a>-- </span>-- </div>-- </div></footer>--<script src="/shared/ov-mark.js?v=03f3596adcab" async></script>--<script src="/shared/navbar.js?v=017a740747b4"></script>--<script src="/shared/footer.js?v=a85ab893be88"></script>--<script>--(function () {-- if (window.OpenVibeNavbar) { try { OpenVibeNavbar.init({ service: 'bot', apiBase: 'https://openvibe.network', links: [{ label: 'How it works', href: '#what' }, { label: 'The network', href: 'https://openvibe.network/#network', external: false }], history: { type: 'page', title: 'OpenVibe.Bot' } }); } catch (e) {} }-- if (window.OpenVibeFooter) { try { OpenVibeFooter.init({ service: 'bot', variant: 'full', links: [{ heading: 'OpenVibe.Bot', items: [{ name: 'Sign in', url: 'https://openvibe.network/login?return=https%3A%2F%2Fopenvibe.bot%2F' }, { name: 'The network', url: 'https://openvibe.network/#network' }, { name: 'Discord', url: 'https://discord.gg/M6MuRUaeJj' }] }] }); } catch (e) {} }--})();--</script>--</body>--</html>ddeleted file mode 100644@@@ -1,13 +0,0 @@--{-- "service": "bot",-- "release": "8512ce660c7e",-- "released_at": "2026-10-03T00:00:00.000Z",-- "booted_at": null,-- "contracts_version": null,-- "packages": {-- "openvibe-shared": "2.5.0"-- },-- "min_client_release": null,-- "mixed_version_window_hours": 24,-- "kind": "placeholder"--}ddeleted file mode 100644@@@ -1,4 +0,0 @@--User-agent: *--Allow: /--Disallow: /auth/--Sitemap: https://openvibe.bot/sitemap.xmlddeleted file mode 100644@@@ -1,16 +0,0 @@--{-- "domain": "openvibe.bot",-- "name": "OpenVibe.Bot",-- "stage": "placeholder",-- "live": false,-- "plannedRepo": null,-- "repoUrl": null,-- "repoExists": false,-- "repoStage": "charter-only",-- "service": null,-- "launchWaitsFor": "the Bot service, its device agent and the first robots paired",-- "factsAsOf": "2026-09-29",-- "network": "https://openvibe.network",-- "updated": "2026-10-03",-- "note": "Static page served by OpenVibers/OpenVibe.Sites; service facts come from each repository's STATUS.json and the Network registry (facts.json). Removed from sites.json in the same release that the real service takes over this domain."--}@@@ -12,7 +12,7 @@ the release in which the product's own vhost is installed.domain yet. When the Sites vhost goes, the record stays in DNS (Cloudflare) and nothing on the host answers it.The Sites repository had 33 host files on 2026-10-02 (the plan said 36), one per `sites.json` entry. Since then OpenVibe.Bot--supplies the `openvibe.bot` vhost (Sites keeps publishing its frozen pages), and `openvibe.work` and `openvibe.zone` were++supplies the `openvibe.bot` vhost and, since 2026-10-07, serves its own front page (Sites keeps only its legal pages there), and `openvibe.work` and `openvibe.zone` wereadded; they have no Contracts manifest yet, so `sync-catalog.js` keeps them as they are. That makes 34 host files for 35`sites.json` entries.@@@ -25,7 +25,7 @@ added; they have no Contracts manifest yet, so `sync-catalog.js` keeps them as t| `auth.openvibe.network.conf` | placeholder | OpenVibe.Network | no || `openre.stream.conf` | placeholder | OpenRe.Stream | yes: `deploy/nginx/openre.stream.conf` || `openvibe.actor.conf` | placeholder (no repo) | park: DNS only (OpenVibe.Node exists but has no deploy config and does not run) | no |--| (`openvibe.bot`, no Sites host file) | placeholder (no repo) | OpenVibe.Bot, which already supplies the vhost; Sites keeps only the frozen pages | yes (Contracts still says `noRepo`) |++| (`openvibe.bot`, no Sites host file) | legal pages, 404, sitemap and manifest (its front page, robots.txt, release.json and status.json are Bot's since 2026-10-07, OpenVibe.Bot#34) | OpenVibe.Bot, which already supplies the vhost | yes (Contracts still says `noRepo`) || `openvibe.coupons.conf` | placeholder | OpenVibe.Coupons | yes: `deploy/nginx/openvibe.coupons.conf` || `openvibe.deals.conf` | placeholder | OpenVibe.Deals | yes: `deploy/nginx/openvibe.deals.conf` || `openvibe.download.conf` | placeholder (no repo) | park: DNS only (Contracts names OpenVibe.MediaHub, which does not exist yet) | no |@@@ -29,6 +29,5 @@"openvibe.help","openvibe.watch","openvibe.events",-- "openvibe.actor",-- "openvibe.bot"++ "openvibe.actor"]@@@ -18,14 +18,20 @@ assert.deepStrictEqual(notices.map(n => n.domain), ['ai.openvibe.network', 'realtime.openvibe.network', 'status.openvibe.network',]);assert.strictEqual(new Set(frozen).size, frozen.length, 'frozen domains are unique');--assert.strictEqual(frozen.length, 32, 'all 32 product domains are frozen');++assert.strictEqual(frozen.length, 31, 'all 31 product domains are frozen');const active = new Set(notices.map(n => n.domain));for (const domain of frozen) {assert.ok(!active.has(domain), `${domain}: product is not a notice`);assert.ok(exists(`dist/${domain}/index.html`), `${domain}: frozen front page`);-- if (domain !== 'openvibe.bot') assert.ok(exists(`deploy/nginx/${domain}.conf`), `${domain}: frozen vhost`);++ assert.ok(exists(`deploy/nginx/${domain}.conf`), `${domain}: frozen vhost`);}assert.ok(!exists('deploy/nginx/openvibe.bot.conf'), 'Bot owns its vhost');++// OpenVibe.Bot serves its own front page, robots.txt, release.json and status.json (OpenVibe.Bot#34,++// 2026-10-07); Sites keeps only the legal pages, 404 page, sitemap and manifest for openvibe.bot.++assert.deepStrictEqual(fs.readdirSync(path.join(ROOT, 'dist/openvibe.bot')).sort(),++ ['404.html', 'dmca.html', 'manifest.webmanifest', 'privacy.html', 'sitemap.xml', 'terms.html'],++ 'openvibe.bot holds only its legal pages, 404, sitemap and manifest (Bot#34)');++assert.ok(!exists('dist/openvibe.bot/index.html'), 'openvibe.bot has no Sites front page (Bot#34)');// A frozen placeholder never claims a product is live, never uses pricing copy (no "free"/"$0"/"no ads"; "free// speech" is fine) and never offers hosting no OpenVibe service provides (2026-09-24 audit).const PRICING = /\$0\b|\bfor free\b|\bfree (forever|to use|of charge|plan|tier)\b|\bno ads\b|\bad-free\b/i;@@@ -36,7 +42,7 @@ for (const domain of frozen) {assert.doesNotMatch(html, PRICING, `${domain}: pricing copy`);assert.doesNotMatch(html, UNBACKED, `${domain}: claims a hosting product that does not exist`);}--for (const domain of ['openvibe.actor', 'openvibe.bot']) {++for (const domain of ['openvibe.actor']) {assert.ok(frozen.includes(domain), `${domain}: remains frozen`);assert.match(read(`dist/${domain}/index.html`), /<meta name="robots" content="index, follow, max-image-preview:large">/, `${domain}: original indexing`);assert.strictEqual(JSON.parse(read(`dist/${domain}/status.json`)).stage, 'placeholder', `${domain}: lifecycle stage`);
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
# OpenVibe.Sites
# OpenVibe.Sites
-OpenVibe.Sites serves static notices for three addresses during the domain handoff. It no longer builds product placeholders. `notices.json` is the build input; `frozen.json` records the 32 product domains whose existing `dist/<domain>/index.html` and nginx vhosts remain in place until their owners complete the DNS and nginx cutover. OpenVibe.Bot owns its own vhost.
+OpenVibe.Sites serves static notices for three addresses during the domain handoff. It no longer builds product placeholders. `notices.json` is the build input; `frozen.json` records the 31 product domains whose existing `dist/<domain>/index.html` and nginx vhosts remain in place until their owners complete the DNS and nginx cutover. OpenVibe.Bot serves its own front page, robots.txt, release.json and status.json (OpenVibe.Bot#34, 2026-10-07), so Sites keeps only its legal pages, 404 page, sitemap and manifest there.
## Remaining notices
## Remaining notices
@@ -14,7 +14,7 @@ All three are `noindex`. The existing page presentation is held in `notice-pages
@@ -14,7 +14,7 @@ All three are `noindex`. The existing page presentation is held in `notice-pages
## Frozen product pages
## Frozen product pages
-`frozen.json` lists all 32 product domains, including OpenVibe.Actor and OpenVibe.Bot. Their committed front pages remain available as static files with their original indexing, status, and sitemaps. The build does not regenerate them. `node build.js --check` verifies that each frozen domain still has an index page and a Sites vhost where Sites owns one, while checking that notice outputs are current. The repository facts snapshot is historical data, not a build input.
+`frozen.json` lists all 31 product domains, including OpenVibe.Actor. Their committed front pages remain available as static files with their original indexing, status, and sitemaps. The build does not regenerate them. `node build.js --check` verifies that each frozen domain still has an index page and a Sites vhost, while checking that notice outputs are current. The repository facts snapshot is historical data, not a build input.
## Product catalog
## Product catalog
@@ -42,7 +42,7 @@
@@ -42,7 +42,7 @@
"deployed": true,
"deployed": true,
"deployment": "Deployed with `sudo ovhost deploy sites --restart` (OpenVibe.Host strategy static-build since the 2026-09-27 cutover): /opt/openvibe.sites, nginx serves dist/<domain>/ through deploy/nginx/<domain>.conf; no unit, no port, no env file",
"deployment": "Deployed with `sudo ovhost deploy sites --restart` (OpenVibe.Host strategy static-build since the 2026-09-27 cutover): /opt/openvibe.sites, nginx serves dist/<domain>/ through deploy/nginx/<domain>.conf; no unit, no port, no env file",
"features": [
"features": [
- "three generated notices and 32 frozen product domains",
+ "three generated notices and 31 frozen product domains",
"sites.json generated from the OpenVibe.Contracts product catalog",
"sites.json generated from the OpenVibe.Contracts product catalog",
"notice pages use preserved presentation; product pages are no longer generated",
"notice pages use preserved presentation; product pages are no longer generated",
"the pinned OpenVibe Frame served from dist/_shared/",
"the pinned OpenVibe Frame served from dist/_shared/",
@@ -50,5 +50,5 @@
@@ -50,5 +50,5 @@
"generated notice vhosts and preserved product vhosts",
"generated notice vhosts and preserved product vhosts",
"a release.json per domain and host.release.published on deploy"
"a release.json per domain and host.release.published on deploy"
],
],
- "updated": "2026-10-03"
+ "updated": "2026-10-07"
}
}
@@ -200,9 +200,7 @@ function verifyFrozen() {
@@ -200,9 +200,7 @@ function verifyFrozen() {
let missing = 0;
let missing = 0;
for (const domain of frozen) {
for (const domain of frozen) {
if (noticeDomains.has(domain)) { console.error(`frozen domain is also a notice: ${domain}`); missing++; }
if (noticeDomains.has(domain)) { console.error(`frozen domain is also a notice: ${domain}`); missing++; }
- // Bot's own repository supplies its vhost; Sites keeps only its frozen files.
- const files = [`dist/${domain}/index.html`, ...(domain === 'openvibe.bot' ? [] : [`deploy/nginx/${domain}.conf`])];
- for (const file of files) {
+ for (const file of [`dist/${domain}/index.html`, `deploy/nginx/${domain}.conf`]) {
if (!fs.existsSync(path.join(ROOT, file))) { console.error(`missing frozen file: ${file}`); missing++; }
if (!fs.existsSync(path.join(ROOT, file))) { console.error(`missing frozen file: ${file}`); missing++; }
}
}
}
}
deleted file mode 100644
deleted file mode 100644
@@ -1,398 +0,0 @@
@@ -1,398 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>OpenVibe.Bot — Get your robot online in minutes.</title>
-<meta name="description" content="OpenVibe.Bot is an open control panel for robots. Add a robot, pair it with one command or a QR code, and drive it from any browser with live video, real controls and a stop button that always works. Buy a ready-made bot or bring your own: a Raspberry Pi robot, an ESP32, a ROS 2 robot, a phone, or a Cozmo. Share control, automate it, hand it to your AI agent, and stream it to OpenVibe.Live or openre.stream when you want to.">
-<meta name="keywords" content="robot control panel, control a robot from the browser, remote control robot online, raspberry pi robot web control, esp32 robot control, ros 2 web control, telepresence robot, stream a robot live, open source robot controller, cozmo remote control, cozmo web control, cozmo sdk alternative">
-<meta name="robots" content="index, follow, max-image-preview:large">
-<meta name="theme-color" content="#f472b6">
-<link rel="canonical" href="https://openvibe.bot/">
-<link rel="icon" type="image/svg+xml" data-ov-icon="network" href="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%22-32%20-32%2064%2064%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22ring%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%221%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2360a5fa%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%232563eb%22%2F%3E%3C%2FlinearGradient%3E%0A%3CradialGradient%20id%3D%22glow%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2360a5fa%22%20stop-opacity%3D%22.34%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%2360a5fa%22%20stop-opacity%3D%220%22%2F%3E%3C%2FradialGradient%3E%0A%3CradialGradient%20id%3D%22bg%22%20cx%3D%22.5%22%20cy%3D%22.38%22%20r%3D%22.8%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2316223a%22%2F%3E%3Cstop%20offset%3D%22.6%22%20stop-color%3D%22%230a0f1c%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23060912%22%2F%3E%3C%2FradialGradient%3E%3C%2Fdefs%3E%3Crect%20x%3D%22-32%22%20y%3D%22-32%22%20width%3D%2264%22%20height%3D%2264%22%20rx%3D%2215%22%20fill%3D%22url(%23bg)%22%2F%3E%3Cg%20transform%3D%22scale(1.22)%22%3E%0A%3Ccircle%20r%3D%2221%22%20fill%3D%22url(%23glow)%22%2F%3E%0A%3Ccircle%20r%3D%2218%22%20fill%3D%22none%22%20stroke%3D%22url(%23ring)%22%20stroke-width%3D%224%22%20opacity%3D%22.38%22%2F%3E%0A%3Cpath%20d%3D%22M0%2C-18%20A18%2C18%200%200%2C1%2017.4%2C4.6%22%20fill%3D%22none%22%20stroke%3D%22url(%23ring)%22%20stroke-width%3D%224.4%22%20stroke-linecap%3D%22round%22%2F%3E%0A%3Cpath%20d%3D%22M-9.5%2C-7%20L0%2C10%20L9.5%2C-7%22%20fill%3D%22none%22%20stroke%3D%22%23fff%22%20stroke-width%3D%224.8%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%0A%3Ccircle%20cx%3D%2217.4%22%20cy%3D%224.6%22%20r%3D%223.2%22%20fill%3D%22%23ffffff%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E">
-<style id="ov-critical">html{background:#0a0f1c;color:#e6edf7;color-scheme:dark}</style><script>(function(){try{var r=localStorage.getItem('ov_theme');if(!r)return;var t=JSON.parse(r),v=t&&t.variables;if(!v)return;var e=document.documentElement;for(var k in v)if(k.charAt(0)==='-')e.style.setProperty(k,v[k]);if(v['--bg-primary'])e.style.background=v['--bg-primary'];if(v['--text-primary'])e.style.color=v['--text-primary'];if(v['--color-scheme']==='light'||v['--color-scheme']==='dark')e.style.colorScheme=v['--color-scheme'];if(t.id)e.setAttribute('data-theme',t.id)}catch(_){}})();</script>
-<link rel="manifest" href="/manifest.webmanifest">
-<link rel="alternate" type="text/html" hreflang="en" href="https://openvibe.bot/">
-<meta property="og:type" content="website">
-<meta property="og:site_name" content="OpenVibe.Bot">
-<meta property="og:url" content="https://openvibe.bot/">
-<meta property="og:title" content="OpenVibe.Bot — Get your robot online in minutes.">
-<meta property="og:description" content="OpenVibe.Bot is an open control panel for robots. Add a robot, pair it with one command or a QR code, and drive it from any browser with live video, real controls and a stop button that always works. Buy a ready-made bot or bring your own: a Raspberry Pi robot, an ESP32, a ROS 2 robot, a phone, or a Cozmo. Share control, automate it, hand it to your AI agent, and stream it to OpenVibe.Live or openre.stream when you want to.">
-<meta property="og:image" content="https://openvibe.network/assets/logo-512.png">
-<meta property="og:image:alt" content="OpenVibe">
-<meta name="twitter:card" content="summary">
-<meta name="twitter:title" content="OpenVibe.Bot — Get your robot online in minutes.">
-<meta name="twitter:description" content="OpenVibe.Bot is an open control panel for robots. Add a robot, pair it with one command or a QR code, and drive it from any browser with live video, real controls and a stop button that always works. Buy a ready-made bot or bring your own: a Raspberry Pi robot, an ESP32, a ROS 2 robot, a phone, or a Cozmo. Share control, automate it, hand it to your AI agent, and stream it to OpenVibe.Live or openre.stream when you want to.">
-<meta name="twitter:image" content="https://openvibe.network/assets/logo-512.png">
-<script type="application/ld+json">{"@context":"https://schema.org","@graph":[{"@type":"WebSite","@id":"https://openvibe.bot/#site","url":"https://openvibe.bot/","name":"OpenVibe.Bot","description":"OpenVibe.Bot is an open control panel for robots. Add a robot, pair it with one command or a QR code, and drive it from any browser with live video, real controls and a stop button that always works. Buy a ready-made bot or bring your own: a Raspberry Pi robot, an ESP32, a ROS 2 robot, a phone, or a Cozmo. Share control, automate it, hand it to your AI agent, and stream it to OpenVibe.Live or openre.stream when you want to.","inLanguage":"en","publisher":{"@type":"Organization","@id":"https://openvibe.network/#org","name":"OpenVibe","url":"https://openvibe.network/","logo":"https://openvibe.network/assets/logo-512.png","sameAs":["https://github.com/OpenVibers","https://discord.gg/M6MuRUaeJj"]},"isPartOf":{"@type":"WebSite","@id":"https://openvibe.network/#site","name":"OpenVibe.Network","url":"https://openvibe.network/"}},{"@type":"WebPage","@id":"https://openvibe.bot/#page","url":"https://openvibe.bot/","name":"OpenVibe.Bot — Get your robot online in minutes.","description":"OpenVibe.Bot is an open control panel for robots. Add a robot, pair it with one command or a QR code, and drive it from any browser with live video, real controls and a stop button that always works. Buy a ready-made bot or bring your own: a Raspberry Pi robot, an ESP32, a ROS 2 robot, a phone, or a Cozmo. Share control, automate it, hand it to your AI agent, and stream it to OpenVibe.Live or openre.stream when you want to.","isPartOf":{"@id":"https://openvibe.bot/#site"},"datePublished":"2026-09-17","dateModified":"2026-10-03","breadcrumb":{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"OpenVibe","item":"https://openvibe.network/"},{"@type":"ListItem","position":2,"name":"OpenVibe.Bot","item":"https://openvibe.bot/"}]}},{"@type":"FAQPage","@id":"https://openvibe.bot/#faq","mainEntity":[{"@type":"Question","name":"Do I need to open ports on my router?","acceptedAnswer":{"@type":"Answer","text":"No. The robot connects out to OpenVibe, and video and controls travel over WebRTC, so it works behind ordinary home and mobile networks."}},{"@type":"Question","name":"Is it only for streaming?","acceptedAnswer":{"@type":"Answer","text":"No. Streaming is optional. Bot is a control panel for your robot first: drive it, check on it, share it and automate it."}},{"@type":"Question","name":"Which robot comes first?","acceptedAnswer":{"@type":"Answer","text":"The Adeept 4WD Smart Car Kit for Raspberry Pi: four motors, a pan-tilt camera, distance and line sensors, lights and a buzzer. OpenVibe's device agent drives it directly, so its own open control port never has to be exposed."}},{"@type":"Question","name":"Does it work with Cozmo?","acceptedAnswer":{"@type":"Answer","text":"Yes, built in. Cozmo makes its own Wi-Fi and runs closed firmware, so the OpenVibe agent runs on a computer next to it (a Raspberry Pi or a laptop) that joins Cozmo's Wi-Fi and stays online through another connection. You get driving, the head and lift, its camera, its face display, its voice, lights and cubes, and it stops at edges on its own. No phone app needed."}},{"@type":"Question","name":"What hardware works?","acceptedAnswer":{"@type":"Answer","text":"A Raspberry Pi or another Linux board, an ESP32, a ROS 2 robot, an Android phone, or an ONVIF or RTSP camera. The curated kits list exactly what to buy."}},{"@type":"Question","name":"How does it keep the robot safe?","acceptedAnswer":{"@type":"Answer","text":"The device stops its motors by itself when commands or the connection stop. There is an emergency stop in the panel, limits on speed, range and time, and every command is logged."}},{"@type":"Question","name":"What will it cost?","acceptedAnswer":{"@type":"Answer","text":"Controlling your own robot will not cost anything. Limits and any paid extras will be published before launch."}}]}]}</script>
-<script>(function(){try{var raw=localStorage.getItem('ov_theme');if(!raw)return;var t=JSON.parse(raw),v=t&&t.variables;if(!v)return;var el=document.documentElement;for(var k in v)if(k.charAt(0)==='-')el.style.setProperty(k,v[k]);if(t.id)el.setAttribute('data-theme',t.id);}catch(_){}})();</script>
-<script src="/shared/theme-loader.js?v=ee4a6754d0f7" defer></script>
-<link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin>
-<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" media="print" onload="this.media='all'">
-<noscript><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"></noscript>
-<style>
-*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
-:root{--bg-primary:#0a0f1c;--bg-secondary:#101828;--bg-card:#131c2e;--bg-hover:#1c2a44;--border:#1f2d47;--text-primary:#e6edf7;--text-secondary:#96a7c2;--text-muted:#7386a3;--accent:#3b82f6;--accent-light:#60a5fa;--accent-rgb:59,130,246;--on-accent:#fff;--site:#f472b6;--site-rgb:244,114,182}
-html{scroll-behavior:smooth}
-body{background:var(--bg-primary);color:var(--text-primary);font-family:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;min-height:100vh;display:flex;flex-direction:column;overflow-x:hidden}
-main{flex:1;position:relative}
-.orbs{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden}
-.orbs i{position:absolute;border-radius:50%;filter:blur(90px);opacity:.16;animation:drift 26s ease-in-out infinite alternate}
-.orbs i:nth-child(1){width:420px;height:420px;background:var(--site);top:-140px;left:-120px}
-.orbs i:nth-child(2){width:360px;height:360px;background:var(--accent);top:40%;right:-140px;animation-delay:-9s}
-.orbs i:nth-child(3){width:300px;height:300px;background:var(--site);bottom:-120px;left:38%;animation-delay:-17s}
-@keyframes drift{0%{transform:translate(0,0) scale(1)}50%{transform:translate(-26px,36px) scale(1.07)}100%{transform:translate(34px,-28px) scale(.95)}}
-.wrap{position:relative;z-index:1;max-width:1040px;margin:0 auto;padding:0 20px}
-.hero{padding:84px 0 44px;text-align:center}
-.hero .mark{display:inline-grid;place-items:center;width:84px;height:84px;border-radius:24px;background:rgba(var(--site-rgb),.12);border:1px solid rgba(var(--site-rgb),.35);color:var(--site);font-size:34px;margin-bottom:22px;box-shadow:0 20px 60px rgba(var(--site-rgb),.18);animation:rise .6s cubic-bezier(.2,.8,.2,1) both}
-.hero .badge{display:inline-flex;align-items:center;gap:8px;padding:6px 14px;border-radius:999px;border:1px solid var(--border);background:var(--bg-secondary);font-size:12px;font-weight:600;color:var(--text-secondary);letter-spacing:.3px;margin-bottom:22px;animation:rise .6s .05s cubic-bezier(.2,.8,.2,1) both}
-.hero .badge b{color:var(--site)}
-.hero h1{font-size:clamp(34px,6vw,58px);font-weight:800;letter-spacing:-1.4px;line-height:1.08;animation:rise .6s .1s cubic-bezier(.2,.8,.2,1) both}
-.hero h1 .d{color:var(--site)}
-.hero h1 .tld{color:var(--text-secondary)}
-.hero .tag{font-size:clamp(18px,2.6vw,24px);font-weight:600;color:var(--text-primary);margin:18px 0 10px;animation:rise .6s .16s cubic-bezier(.2,.8,.2,1) both}
-.hero p.lead{color:var(--text-secondary);font-size:16px;line-height:1.65;max-width:680px;margin:0 auto;animation:rise .6s .22s cubic-bezier(.2,.8,.2,1) both}
-.ctas{display:flex;flex-wrap:wrap;gap:12px;justify-content:center;margin-top:30px;animation:rise .6s .3s cubic-bezier(.2,.8,.2,1) both}
-.hero .status{margin:22px auto 0;max-width:720px;font-size:12.5px;line-height:1.7;color:var(--text-muted);border:1px dashed var(--border);border-radius:12px;padding:10px 14px;background:rgba(0,0,0,.15)}
-.hero .status b{color:var(--site)}
-.hero .status code{font-size:12px;color:var(--text-secondary);background:var(--bg-secondary);padding:1px 6px;border-radius:6px}
-.hero .status a{color:var(--text-secondary)}
-.btn{display:inline-flex;align-items:center;gap:9px;padding:12px 20px;border-radius:12px;font-size:14px;font-weight:600;text-decoration:none;border:1px solid var(--border);color:var(--text-primary);background:var(--bg-secondary);transition:transform .15s,border-color .15s,box-shadow .15s}
-.btn:hover{transform:translateY(-1px);border-color:var(--site);box-shadow:0 10px 30px rgba(var(--site-rgb),.15)}
-.btn-primary{background:var(--site);border-color:var(--site);color:#0b0d10}
-.btn-primary:hover{filter:brightness(1.08)}
-@keyframes rise{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
-section{padding:36px 0}
-h2{font-size:22px;font-weight:700;letter-spacing:-.3px;margin-bottom:6px}
-.lead2{color:var(--text-secondary);font-size:14px;margin-bottom:20px}
-.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:14px}
-.card{background:var(--bg-card);border:1px solid var(--border);border-radius:16px;padding:20px;transition:transform .2s,border-color .2s,box-shadow .2s;text-decoration:none;color:inherit;display:flex;flex-direction:column;gap:8px}
-a.card:hover{transform:translateY(-3px);border-color:rgba(var(--site-rgb),.6);box-shadow:0 16px 40px rgba(0,0,0,.35)}
-.card .ic{width:40px;height:40px;border-radius:11px;display:grid;place-items:center;background:rgba(var(--site-rgb),.12);color:var(--site);font-size:17px}
-.card b{font-size:15px}
-.card span{font-size:13px;color:var(--text-secondary);line-height:1.55}
-.card .go{margin-top:auto;font-size:12.5px;font-weight:600;color:var(--site)}
-.highlight .hl-card{border:1px solid rgba(var(--accent-rgb),.45);background:rgba(var(--accent-rgb),.10);border-radius:18px;padding:22px 22px 18px}
-.highlight h2{margin:0 0 8px}.highlight h2 i{color:var(--accent-light)}.highlight p{margin:0 0 10px}
-.highlight ul{margin:0 0 14px;padding-left:20px}.highlight li{margin:4px 0}
-.faq details{border:1px solid rgba(255,255,255,.08);border-radius:12px;padding:12px 14px;margin:8px 0}
-.faq summary{cursor:pointer;font-weight:600}.faq details p{margin:8px 0 0;opacity:.85}
-.meanwhile .card .ic{background:rgba(var(--accent-rgb),.12);color:var(--accent-light)}
-.net .card .ic{background:var(--bg-hover);color:var(--text-primary)}
-.rooms{display:flex;flex-wrap:wrap;gap:8px}
-.rooms a{font-size:12.5px;padding:7px 12px;border-radius:999px;border:1px solid var(--border);color:var(--text-secondary);text-decoration:none;transition:all .15s;background:var(--bg-secondary)}
-.rooms a:hover{color:var(--text-primary);border-color:var(--site)}
-.rooms a i{margin-right:6px;opacity:.8}
-.strip{border:1px solid var(--border);border-radius:18px;background:var(--bg-secondary);padding:30px 26px;text-align:center;margin:10px 0 50px}
-.strip h3{font-size:19px;font-weight:700;margin:12px 0 8px}
-.strip p{font-size:14px;color:var(--text-secondary);max-width:600px;margin:0 auto 18px;line-height:1.6}
-.strip .ov-mark{width:44px;height:44px}
-.hero.split{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);gap:40px;align-items:center;text-align:left;padding-top:64px}
-.hero.split .ctas{justify-content:flex-start}.hero.split p.lead{margin:0}
-.viz{background:var(--bg-card);border:1px solid var(--border);border-radius:20px;padding:14px;box-shadow:0 30px 80px rgba(0,0,0,.45),0 0 0 1px rgba(var(--site-rgb),.08);animation:rise .7s .25s cubic-bezier(.2,.8,.2,1) both;text-align:left}
-.viz figcaption{margin-top:10px;font-size:11.5px;color:var(--text-muted);text-align:center}
-.viz-top{display:flex;align-items:center;gap:8px;font-size:13px;padding:2px 4px 12px}
-.viz-top b{font-weight:700}.viz-top .muted{color:var(--text-muted)}
-.viz-top .lat{margin-left:auto;font-size:12px;color:var(--site);background:rgba(var(--site-rgb),.1);border:1px solid rgba(var(--site-rgb),.3);padding:3px 9px;border-radius:999px}
-.viz-top .dot{width:8px;height:8px;border-radius:50%;background:#22c55e;box-shadow:0 0 0 4px rgba(34,197,94,.18)}
-.viz-top .av{width:26px;height:26px;border-radius:8px;display:grid;place-items:center;background:rgba(var(--site-rgb),.15);color:var(--site);font-size:13px}
-.viz-video{position:relative;aspect-ratio:16/9;border-radius:14px;overflow:hidden;background:radial-gradient(120% 90% at 30% 20%,rgba(var(--site-rgb),.28),transparent 60%),linear-gradient(160deg,#1a2338,#0b1020 70%);border:1px solid var(--border)}
-.viz-video::after{content:'';position:absolute;left:10%;right:10%;bottom:0;height:42%;background:linear-gradient(transparent,rgba(0,0,0,.35)),repeating-linear-gradient(90deg,rgba(255,255,255,.05) 0 1px,transparent 1px 38px);transform:perspective(220px) rotateX(58deg);transform-origin:bottom}
-.viz-video .scan{position:absolute;inset:0;background:linear-gradient(transparent 0,rgba(255,255,255,.04) 50%,transparent 100%);background-size:100% 6px;opacity:.5}
-.viz-video .onair{position:absolute;top:10px;left:10px;font-size:11px;font-weight:700;padding:3px 8px;border-radius:6px;background:rgba(239,68,68,.9);color:#fff}.viz-video .onair i{font-size:7px;vertical-align:2px;margin-right:3px}
-.viz-video .cam{position:absolute;bottom:10px;right:10px;font-size:11px;color:#dbe4f5;background:rgba(0,0,0,.45);padding:3px 8px;border-radius:6px}
-.viz-ctrl{display:flex;gap:14px;align-items:center;margin-top:12px}
-.dpad{display:grid;grid-template-columns:repeat(3,34px);grid-template-rows:repeat(3,34px);gap:4px;flex:none}
-.dpad span{display:grid;place-items:center;border-radius:9px;background:var(--bg-hover);color:var(--text-primary);font-size:15px;border:1px solid var(--border)}
-.dpad .u{grid-area:1/2}.dpad .l{grid-area:2/1}.dpad .c{grid-area:2/2;background:rgba(var(--site-rgb),.15);border-color:rgba(var(--site-rgb),.35)}.dpad .r{grid-area:2/3}.dpad .d{grid-area:3/2}
-.dpad .u{background:rgba(var(--site-rgb),.22);border-color:rgba(var(--site-rgb),.5)}
-.viz-side{flex:1;min-width:0;display:grid;gap:8px}
-.viz-side .keys{display:flex;flex-wrap:wrap;gap:6px}
-.viz-side .keys span{font-size:11.5px;padding:5px 9px;border-radius:8px;background:var(--bg-secondary);border:1px solid var(--border);color:var(--text-secondary)}
-.viz-side .meter{display:flex;align-items:center;gap:8px;font-size:11.5px;color:var(--text-muted)}
-.viz-side .meter i{flex:1;height:6px;border-radius:9px;background:linear-gradient(90deg,#22c55e var(--v),var(--bg-hover) var(--v))}
-.viz-side .meter b{color:var(--text-secondary);font-weight:600}
-.viz-side .estop{justify-self:end;font-size:12px;font-weight:800;letter-spacing:.08em;color:#fff;background:#dc2626;border-radius:10px;padding:7px 16px;box-shadow:0 0 0 3px rgba(220,38,38,.25)}
-.feed{list-style:none;display:grid;gap:8px;padding:2px}
-.feed li{display:flex;align-items:flex-start;gap:10px;font-size:13.5px;line-height:1.45;padding:10px 12px;border-radius:12px;background:var(--bg-secondary);border:1px solid var(--border);color:var(--text-secondary)}
-.feed li i{color:#22c55e;margin-top:3px}
-.feed li.ask{flex-wrap:wrap;border-color:rgba(var(--site-rgb),.45);background:rgba(var(--site-rgb),.08);color:var(--text-primary)}.feed li.ask i{color:var(--site)}.feed li.ask>span:first-of-type{flex:1;min-width:160px}
-.feed .pills{display:flex;gap:6px;margin-left:auto}.feed .pills span{font-size:12px;font-weight:600;padding:4px 11px;border-radius:999px;border:1px solid var(--border);color:var(--text-secondary)}.feed .pills .ok{background:var(--site);border-color:var(--site);color:#0b0d10}
-.steps{list-style:none;display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:14px;counter-reset:s}
-.steps li{position:relative;background:var(--bg-card);border:1px solid var(--border);border-radius:16px;padding:20px 20px 20px;display:flex;flex-direction:column;gap:8px}
-.steps .n{width:30px;height:30px;border-radius:50%;display:grid;place-items:center;font-weight:800;font-size:14px;color:#0b0d10;background:var(--site)}
-.steps b{font-size:15px}.steps span:last-child{font-size:13px;color:var(--text-secondary);line-height:1.55}
-.grid.three{grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}
-.viz .task{font-size:14px;line-height:1.5;padding:10px 12px;border-radius:12px;background:var(--bg-secondary);border:1px solid var(--border);color:var(--text-primary)}
-.viz .modes{display:flex;flex-wrap:wrap;gap:6px;margin:10px 0}
-.viz .modes span{font-size:11.5px;font-weight:600;padding:4px 10px;border-radius:999px;border:1px solid var(--border);color:var(--text-secondary)}
-.viz .modes .on{background:var(--site);border-color:var(--site);color:#0b0d10}
-.cands{list-style:none;display:grid;gap:6px}
-.cands li{display:grid;grid-template-columns:18px minmax(0,1fr) 54px 50px 44px;align-items:center;gap:8px;font-size:12.5px;padding:8px 10px;border-radius:10px;background:var(--bg-secondary);border:1px solid var(--border);color:var(--text-secondary);position:relative}
-.cands li i{color:var(--text-muted)}.cands li b{font-weight:600;color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
-.cands li span{text-align:right;font-variant-numeric:tabular-nums}
-.cands li.pick{border-color:rgba(var(--site-rgb),.55);background:rgba(var(--site-rgb),.09)}.cands li.pick i{color:var(--site)}
-.cands li em{position:absolute;top:-8px;right:10px;font-style:normal;font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;padding:1px 7px;border-radius:999px;background:var(--site);color:#0b0d10}
-.viz .why{margin-top:10px;font-size:12.5px;line-height:1.5;color:var(--text-secondary)}.viz .why i{color:var(--site);margin-right:4px}
-.choice{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:14px}
-.card.big{padding:24px}.card.big b{font-size:17px}
-.chips{display:flex;flex-wrap:wrap;gap:7px;margin-top:6px}
-.chips span{font-size:12.5px;padding:6px 11px;border-radius:999px;border:1px solid var(--border);background:var(--bg-secondary);color:var(--text-secondary)}
-.chips.big span{font-size:13.5px;padding:9px 14px;color:var(--text-primary)}.chips.big span i{color:var(--site);margin-right:8px}
-.build .card{border-style:dashed;background:rgba(0,0,0,.15)}.build .card b i{color:var(--site);margin-right:6px}.build .card span a{color:var(--text-secondary)}.build .card code{font-size:12px}
-@media (max-width:860px){.hero.split{grid-template-columns:1fr;text-align:center;gap:28px}.hero.split .ctas{justify-content:center}.hero.split p.lead{margin:0 auto}}
-@media (max-width:600px){.hero{padding-top:56px}.ctas .btn{width:100%;justify-content:center}.viz-ctrl{flex-direction:column;align-items:stretch}.dpad{align-self:center}.cands li{grid-template-columns:14px minmax(0,1fr) 30px 40px 30px;gap:6px;font-size:12px;padding:8px}}
-@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}
-</style>
-</head>
-<body>
-<div class="orbs"><i></i><i></i><i></i></div>
-<div id="navbar-mount"></div>
-<main class="wrap">
- <header class="hero split"><div class="hero-main">
- <div class="mark"><i class="fa-solid fa-robot" aria-hidden="true"></i></div>
- <div class="badge"><span class="ov-mark" data-size="16" data-variant="bot"></span> Part of the OpenVibe network · <b>being built</b></div>
- <h1>OpenVibe<span class="d">.</span><span class="tld">Bot</span></h1>
- <div class="tag">Get your robot online in minutes.</div>
- <p class="lead">OpenVibe.Bot is an open control panel for robots. Add a robot, pair it with one command or a QR code, and drive it from any browser with live video, real controls and a stop button that always works. Buy a ready-made bot or bring your own: a Raspberry Pi robot, an ESP32, a ROS 2 robot, a phone, or a Cozmo. Share control, automate it, hand it to your AI agent, and stream it to OpenVibe.Live or openre.stream when you want to.</p>
- <div class="ctas">
- <a class="btn btn-primary" href="https://openvibe.network/login?return=https%3A%2F%2Fopenvibe.bot%2F"><i class="fa-solid fa-right-to-bracket"></i> Sign in with OpenVibe</a>
- <a class="btn" href="https://openvibe.live"><i class="fa-solid fa-tower-broadcast"></i> Robots on Live today</a>
- <a class="btn" href="https://discord.gg/M6MuRUaeJj" rel="noopener"><i class="fa-brands fa-discord"></i> Follow the build</a>
- </div>
- </div>
- <figure class="viz" aria-label="Design preview: a robot control panel with live video, a drive pad, buttons, battery level and a stop button">
- <div class="viz-top"><span class="dot"></span><b>Rover-1</b><span class="muted">online</span><span class="lat"><i class="fa-solid fa-signal" aria-hidden="true"></i> 84 ms</span></div>
- <div class="viz-video" aria-hidden="true"><div class="scan"></div><span class="onair"><i class="fa-solid fa-circle" aria-hidden="true"></i> Streaming to openvibe.live</span><span class="cam"><i class="fa-solid fa-video" aria-hidden="true"></i> Front camera</span></div>
- <div class="viz-ctrl" aria-hidden="true">
- <div class="dpad"><span class="u"><i class="fa-solid fa-caret-up"></i></span><span class="l"><i class="fa-solid fa-caret-left"></i></span><span class="c"></span><span class="r"><i class="fa-solid fa-caret-right"></i></span><span class="d"><i class="fa-solid fa-caret-down"></i></span></div>
- <div class="viz-side">
- <div class="keys"><span><i class="fa-solid fa-lightbulb"></i> Lights</span><span><i class="fa-solid fa-bullhorn"></i> Horn</span><span><i class="fa-solid fa-comment"></i> Speak</span><span><i class="fa-solid fa-camera-rotate"></i> Camera</span></div>
- <div class="meter"><span>Battery</span><i style="--v:82%"></i><b>82%</b></div>
- <div class="estop">STOP</div>
- </div>
- </div>
- <figcaption>Design preview of the robot panel</figcaption>
- </figure>
- </header>
-
-
- <section id="what">
- <h2>Online in three steps</h2>
- <p class="lead2">No port forwarding, no stream keys, no config files.</p>
- <ol class="steps">
- <li><span class="n">1</span><b>Add a robot</b><span>Name it and pick what it is: a rover, an arm, a camera, a phone on wheels or your own design.</span></li>
- <li><span class="n">2</span><b>Pair it</b><span>Paste one command on the robot, flash a ready-made card, or scan a QR code. It gets its own key, which you can revoke any time.</span></li>
- <li><span class="n">3</span><b>Drive it</b><span>Live video and controls in any browser, phone included, with a stop button that always works.</span></li>
- </ol>
- </section>
-
- <section>
- <h2>Buy one or bring your own</h2>
- <p class="lead2">Start with hardware that is known to work, or use what you already have.</p>
- <div class="choice">
- <div class="card big"><div class="ic"><i class="fa-solid fa-box-open" aria-hidden="true"></i></div><b>Get a robot</b><span>Curated kits with parts lists, tested settings and build guides, and ready-made bots that arrive paired to your account. The first one on OpenVibe.Bot is the Adeept 4WD Smart Car for Raspberry Pi.</span><div class="chips"><span>Adeept 4WD Smart Car (Raspberry Pi)</span><span>Rover kits</span><span>Telepresence bots</span><span>Pan-tilt cameras</span><span>Robot arms</span></div></div>
- <div class="card big"><div class="ic"><i class="fa-solid fa-screwdriver-wrench" aria-hidden="true"></i></div><b>Bring your own</b><span>Anything with motors, a camera or sensors. Install the OpenVibe device agent on the robot, or, for robots with their own firmware like Cozmo, on a computer next to it, and your robot shows up in the panel.</span><div class="chips"><span>Raspberry Pi and Linux boards</span><span>Cozmo, through a bridge</span><span>ESP32</span><span>ROS 2</span><span>Android phones</span><span>ONVIF and RTSP cameras</span><span>Serial motor boards</span></div></div>
- </div>
- </section>
-
- <section>
- <h2>More than a stream</h2>
- <p class="lead2">A control panel for anything you build, whether or not anyone is watching.</p>
- <div class="grid three">
- <div class="card"><div class="ic"><i class="fa-solid fa-gamepad" aria-hidden="true"></i></div><b>Real controls</b><span>Drive pad, keyboard, touch joystick and gamepad; buttons, sliders, servos and camera pan-tilt, laid out from your robot's profile.</span></div>
- <div class="card"><div class="ic"><i class="fa-solid fa-bolt" aria-hidden="true"></i></div><b>Low latency</b><span>Video and commands over WebRTC, so driving feels direct. Works behind ordinary home and mobile networks.</span></div>
- <div class="card"><div class="ic"><i class="fa-solid fa-user-group" aria-hidden="true"></i></div><b>Share control</b><span>Invite friends as operators, or open a public queue with timed turns, cooldowns and per-role limits.</span></div>
- <div class="card"><div class="ic"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i></div><b>Safe by default</b><span>The robot stops itself when commands stop. An emergency stop, speed and range limits and time windows, all logged.</span></div>
- <div class="card"><div class="ic"><i class="fa-solid fa-diagram-project" aria-hidden="true"></i></div><b>Automate it</b><span>Schedules, triggers and webhooks, plus an API and SDKs for your own apps.</span></div>
- <div class="card"><div class="ic"><i class="fa-solid fa-user-astronaut" aria-hidden="true"></i></div><b>Hand it to your agent</b><span>Let your OpenVibe.Actor agent patrol, check on or perform with your robot, with your approval.</span></div>
- </div>
- </section>
-
-
-
- <section class="meanwhile">
- <h2>Stream it, record it, connect it</h2>
- <p class="lead2">Optional, one toggle each. Your robot does not need an audience to be useful.</p>
- <div class="grid">
- <a class="card" href="https://openvibe.live"><div class="ic"><i class="fa-solid fa-tower-broadcast" aria-hidden="true"></i></div><b>Stream to OpenVibe.Live</b><span>Put the robot's camera on your channel; viewers can drive it from chat or the panel.</span><span class="go">openvibe.live →</span></a>
- <a class="card" href="https://openre.stream"><div class="ic"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i></div><b>Stream through openre.stream</b><span>Low-latency ingest and restreaming to other platforms from the same camera.</span><span class="go">openre.stream →</span></a>
- <a class="card" href="https://openvibe.media"><div class="ic"><i class="fa-solid fa-photo-film" aria-hidden="true"></i></div><b>Record to OpenVibe.Media</b><span>Keep every run as a video and cut clips from it.</span><span class="go">openvibe.media →</span></a>
- <a class="card" href="https://openvibe.codes"><div class="ic"><i class="fa-solid fa-code" aria-hidden="true"></i></div><b>Build on it</b><span>The API, SDKs and examples.</span><span class="go">openvibe.codes →</span></a>
- </div>
- </section>
-
- <section id="questions" class="faq">
- <h2>Questions</h2>
- <details><summary>Do I need to open ports on my router?</summary><p>No. The robot connects out to OpenVibe, and video and controls travel over WebRTC, so it works behind ordinary home and mobile networks.</p></details>
- <details><summary>Is it only for streaming?</summary><p>No. Streaming is optional. Bot is a control panel for your robot first: drive it, check on it, share it and automate it.</p></details>
- <details><summary>Which robot comes first?</summary><p>The Adeept 4WD Smart Car Kit for Raspberry Pi: four motors, a pan-tilt camera, distance and line sensors, lights and a buzzer. OpenVibe's device agent drives it directly, so its own open control port never has to be exposed.</p></details>
- <details><summary>Does it work with Cozmo?</summary><p>Yes, built in. Cozmo makes its own Wi-Fi and runs closed firmware, so the OpenVibe agent runs on a computer next to it (a Raspberry Pi or a laptop) that joins Cozmo's Wi-Fi and stays online through another connection. You get driving, the head and lift, its camera, its face display, its voice, lights and cubes, and it stops at edges on its own. No phone app needed.</p></details>
- <details><summary>What hardware works?</summary><p>A Raspberry Pi or another Linux board, an ESP32, a ROS 2 robot, an Android phone, or an ONVIF or RTSP camera. The curated kits list exactly what to buy.</p></details>
- <details><summary>How does it keep the robot safe?</summary><p>The device stops its motors by itself when commands or the connection stop. There is an emergency stop in the panel, limits on speed, range and time, and every command is logged.</p></details>
- <details><summary>What will it cost?</summary><p>Controlling your own robot will not cost anything. Limits and any paid extras will be published before launch.</p></details>
- </section>
-
- <section class="build">
- <div class="card">
- <b><i class="fa-solid fa-person-digging" aria-hidden="true"></i> Build status</b>
- <span>OpenVibe.Bot is being built now, starting with our own robots; stream-controlled robots already run on OpenVibe.Live. Its own service is not running yet: this page is a placeholder, nothing here is live yet. It opens with the Bot service, its device agent and the first robots paired. · as of 2026-09-29 · <a href="/status.json">status.json</a></span>
- </div>
- </section>
-
- <section class="net">
- <h2>The OpenVibe network</h2>
- <p class="lead2">One account for all of it. Sign in once and every site signs you in.</p>
- <div class="grid">
- <a class="card" href="https://openvibe.live"><div class="ic"><i class="fa-solid fa-tower-broadcast" aria-hidden="true"></i></div><b>OpenVibe.Live</b><span>Go live, chat, clip, restream</span><span class="go">openvibe.live →</span></a>
- <a class="card" href="https://openvibe.tools"><div class="ic"><i class="fa-solid fa-screwdriver-wrench" aria-hidden="true"></i></div><b>OpenVibe.Tools</b><span>Hundreds of online tools</span><span class="go">openvibe.tools →</span></a>
- <a class="card" href="https://openvibe.community"><div class="ic"><i class="fa-solid fa-people-group" aria-hidden="true"></i></div><b>OpenVibe.Community</b><span>Pastes, posts, people</span><span class="go">openvibe.community →</span></a>
- <a class="card" href="https://openvibe.games"><div class="ic"><i class="fa-solid fa-gamepad" aria-hidden="true"></i></div><b>OpenVibe.Games</b><span>Scraplandia and browser games</span><span class="go">openvibe.games →</span></a>
- <a class="card" href="https://openvibe.media"><div class="ic"><i class="fa-solid fa-photo-film" aria-hidden="true"></i></div><b>OpenVibe.Media</b><span>VODs, clips and files</span><span class="go">openvibe.media →</span></a>
- <a class="card" href="https://openvibe.network"><div class="ic"><i class="fa-solid fa-circle-nodes" aria-hidden="true"></i></div><b>OpenVibe.Network</b><span>One account, every site</span><span class="go">openvibe.network →</span></a>
- </div>
- <h2 style="margin-top:28px;font-size:16px">Other OpenVibe domains, not open yet</h2>
- <div class="rooms" style="margin-top:8px">
- <a href="https://openvibe.news/"><i class="fa-solid fa-newspaper" aria-hidden="true"></i>OpenVibe.News</a>
- <a href="https://openvibe.reviews/"><i class="fa-solid fa-star-half-stroke" aria-hidden="true"></i>OpenVibe.Reviews</a>
- <a href="https://openvibe.tips/"><i class="fa-solid fa-hand-holding-heart" aria-hidden="true"></i>OpenVibe.Tips</a>
- <a href="https://openvibe.vip/"><i class="fa-solid fa-crown" aria-hidden="true"></i>OpenVibe.VIP</a>
- <a href="https://openvibe.trade/"><i class="fa-solid fa-chart-line" aria-hidden="true"></i>OpenVibe.Trade</a>
- <a href="https://openvibe.host/"><i class="fa-solid fa-server" aria-hidden="true"></i>OpenVibe.Host</a>
- <a href="https://openvibe.deals/"><i class="fa-solid fa-tags" aria-hidden="true"></i>OpenVibe.Deals</a>
- <a href="https://openvibe.coupons/"><i class="fa-solid fa-ticket" aria-hidden="true"></i>OpenVibe.Coupons</a>
- <a href="https://openre.stream/"><i class="fa-solid fa-satellite-dish" aria-hidden="true"></i>OpenRe.Stream</a>
- <a href="https://auth.openvibe.network/"><i class="fa-solid fa-key" aria-hidden="true"></i>auth.openvibe.network</a>
- <a href="https://api.openvibe.network/"><i class="fa-solid fa-plug" aria-hidden="true"></i>api.openvibe.network</a>
- <a href="https://admin.openvibe.network/"><i class="fa-solid fa-shield-halved" aria-hidden="true"></i>admin.openvibe.network</a>
- <a href="https://themes.openvibe.network/"><i class="fa-solid fa-palette" aria-hidden="true"></i>themes.openvibe.network</a>
- <a href="https://ai.openvibe.services/"><i class="fa-solid fa-robot" aria-hidden="true"></i>ai.openvibe.services</a>
- <a href="https://openvibe.pics/"><i class="fa-solid fa-images" aria-hidden="true"></i>OpenVibe.Pics</a>
- <a href="https://openvibe.download/"><i class="fa-solid fa-cloud-arrow-down" aria-hidden="true"></i>OpenVibe.Download</a>
- <a href="https://openvibe.space/"><i class="fa-solid fa-layer-group" aria-hidden="true"></i>OpenVibe.Space</a>
- <a href="https://openvibe.food/"><i class="fa-solid fa-utensils" aria-hidden="true"></i>OpenVibe.Food</a>
- <a href="https://openvibe.quest/"><i class="fa-solid fa-map" aria-hidden="true"></i>OpenVibe.Quest</a>
- <a href="https://openvibe.rent/"><i class="fa-solid fa-key" aria-hidden="true"></i>OpenVibe.Rent</a>
- <a href="https://openvibe.homes/"><i class="fa-solid fa-house" aria-hidden="true"></i>OpenVibe.Homes</a>
- <a href="https://openvibe.services/"><i class="fa-solid fa-server" aria-hidden="true"></i>OpenVibe.Services</a>
- <a href="https://openvibe.run/"><i class="fa-solid fa-terminal" aria-hidden="true"></i>OpenVibe.Run</a>
- <a href="https://openvibe.work/"><i class="fa-solid fa-briefcase" aria-hidden="true"></i>OpenVibe.Work</a>
- <a href="https://openvibe.zone/"><i class="fa-solid fa-box-archive" aria-hidden="true"></i>OpenVibe.Zone</a>
- <a href="https://openvibe.video/"><i class="fa-solid fa-film" aria-hidden="true"></i>OpenVibe.Video</a>
- <a href="https://openvibe.website/"><i class="fa-solid fa-globe" aria-hidden="true"></i>OpenVibe.Website</a>
- <a href="https://openvibe.help/"><i class="fa-solid fa-life-ring" aria-hidden="true"></i>OpenVibe.Help</a>
- <a href="https://openvibe.watch/"><i class="fa-solid fa-eye" aria-hidden="true"></i>OpenVibe.Watch</a>
- <a href="https://openvibe.actor/"><i class="fa-solid fa-user-astronaut" aria-hidden="true"></i>OpenVibe.Actor</a>
- <a href="https://openvibe.events/"><i class="fa-solid fa-bolt" aria-hidden="true"></i>OpenVibe.Events</a>
- </div>
- </section>
-
- <div class="strip">
- <span class="ov-mark" data-size="44" data-variant="bot"></span>
- <h3>Open source. Community run.</h3>
- <p>Every OpenVibe site is built in the open by the people using it — free speech within the rules, no gatekeeping, one identity that follows you everywhere.</p>
- <a class="btn" href="https://github.com/OpenVibers" rel="noopener"><i class="fa-brands fa-github"></i> OpenVibers on GitHub</a>
- </div>
-</main>
-<style id="ovf-css">
-.ovf{background:var(--bg-secondary,#12131c);border-top:1px solid var(--border,rgba(255,255,255,.08));margin-top:40px;
- padding:clamp(24px,4vw,40px) clamp(14px,4vw,32px) calc(clamp(20px,3vw,28px) + env(safe-area-inset-bottom,0px));}
-.ovf[data-variant="compact"]{margin-top:24px;padding:14px clamp(12px,3vw,24px) calc(14px + env(safe-area-inset-bottom,0px));}
-.ovf-inner{max-width:1240px;margin:0 auto}
-.ovf-inner--compact{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:8px 18px;text-align:center}
-.ovf-cols{display:grid;gap:clamp(20px,3vw,36px);grid-template-columns:minmax(230px,1.6fr) repeat(auto-fit,minmax(120px,1fr));align-items:start}
-.ovf-col{display:flex;flex-direction:column;gap:8px;min-width:0}
-.ovf-col h3{margin:0 0 2px;font-size:.72rem;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--text-muted,#8b93ad)}
-.ovf-col a{color:var(--text-secondary,#b6bdd2);font-size:.86rem;text-decoration:none;line-height:1.4;width:fit-content;transition:color .15s,transform .15s}
-.ovf-col a:hover{color:var(--accent,#60a5fa);transform:translateX(2px)}
-.ovf-more{font-weight:600;opacity:.85}.ovf-ic{flex:none;vertical-align:-.14em}.ovf-more .ovf-ic{font-size:.85em;margin-left:3px;transition:transform .15s}.ovf-more:hover .ovf-ic{transform:translateX(3px)}.ovf-social .ovf-ic{font-size:17px}.ovf-account-links .ovf-ic{font-size:1.05em;opacity:.85}
-.ovf-brand{display:inline-flex;align-items:center;gap:9px;color:var(--text-primary,#f1f4fb);font-size:1.05rem;font-weight:700;text-decoration:none}
-.ovf-brand--sm{font-size:.9rem}
-.ovf-tagline{margin:0;font-size:.82rem;line-height:1.55;color:var(--text-muted,#8b93ad);max-width:46ch}
-.ovf-social{display:flex;gap:8px;margin-top:4px}
-.ovf-social a{width:36px;height:36px;border-radius:10px;display:grid;place-items:center;color:var(--text-secondary,#b6bdd2);
- background:var(--bg-tertiary,#1a1b28);border:1px solid var(--border,rgba(255,255,255,.08));font-size:.95rem;transition:color .15s,border-color .15s,transform .15s}
-.ovf-social a:hover{color:var(--accent,#60a5fa);border-color:var(--accent,#60a5fa);transform:translateY(-2px)}
-.ovf-account{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px 18px;
- margin-top:clamp(18px,2.5vw,26px);padding:10px 14px;border-radius:14px;
- background:color-mix(in srgb, var(--accent,#60a5fa) 8%, var(--bg-tertiary,#1a1b28));
- border:1px solid color-mix(in srgb, var(--accent,#60a5fa) 26%, var(--border,rgba(255,255,255,.08)));
- animation:ovfIn .4s ease-out both}
-@keyframes ovfIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
-.ovf-account-who{display:inline-flex;align-items:center;gap:8px;font-size:.84rem;color:var(--text-secondary,#b6bdd2)}
-.ovf-account-who strong{color:var(--text-primary,#f1f4fb)}
-.ovf-avatar{width:24px;height:24px;border-radius:50%;overflow:hidden;display:grid;place-items:center;
- background:var(--accent,#60a5fa);color:#fff;font-size:.7rem;font-weight:800;flex:none}
-.ovf-avatar img{width:100%;height:100%;object-fit:cover}
-.ovf-account-links{display:flex;flex-wrap:wrap;gap:6px}
-.ovf-account-links a{display:inline-flex;align-items:center;gap:6px;padding:5px 11px;border-radius:999px;font-size:.78rem;font-weight:600;
- color:var(--text-secondary,#b6bdd2);background:var(--bg-secondary,#12131c);border:1px solid var(--border,rgba(255,255,255,.08));
- text-decoration:none;transition:color .15s,border-color .15s,transform .15s}
-.ovf-account-links a:hover{color:var(--accent,#60a5fa);border-color:var(--accent,#60a5fa);transform:translateY(-1px)}
-.ovf-account-links i{font-size:.72rem;opacity:.8}
-.ovf-bar{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px;
- margin-top:clamp(20px,3vw,30px);padding-top:16px;border-top:1px solid var(--border,rgba(255,255,255,.08));
- padding-inline:clamp(0px, calc(84px - (100vw - 1240px) / 2), 84px)}
-.ovf-copy{color:var(--text-muted,#8b93ad);font-size:.78rem}
-.ovf-legal-inline,.ovf-compact-links{display:flex;flex-wrap:wrap;gap:14px}
-.ovf [hidden],.ovf-account[hidden]{display:none!important}
-.ovf .ovf-shipped.ov-shipped-latest{font-size:.76rem;padding:4px 12px;max-width:min(520px,100%);background:transparent}
-.ovf-legal-inline a,.ovf-compact-links a{color:var(--text-muted,#8b93ad);font-size:.78rem;text-decoration:none;transition:color .15s}
-.ovf-legal-inline a:hover,.ovf-compact-links a:hover{color:var(--accent,#60a5fa)}
-.ovf-compact-meta{color:var(--text-muted,#8b93ad);font-size:.74rem}
-@media (max-width:900px){.ovf-cols{grid-template-columns:repeat(2,minmax(0,1fr))}.ovf-col--brand{grid-column:1/-1}}
-@media (max-width:560px){
- .ovf{padding-bottom:calc(20px + var(--ov-footer-clearance,0px) + env(safe-area-inset-bottom,0px))}
- .ovf[data-variant="compact"]{padding-bottom:calc(14px + var(--ov-footer-clearance,0px) + env(safe-area-inset-bottom,0px))}
- .ovf-cols{gap:22px 16px}
- .ovf-bar{justify-content:center;text-align:center;padding-inline:0}
- .ovf-legal-inline{justify-content:center}
- .ovf-account{flex-direction:column;align-items:flex-start}
-}
-@media (prefers-reduced-motion:reduce){.ovf-account{animation:none}.ovf-col a:hover,.ovf-social a:hover,.ovf-account-links a:hover{transform:none}}
-.ovf{-webkit-tap-highlight-color:transparent}
-:where(.ovf) :where(a,button):active{scale:.97}
-:where(.ovf) :where(a,button):focus-visible{outline:2px solid var(--accent-light,var(--accent,#3b82f6));outline-offset:2px;border-radius:4px}
-@media (prefers-reduced-motion:reduce){:where(.ovf) :where(a,button):active{scale:none;opacity:.82}}</style><footer id="ov-footer" class="ovf" data-variant="full"><div class="ovf-inner">
- <div class="ovf-cols">
- <div class="ovf-col ovf-col--brand">
- <a class="ovf-brand" href="/"><span class="ov-mark" data-size="26"></span><span>OpenVibe</span></a>
- <p class="ovf-tagline">Open source and community run. Built in the open by the people using it.</p>
- <div class="ovf-social">
- <a href="https://github.com/OpenVibers" target="_blank" rel="noopener" aria-label="GitHub" title="GitHub"><svg class="ovf-ic" viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="1.800" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path fill="currentColor" stroke="none" d="M12 2.2a9.8 9.8 0 0 0-3.1 19.1c.5.1.7-.2.7-.5v-1.7c-2.7.6-3.3-1.2-3.3-1.2-.4-1.1-1.1-1.4-1.1-1.4-.9-.6.1-.6.1-.6 1 .1 1.5 1 1.5 1 .9 1.5 2.3 1.1 2.9.8.1-.6.3-1.1.6-1.3-2.2-.2-4.5-1.1-4.5-4.8 0-1.1.4-1.9 1-2.6-.1-.2-.4-1.2.1-2.6 0 0 .8-.3 2.7 1a9.3 9.3 0 0 1 4.9 0c1.9-1.3 2.7-1 2.7-1 .5 1.4.2 2.4.1 2.6.6.7 1 1.5 1 2.6 0 3.7-2.3 4.6-4.5 4.8.4.3.7.9.7 1.800v2.700c0 .3.2.6.7.5A9.8 9.8 0 0 0 12 2.200z"/></svg></a><a href="https://discord.gg/M6MuRUaeJj" target="_blank" rel="noopener" aria-label="Discord" title="Discord"><svg class="ovf-ic" viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="1.800" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path fill="currentColor" stroke="none" d="M19.3 5.300a16.5 16.5 0 0 0-4.1-1.300l-.5 1a15.3 15.3 0 0 0-5.4 0l-.5-1a16.5 16.5 0 0 0-4.1 1.300C2.1 9.2 1.4 13 1.7 16.700a16.6 16.6 0 0 0 5.1 2.600l1.1-1.800c-.6-.2-1.2-.5-1.7-.8l.4-.3a11.8 11.8 0 0 0 10.8 0l.4.3c-.5.3-1.1.6-1.7.8l1.1 1.800a16.6 16.6 0 0 0 5.1-2.600c.4-4.3-.7-8.1-3-11.400zM8.7 14.400c-1 0-1.8-.9-1.8-2.100s.8-2.1 1.8-2.1 1.9 1 1.8 2.100c0 1.2-.8 2.1-1.8 2.100zm6.6 0c-1 0-1.8-.9-1.8-2.100s.8-2.1 1.8-2.1 1.9 1 1.8 2.100c0 1.2-.8 2.1-1.8 2.100z"/></svg></a>
- <a href="/sitemap.xml" aria-label="Sitemap" title="Sitemap"><svg class="ovf-ic" viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="1.800" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect x="9" y="3.5" width="6" height="4.5" rx="1"/><rect x="3" y="16" width="6" height="4.5" rx="1"/><rect x="15" y="16" width="6" height="4.5" rx="1"/><path d="M12 8v4M6 16v-2.500h12V16"/></svg></a>
- </div>
- </div>
-
- <nav class="ovf-col" aria-label="The OpenVibe network">
- <h3>Network</h3>
- <a href="https://openvibe.live" title="Go live, restream and clip">Live streaming</a><a href="https://openvibe.tools" title="The whole toolbox">Online tools</a><a href="https://dev.openvibe.tools" title="Formatters, encoders, validators">Developer tools</a><a href="https://net.openvibe.tools" title="Ping, DNS, Whois, SSL">Network diagnostics</a><a href="https://img.openvibe.tools" title="Convert, resize, compress">Image converter</a><a href="https://audio.openvibe.tools" title="Convert, trim, pitch-shift">Audio converter</a>
- <a class="ovf-more" href="https://openvibe.network" target="_blank" rel="noopener">Everything else <svg class="ovf-ic" viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="1.800" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6"/></svg></a>
- </nav>
-
- <nav class="ovf-col" aria-label="Legal">
- <h3>Legal</h3>
- <a href="https://openvibe.live/tos">Terms of Service</a><a href="https://openvibe.live/privacy">Privacy Policy</a><a href="https://openvibe.live/dmca">DMCA</a>
- </nav>
- </div>
- <div class="ovf-account" id="ovf-account" hidden></div>
- <div class="ovf-bar">
- <span class="ovf-copy">Open source & community driven · built in the open</span>
- <a class="ovf-shipped" data-ov-shipped="latest" data-service="bot" href="https://openvibe.network/updates?site=bot" hidden></a>
- <span class="ovf-legal-inline">
- <a href="https://openvibe.network/updates?site=bot">Updates</a>
- <a href="https://openvibe.live/tos">Terms</a><a href="https://openvibe.live/privacy">Privacy</a><a href="https://openvibe.live/dmca">DMCA</a>
- </span>
- </div>
- </div></footer>
-<script src="/shared/ov-mark.js?v=03f3596adcab" async></script>
-<script src="/shared/navbar.js?v=017a740747b4"></script>
-<script src="/shared/footer.js?v=a85ab893be88"></script>
-<script>
-(function () {
- if (window.OpenVibeNavbar) { try { OpenVibeNavbar.init({ service: 'bot', apiBase: 'https://openvibe.network', links: [{ label: 'How it works', href: '#what' }, { label: 'The network', href: 'https://openvibe.network/#network', external: false }], history: { type: 'page', title: 'OpenVibe.Bot' } }); } catch (e) {} }
- if (window.OpenVibeFooter) { try { OpenVibeFooter.init({ service: 'bot', variant: 'full', links: [{ heading: 'OpenVibe.Bot', items: [{ name: 'Sign in', url: 'https://openvibe.network/login?return=https%3A%2F%2Fopenvibe.bot%2F' }, { name: 'The network', url: 'https://openvibe.network/#network' }, { name: 'Discord', url: 'https://discord.gg/M6MuRUaeJj' }] }] }); } catch (e) {} }
-})();
-</script>
-</body>
-</html>
deleted file mode 100644
deleted file mode 100644
@@ -1,13 +0,0 @@
@@ -1,13 +0,0 @@
-{
- "service": "bot",
- "release": "8512ce660c7e",
- "released_at": "2026-10-03T00:00:00.000Z",
- "booted_at": null,
- "contracts_version": null,
- "packages": {
- "openvibe-shared": "2.5.0"
- },
- "min_client_release": null,
- "mixed_version_window_hours": 24,
- "kind": "placeholder"
-}
deleted file mode 100644
deleted file mode 100644
@@ -1,4 +0,0 @@
@@ -1,4 +0,0 @@
-User-agent: *
-Allow: /
-Disallow: /auth/
-Sitemap: https://openvibe.bot/sitemap.xml
deleted file mode 100644
deleted file mode 100644
@@ -1,16 +0,0 @@
@@ -1,16 +0,0 @@
-{
- "domain": "openvibe.bot",
- "name": "OpenVibe.Bot",
- "stage": "placeholder",
- "live": false,
- "plannedRepo": null,
- "repoUrl": null,
- "repoExists": false,
- "repoStage": "charter-only",
- "service": null,
- "launchWaitsFor": "the Bot service, its device agent and the first robots paired",
- "factsAsOf": "2026-09-29",
- "network": "https://openvibe.network",
- "updated": "2026-10-03",
- "note": "Static page served by OpenVibers/OpenVibe.Sites; service facts come from each repository's STATUS.json and the Network registry (facts.json). Removed from sites.json in the same release that the real service takes over this domain."
-}
@@ -12,7 +12,7 @@ the release in which the product's own vhost is installed.
@@ -12,7 +12,7 @@ the release in which the product's own vhost is installed.
domain yet. When the Sites vhost goes, the record stays in DNS (Cloudflare) and nothing on the host answers it.
domain yet. When the Sites vhost goes, the record stays in DNS (Cloudflare) and nothing on the host answers it.
The Sites repository had 33 host files on 2026-10-02 (the plan said 36), one per `sites.json` entry. Since then OpenVibe.Bot
The Sites repository had 33 host files on 2026-10-02 (the plan said 36), one per `sites.json` entry. Since then OpenVibe.Bot
-supplies the `openvibe.bot` vhost (Sites keeps publishing its frozen pages), and `openvibe.work` and `openvibe.zone` were
+supplies the `openvibe.bot` vhost and, since 2026-10-07, serves its own front page (Sites keeps only its legal pages there), and `openvibe.work` and `openvibe.zone` were
added; they have no Contracts manifest yet, so `sync-catalog.js` keeps them as they are. That makes 34 host files for 35
added; they have no Contracts manifest yet, so `sync-catalog.js` keeps them as they are. That makes 34 host files for 35
`sites.json` entries.
`sites.json` entries.
@@ -25,7 +25,7 @@ added; they have no Contracts manifest yet, so `sync-catalog.js` keeps them as t
@@ -25,7 +25,7 @@ added; they have no Contracts manifest yet, so `sync-catalog.js` keeps them as t
| `auth.openvibe.network.conf` | placeholder | OpenVibe.Network | no |
| `auth.openvibe.network.conf` | placeholder | OpenVibe.Network | no |
| `openre.stream.conf` | placeholder | OpenRe.Stream | yes: `deploy/nginx/openre.stream.conf` |
| `openre.stream.conf` | placeholder | OpenRe.Stream | yes: `deploy/nginx/openre.stream.conf` |
| `openvibe.actor.conf` | placeholder (no repo) | park: DNS only (OpenVibe.Node exists but has no deploy config and does not run) | no |
| `openvibe.actor.conf` | placeholder (no repo) | park: DNS only (OpenVibe.Node exists but has no deploy config and does not run) | no |
-| (`openvibe.bot`, no Sites host file) | placeholder (no repo) | OpenVibe.Bot, which already supplies the vhost; Sites keeps only the frozen pages | yes (Contracts still says `noRepo`) |
+| (`openvibe.bot`, no Sites host file) | legal pages, 404, sitemap and manifest (its front page, robots.txt, release.json and status.json are Bot's since 2026-10-07, OpenVibe.Bot#34) | OpenVibe.Bot, which already supplies the vhost | yes (Contracts still says `noRepo`) |
| `openvibe.coupons.conf` | placeholder | OpenVibe.Coupons | yes: `deploy/nginx/openvibe.coupons.conf` |
| `openvibe.coupons.conf` | placeholder | OpenVibe.Coupons | yes: `deploy/nginx/openvibe.coupons.conf` |
| `openvibe.deals.conf` | placeholder | OpenVibe.Deals | yes: `deploy/nginx/openvibe.deals.conf` |
| `openvibe.deals.conf` | placeholder | OpenVibe.Deals | yes: `deploy/nginx/openvibe.deals.conf` |
| `openvibe.download.conf` | placeholder (no repo) | park: DNS only (Contracts names OpenVibe.MediaHub, which does not exist yet) | no |
| `openvibe.download.conf` | placeholder (no repo) | park: DNS only (Contracts names OpenVibe.MediaHub, which does not exist yet) | no |
@@ -29,6 +29,5 @@
@@ -29,6 +29,5 @@
"openvibe.help",
"openvibe.help",
"openvibe.watch",
"openvibe.watch",
"openvibe.events",
"openvibe.events",
- "openvibe.actor",
- "openvibe.bot"
+ "openvibe.actor"
]
]
@@ -18,14 +18,20 @@ assert.deepStrictEqual(notices.map(n => n.domain), [
@@ -18,14 +18,20 @@ assert.deepStrictEqual(notices.map(n => n.domain), [
'ai.openvibe.network', 'realtime.openvibe.network', 'status.openvibe.network',
'ai.openvibe.network', 'realtime.openvibe.network', 'status.openvibe.network',
]);
]);
assert.strictEqual(new Set(frozen).size, frozen.length, 'frozen domains are unique');
assert.strictEqual(new Set(frozen).size, frozen.length, 'frozen domains are unique');
-assert.strictEqual(frozen.length, 32, 'all 32 product domains are frozen');
+assert.strictEqual(frozen.length, 31, 'all 31 product domains are frozen');
const active = new Set(notices.map(n => n.domain));
const active = new Set(notices.map(n => n.domain));
for (const domain of frozen) {
for (const domain of frozen) {
assert.ok(!active.has(domain), `${domain}: product is not a notice`);
assert.ok(!active.has(domain), `${domain}: product is not a notice`);
assert.ok(exists(`dist/${domain}/index.html`), `${domain}: frozen front page`);
assert.ok(exists(`dist/${domain}/index.html`), `${domain}: frozen front page`);
- if (domain !== 'openvibe.bot') assert.ok(exists(`deploy/nginx/${domain}.conf`), `${domain}: frozen vhost`);
+ assert.ok(exists(`deploy/nginx/${domain}.conf`), `${domain}: frozen vhost`);
}
}
assert.ok(!exists('deploy/nginx/openvibe.bot.conf'), 'Bot owns its vhost');
assert.ok(!exists('deploy/nginx/openvibe.bot.conf'), 'Bot owns its vhost');
+// OpenVibe.Bot serves its own front page, robots.txt, release.json and status.json (OpenVibe.Bot#34,
+// 2026-10-07); Sites keeps only the legal pages, 404 page, sitemap and manifest for openvibe.bot.
+assert.deepStrictEqual(fs.readdirSync(path.join(ROOT, 'dist/openvibe.bot')).sort(),
+ ['404.html', 'dmca.html', 'manifest.webmanifest', 'privacy.html', 'sitemap.xml', 'terms.html'],
+ 'openvibe.bot holds only its legal pages, 404, sitemap and manifest (Bot#34)');
+assert.ok(!exists('dist/openvibe.bot/index.html'), 'openvibe.bot has no Sites front page (Bot#34)');
// A frozen placeholder never claims a product is live, never uses pricing copy (no "free"/"$0"/"no ads"; "free
// A frozen placeholder never claims a product is live, never uses pricing copy (no "free"/"$0"/"no ads"; "free
// speech" is fine) and never offers hosting no OpenVibe service provides (2026-09-24 audit).
// speech" is fine) and never offers hosting no OpenVibe service provides (2026-09-24 audit).
const PRICING = /\$0\b|\bfor free\b|\bfree (forever|to use|of charge|plan|tier)\b|\bno ads\b|\bad-free\b/i;
const PRICING = /\$0\b|\bfor free\b|\bfree (forever|to use|of charge|plan|tier)\b|\bno ads\b|\bad-free\b/i;
@@ -36,7 +42,7 @@ for (const domain of frozen) {
@@ -36,7 +42,7 @@ for (const domain of frozen) {
assert.doesNotMatch(html, PRICING, `${domain}: pricing copy`);
assert.doesNotMatch(html, PRICING, `${domain}: pricing copy`);
assert.doesNotMatch(html, UNBACKED, `${domain}: claims a hosting product that does not exist`);
assert.doesNotMatch(html, UNBACKED, `${domain}: claims a hosting product that does not exist`);
}
}
-for (const domain of ['openvibe.actor', 'openvibe.bot']) {
+for (const domain of ['openvibe.actor']) {
assert.ok(frozen.includes(domain), `${domain}: remains frozen`);
assert.ok(frozen.includes(domain), `${domain}: remains frozen`);
assert.match(read(`dist/${domain}/index.html`), /<meta name="robots" content="index, follow, max-image-preview:large">/, `${domain}: original indexing`);
assert.match(read(`dist/${domain}/index.html`), /<meta name="robots" content="index, follow, max-image-preview:large">/, `${domain}: original indexing`);
assert.strictEqual(JSON.parse(read(`dist/${domain}/status.json`)).stage, 'placeholder', `${domain}: lifecycle stage`);
assert.strictEqual(JSON.parse(read(`dist/${domain}/status.json`)).stage, 'placeholder', `${domain}: lifecycle stage`);