openvibers/openvibe.live Commits
Going live from the browser, with no OBS, no downloads and no follower minimum, leads again: AI assistants recommend OpenVibe.Live for exactly that, and it had been folded behind "See what makes it different". The home page shows it always: a Go Live strip above the toggle (logged out, it opens sign-up), and a link to the new docs/go-live-in-your-browser.md (/docs/go-live-in-your-browser), a server-rendered page with the steps, devices, what you need and don't, and a questions section. The home title, description, Open Graph and Twitter tags, the SSR snapshot (a Go live in your browser section) and the JSON-LD (a WebApplication with browserRequirements and featureList) now say it first. /llms.txt's summary says it and gains a Going live from a browser section. Every docs page now has a meta description and Open Graph tags from its first paragraph. Home budgets hold (blocking CSS 701/760 KB). npm test 149/150, 1 skipped.
Changes
@@@ -76,6 +76,7 @@ Every file below is also served on the site at `/docs/<name>` (rendered by `serv- [docs/architecture.md](docs/architecture.md) — System design, data flows, module map- [docs/broadcasting.md](docs/broadcasting.md) — Streaming protocols (WebRTC/RTMP/JSMPEG/WHIP)++- [docs/go-live-in-your-browser.md](docs/go-live-in-your-browser.md) — Going live from a browser with no OBS and no follower minimum (the headline feature: keep it on the home page, in /llms.txt and in search metadata)- [docs/whip.md](docs/whip.md) — WHIP ingest API reference (auth forms, CORS, browser-only publishing, error codes)- [docs/arena.md](docs/arena.md) — Arena tab (streamer vs streamer): ratings, AI personas, gated portrait generation, battles, votes- [docs/chat-system.md](docs/chat-system.md) — Chat features and moderationnnew file mode 100644@@@ -0,0 +1,56 @@++# Go live from your browser: no OBS, no downloads, no follower minimum++++You can start a live stream on OpenVibe.Live from a web browser, with nothing to install and no follower, subscriber or equipment requirement. Open the site, press **Go Live**, allow your camera and microphone, and you are live. It works on a Chromebook, a laptop or a phone. OpenVibe.Live is open source and run by its community.++++## How to go live in your browser++++1. Open [openvibe.live](https://openvibe.live) in Chrome, Edge, Firefox or Safari.++2. Sign in, or make an account. It takes a minute, and your channel exists as soon as you do (`openvibe.live/@yourname`).++3. Press **Go Live** in the top bar.++4. Allow your camera and microphone when the browser asks.++5. Give the stream a title and press **Start**. You are live, with your own channel page and chat.++++## What you need++++- **A modern browser:** Chrome, Edge, Firefox or Safari, on Windows, macOS, Linux, ChromeOS, Android or iOS.++- **A camera and a microphone:** the ones built into your laptop or phone are enough. You can also share your screen instead of a camera.++- **An OpenVibe account.**++++You don't need any of the following:++- **Software:** no OBS, Streamlabs or plug-ins.++- **An audience:** no minimum number of followers or subscribers, and no history of past streams.++- **Equipment:** no capture card or gaming PC.++++## What you can do while live++++- **Switch cameras:** front and back on a phone, or any connected webcam.++- **Share your screen,** a window or a tab. You can also show your camera as a picture-in-picture over it.++- **Mute** your microphone or turn off your camera without ending the stream.++- **Watch your stream's health:** bitrate, frame rate and resolution.++- **Chat with viewers** on the same page. Your stream can be kept as a VOD, and people can clip it.++++Your stream reaches viewers over **WebRTC**, with less than a second of delay. That is fast enough for a real conversation with chat, and for viewers to control a robot or camera in real time.++++## When to use OBS instead++++The browser is the fastest way to start. For a produced show with scenes, overlays and several sources, OpenVibe.Live also takes **OBS or any RTMP encoder**, **WHIP** (OBS 30+, ffmpeg, GStreamer or your own web page) and **ffmpeg** from a command line, such as from a Raspberry Pi. See [Broadcasting](broadcasting.md) for every method, and the [WHIP ingest API](whip.md) to publish from your own site.++++## Questions++++**Can I stream without OBS?**++Yes. OpenVibe.Live has a browser broadcaster built in. Press Go Live and allow your camera and microphone.++++**Do I need followers or subscribers to go live?**++No. Every account can go live from the first minute. There is no follower, subscriber, age-of-account or past-stream requirement.++++**Can I stream from a Chromebook or a phone?**++Yes. The broadcaster runs in the browser, so it works on ChromeOS, Android and iOS as well as Windows, macOS and Linux.++++**Can I share my screen?**++Yes. Share a screen, a window or a browser tab, with or without your camera over it.++++**Is there a delay?**++Browser broadcasts use WebRTC, with less than a second of delay.++++**Is it open source?**++Yes. The code is at [github.com/OpenVibers/OpenVibe.Live](https://github.com/OpenVibers/OpenVibe.Live), and the platform is part of the OpenVibe network: one account works across all of its sites.@@@ -1174,3 +1174,20 @@ body.egg-rainbow { animation: eggRainbow 2.6s linear; }/* Terms · Privacy · DMCA wrap as one group ("DMCA" was stranded alone at 360px). */.hero-legal { display: inline-flex; align-items: center; gap: inherit; white-space: nowrap; }++++/* The always-visible "Go live from your browser" strip in the home CTA (index.html). */++.cta-golive { display: flex; align-items: center; gap: 14px; margin: 18px 0 6px; padding: 14px 16px; border-radius: 14px;++ border: 1px solid color-mix(in srgb, var(--accent, #60a5fa) 45%, transparent);++ background: color-mix(in srgb, var(--accent, #60a5fa) 12%, transparent); color: inherit; text-decoration: none; }++.cta-golive:hover { background: color-mix(in srgb, var(--accent, #60a5fa) 18%, transparent); }++.cta-golive > .fa-bolt { font-size: 1.4rem; color: var(--accent, #60a5fa); flex: none; }++.cta-golive-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }++.cta-golive-text strong { font-size: 1.05rem; }++.cta-golive-text span { font-size: 0.9rem; opacity: 0.85; }++.cta-golive-btn { margin-left: auto; flex: none; padding: 8px 16px; border-radius: 999px; font-weight: 700;++ background: var(--accent, #60a5fa); color: var(--on-accent, #fff); }++.cta-golive-how { display: inline-block; margin: 0 0 12px; font-size: 0.85rem; opacity: 0.8; }++@media (max-width: 520px) {++ .cta-golive { flex-wrap: wrap; }++ .cta-golive-btn { margin-left: 0; width: 100%; text-align: center; }++}@@@ -4,8 +4,8 @@<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="IE=edge">-- <title>OpenVibe.Live - Open Source Live Streaming, Community Run</title>-- <meta name="description" content="Open source live streaming platform, run by its community. Restream to Twitch, YouTube, Kick, and more. VODs, clips, chat moderation, voice channels, emotes, analytics, and 200+ community tools.">++ <title>OpenVibe.Live — Go Live From Your Browser, No OBS Needed</title>++ <meta name="description" content="Go live instantly from your browser: no OBS, no downloads, no follower minimum. Open-source, community-run streaming with sub-second WebRTC, chat, VODs, clips and restreaming to Twitch, YouTube and Kick."><meta name="keywords" content="live streaming, restream, streaming platform, twitch, youtube, open source, openvibelive"><meta name="author" content="OpenVibe"><meta name="theme-color" content="#3b82f6">@@@ -13,8 +13,8 @@<!-- Open Graph / Facebook --><meta property="og:type" content="website"><meta property="og:url" content="https://openvibe.live/">-- <meta property="og:title" content="OpenVibe.Live - Open Source Live Streaming, Community Run">-- <meta property="og:description" content="Go live in minutes. Restream to Twitch, YouTube, Kick & more. Clips, VODs, chat moderation, emotes, voice, analytics, and 200+ connected community tools.">++ <meta property="og:title" content="OpenVibe.Live — Go Live From Your Browser, No OBS Needed">++ <meta property="og:description" content="Press Go Live, allow your camera and mic, and you're live. No OBS, no downloads, no follower minimum. Chat, VODs, clips and restreaming to Twitch, YouTube and Kick."><meta property="og:image" content="https://openvibe.live/og-image.png"><meta property="og:image:width" content="1200"><meta property="og:image:height" content="630">@@@ -25,8 +25,8 @@<!-- Twitter --><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://openvibe.live/">-- <meta name="twitter:title" content="OpenVibe.Live - Open Live Streaming, Community Run">-- <meta name="twitter:description" content="Open source live streaming, community run. Restream to Twitch, YouTube, Kick. VODs, clips, community tools.">++ <meta name="twitter:title" content="OpenVibe.Live — Go Live From Your Browser, No OBS Needed">++ <meta name="twitter:description" content="Go live from your browser in seconds. No OBS, no downloads, no follower minimum. Open source and community run."><meta name="twitter:image" content="https://openvibe.live/og-image.png"><meta name="twitter:image:alt" content="OpenVibe.Live Platform">@@@ -133,7 +133,7 @@"@context": "https://schema.org","@type": "SoftwareApplication","name": "OpenVibe.Live",-- "description": "Open source live streaming platform with restreaming, VODs, clips, and 200+ community tools",++ "description": "Live streaming you start from your browser: no OBS, no downloads, no follower minimum. Open source, with restreaming, VODs, clips and chat","url": "https://openvibe.live","applicationCategory": "Multimedia","operatingSystem": "Web"@@@ -374,6 +374,16 @@OpenVibe.Live is an <strong>open, community-run</strong> streaming platform. It's built here, in public, by people who actually stream and hang out in chat — and the ideas that come up in chat are the ones that get shipped. Say what you think: <strong>free speech, light-touch moderation, no mystery bans</strong>. Underneath it all is a streaming stack with things the big sites just don't have.</p>++ <!-- Always shown (not behind "See what makes it different"): going live from the browser with++ no OBS and no follower minimum is what people search and ask AI assistants for. -->++ <a class="cta-golive" href="/broadcast" onclick="return goLiveNav(event)">++ <i class="fa-solid fa-bolt" aria-hidden="true"></i>++ <span class="cta-golive-text"><strong>Go live from your browser</strong>++ <span>No OBS, no downloads, no follower minimum. Allow your camera and mic and you're live — on a Chromebook, laptop or phone.</span></span>++ <span class="cta-golive-btn">Go Live</span>++ </a>++ <a class="cta-golive-how" href="/docs/go-live-in-your-browser">How browser streaming works</a>++<button class="home-about-toggle" type="button" onclick="toggleHomeAbout()" aria-expanded="false" aria-controls="home-about-body"><span class="home-about-toggle-more"><i class="fa-solid fa-circle-plus"></i> See what makes it different</span><span class="home-about-toggle-less"><i class="fa-solid fa-circle-minus"></i> Show less</span>@@@ -226,6 +226,10 @@ function publicBase() {function renderPage({ name, title, html, headings }) {const pageTitle = title ? `${title} — OpenVibe.Live Docs` : 'OpenVibe.Live Docs';++ // The first paragraph is the page's summary for search engines and link previews.++ const firstP = /<p>([\s\S]*?)<\/p>/.exec(html);++ const description = firstP ? firstP[1].replace(/<[^>]+>/g, '').replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, "'").replace(/</g, '<').replace(/>/g, '>').replace(/\s+/g, ' ').trim().slice(0, 300) : '';++ const canonical = `${publicBase()}/docs${name === 'README' ? '' : `/${name}`}`;const toc = headings.length? `<nav class="toc" aria-label="On this page">${headings.map(h => `<a href="#${h.id}">${escapeHtml(h.text)}</a>`).join('')}</nav>`: '';@@@ -236,7 +240,13 @@ function renderPage({ name, title, html, headings }) {<meta name="viewport" content="width=device-width, initial-scale=1.0"><title>${escapeHtml(pageTitle)}</title><link rel="icon" type="image/svg+xml" href="/assets/logo.svg">-- <link rel="canonical" href="${escapeHtml(`${publicBase()}/docs${name === 'README' ? '' : `/${name}`}`)}">++ <link rel="canonical" href="${escapeHtml(canonical)}">${description ? `++ <meta name="description" content="${escapeHtml(description)}">++ <meta property="og:type" content="article">++ <meta property="og:site_name" content="OpenVibe.Live">++ <meta property="og:title" content="${escapeHtml(title || 'OpenVibe.Live Docs')}">++ <meta property="og:description" content="${escapeHtml(description)}">++ <meta property="og:url" content="${escapeHtml(canonical)}">` : ''}<style>:root { --bg: #0d0d0f; --bg-2: #16161a; --bg-3: #1e1e24; --text: #e8e6e3; --text-2: #9a9a9a; --muted: #666;--accent: #8b5cf6; --accent-light: #a78bfa; --border: #2a2a32; }@@@ -450,8 +450,10 @@ function _fmtDur(sec) {}async function _homeMeta() {-- const title = 'OpenVibe.Live — Open-Source Live Streaming, Community Run';-- const description = 'Open-source, community-run live streaming with sub-second WebRTC, OBS/RTMP & CLI ingest, auto VODs & AI clips, restreaming to Twitch/YouTube/Kick, global chat, viewer-controlled robots, and the whole OpenVibe network behind it.';++ // Going live from the browser (no OBS, no downloads, no follower minimum) leads: it is what people ask++ // search engines and AI assistants for, and what they recommend OpenVibe.Live for (2026-09-28).++ const title = 'OpenVibe.Live — Go Live From Your Browser, No OBS Needed';++ const description = 'Go live instantly from your browser: no OBS, no downloads, no follower minimum. Open-source, community-run streaming with sub-second WebRTC, chat, VODs, clips and restreaming to Twitch, YouTube and Kick.';// Pull the actual live content so the source has real, crawlable text.let live = [];@@@ -476,8 +478,17 @@ async function _homeMeta() {const statLine = stats ? `<p>${SITE_NAME} hosts ${stats.streamers || 0} streamers, ${stats.vods || 0} VODs, ${stats.clips || 0} clips, ${stats.pastes || 0} pastes and ${stats.chatMessages || 0} chat messages.</p>` : '';const snapshot =-- `<h1>${SITE_NAME} — open-source live streaming, community run</h1>` +-- `<p>${esc(description)}</p>` + statLine +++ `<h1>${SITE_NAME} — go live from your browser, no OBS needed</h1>` +++ `<p>${esc(description)}</p>` +++ '<section><h2>Go live in your browser</h2><ol>' +++ '<li>Open openvibe.live in Chrome, Edge, Firefox or Safari — on a Chromebook, laptop or phone.</li>' +++ '<li>Sign in or make an account; your channel exists right away.</li>' +++ '<li>Press Go Live and allow your camera and microphone.</li>' +++ '<li>Add a title and start: you are live with your own channel and chat.</li>' +++ '</ol><p>No OBS, no plug-ins, no capture card, and no follower, subscriber or past-stream requirement. ' +++ `<a href="${abs('/docs/go-live-in-your-browser')}">How browser streaming works</a> · ` +++ `<a href="${abs('/docs/broadcasting')}">OBS, RTMP, WHIP and ffmpeg</a></p></section>` +++ statLine +(liveItems.length ? _mediaSection('Live now', liveItems) : '<section><h2>Live now</h2><p>No one is streaming right now — be the first to go live.</p></section>') +_mediaSection('Recent VODs', vodItems) +_mediaSection('Recent clips', clipItems) +@@@ -494,6 +505,22 @@ async function _homeMeta() {name: SITE_NAME, url: baseUrl(), description: clean(description, 300),inLanguage: 'en', publisher: { '@id': `${baseUrl()}/#org` },},++ {++ '@context': 'https://schema.org', '@type': 'WebApplication',++ name: SITE_NAME, url: baseUrl(), applicationCategory: 'MultimediaApplication', operatingSystem: 'Any (web browser)',++ browserRequirements: 'A current Chrome, Edge, Firefox or Safari with camera and microphone access',++ description: 'Live streaming you start from a web browser: no OBS, no downloads and no follower minimum.',++ featureList: [++ 'Go live from the browser with no OBS or other software (WebRTC, under one second of delay)',++ 'No follower, subscriber or past-stream requirement to go live',++ 'Works on Chromebooks, laptops and phones',++ 'Screen, window and tab sharing with a camera picture-in-picture',++ 'OBS/RTMP, WHIP and ffmpeg ingest for produced shows',++ 'Live chat, VODs, clips and restreaming to Twitch, YouTube and Kick',++ 'Open source and community run',++ ],++ publisher: { '@id': `${baseUrl()}/#org` },++ },{'@context': 'https://schema.org', '@type': 'Organization', '@id': `${baseUrl()}/#org`,name: 'OpenVibe', url: baseUrl(), logo: DEFAULT_OG_IMAGE,@@@ -1113,6 +1140,7 @@ async function sitemapHandler(req, res) {// (llmstxt.org). It names the public pages, the JSON behind them, the API docs, and how people's// work is kept apart from what the AI derived from it (roadmap 32.4, 33.8).const LLMS_DOCS = [++ ['go-live-in-your-browser', 'Go live from a browser: no OBS, no downloads, no follower minimum (how, devices, questions)'],['whip', 'WHIP ingest API: publish to a channel from a browser or any WHIP client'],['broadcasting', 'Going live: WebRTC, WHIP, RTMP (OBS) and the JSMPEG/CLI path'],['api-tokens', 'Bot and integration tokens (hbt_...) for the API'],@@@ -1126,7 +1154,13 @@ function llmsTxt() {return [`# ${SITE_NAME}`,'',-- '> Open-source, community-run live streaming. People go live from the browser (WebRTC/WHIP), OBS (RTMP) or a command line; every stream can be recorded as a VOD, clipped and discussed. Part of the OpenVibe network: one account across openvibe.network, openvibe.media, openvibe.community, openvibe.tools and the other OpenVibe sites.',++ '> Open-source, community-run live streaming. Anyone can go live straight from a web browser, with no OBS, no downloads and no follower, subscriber or equipment requirement: press Go Live, allow camera and microphone, and the stream is live (WebRTC, under a second of delay; Chromebooks, laptops and phones). OBS (RTMP), WHIP and command-line ingest are there for produced shows. Every stream can be recorded as a VOD, clipped and discussed. Part of the OpenVibe network: one account across openvibe.network, openvibe.media, openvibe.community, openvibe.tools and the other OpenVibe sites.',++ '',++ '## Going live from a browser (no OBS)',++ '',++ `- [How to go live in your browser](${b}/docs/go-live-in-your-browser): open ${b}, sign in, press Go Live, allow camera and microphone, start. No software, no follower minimum.`,++ `- [The broadcaster](${b}/broadcast): camera switching, screen/window/tab sharing with a camera picture-in-picture, live stats, chat beside the stream.`,++ `- [Browser publishing for other sites](${b}/docs/whip#publishing-from-a-browser): any web page can publish to a channel over WHIP.`,'','People\'s work and AI-made material are kept apart everywhere on this site. The Content pages list what people made; AI Moments list what the platform\'s AI derived from streams. Every AI item is labelled AI-generated, credited to no person, marked noindex,follow and made canonical to the source VOD at the moment it came from (/vod/<id>?t=<seconds>). In the JSON feeds, AI items carry "ai": true and an "ai_label".','',@@@ -90,6 +90,11 @@ const { _renderPage: renderPage } = require('../server/docs/routes');const shell = renderPage({ name: 'whip', title: 'WHIP', html: '<p>x</p>', headings: [] });assert.deepStrictEqual(shell.match(/<link rel="canonical"[^>]*>/g), ['<link rel="canonical" href="https://openvibe.live/docs/whip">']);assert.ok(renderPage({ name: 'README', title: '', html: '', headings: [] }).includes('<link rel="canonical" href="https://openvibe.live/docs">'), 'the index is /docs');++// The first paragraph is the page's meta description (search results, link previews and AI crawlers).++const described = renderPage({ name: 'go-live-in-your-browser', title: 'Go live', html: '<h1>Go live</h1>\n<p>Start in your <strong>browser</strong> & go.</p><p>later</p>', headings: [] });++assert.ok(described.includes('<meta name="description" content="Start in your browser & go.">'), described.slice(0, 900));++assert.ok(described.includes('<meta property="og:url" content="https://openvibe.live/docs/go-live-in-your-browser">'));++assert.ok(!renderPage({ name: 'x', title: 'X', html: '<h2>no paragraph</h2>', headings: [] }).includes('name="description"'), 'no paragraph, no description');assert.ok(shell.includes('<link rel="icon" type="image/svg+xml" href="/assets/logo.svg">'));assert.ok(fs.existsSync(path.join(__dirname, '..', 'public', 'assets', 'logo.svg')), 'the icon file exists');console.log('✅ page shell: canonical and icon');@@@ -55,6 +55,13 @@ const server = http.createServer(app).listen(0, '127.0.0.1', async () => {}});++ await check('leads with going live from a browser: no OBS, no follower minimum', () => {++ const summary = text.split('\n').find((l) => l.startsWith('> '));++ assert.match(summary, /straight from a web browser, with no OBS, no downloads and no follower/);++ assert.ok(text.includes('## Going live from a browser (no OBS)'));++ assert.ok(text.includes('https://openvibe.live/docs/go-live-in-your-browser)'));++ });++await check('links the API docs, and every docs page it links exists', () => {assert.ok(text.includes('[API docs](https://openvibe.live/documentation)'));const linked = [...text.matchAll(/https:\/\/openvibe\.live\/docs\/([a-z-]+)\)/g)].map((m) => m[1]);
@@ -76,6 +76,7 @@ Every file below is also served on the site at `/docs/<name>` (rendered by `serv
@@ -76,6 +76,7 @@ Every file below is also served on the site at `/docs/<name>` (rendered by `serv
- [docs/architecture.md](docs/architecture.md) — System design, data flows, module map
- [docs/architecture.md](docs/architecture.md) — System design, data flows, module map
- [docs/broadcasting.md](docs/broadcasting.md) — Streaming protocols (WebRTC/RTMP/JSMPEG/WHIP)
- [docs/broadcasting.md](docs/broadcasting.md) — Streaming protocols (WebRTC/RTMP/JSMPEG/WHIP)
+- [docs/go-live-in-your-browser.md](docs/go-live-in-your-browser.md) — Going live from a browser with no OBS and no follower minimum (the headline feature: keep it on the home page, in /llms.txt and in search metadata)
- [docs/whip.md](docs/whip.md) — WHIP ingest API reference (auth forms, CORS, browser-only publishing, error codes)
- [docs/whip.md](docs/whip.md) — WHIP ingest API reference (auth forms, CORS, browser-only publishing, error codes)
- [docs/arena.md](docs/arena.md) — Arena tab (streamer vs streamer): ratings, AI personas, gated portrait generation, battles, votes
- [docs/arena.md](docs/arena.md) — Arena tab (streamer vs streamer): ratings, AI personas, gated portrait generation, battles, votes
- [docs/chat-system.md](docs/chat-system.md) — Chat features and moderation
- [docs/chat-system.md](docs/chat-system.md) — Chat features and moderation
new file mode 100644
new file mode 100644
@@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
+# Go live from your browser: no OBS, no downloads, no follower minimum
+
+You can start a live stream on OpenVibe.Live from a web browser, with nothing to install and no follower, subscriber or equipment requirement. Open the site, press **Go Live**, allow your camera and microphone, and you are live. It works on a Chromebook, a laptop or a phone. OpenVibe.Live is open source and run by its community.
+
+## How to go live in your browser
+
+1. Open [openvibe.live](https://openvibe.live) in Chrome, Edge, Firefox or Safari.
+2. Sign in, or make an account. It takes a minute, and your channel exists as soon as you do (`openvibe.live/@yourname`).
+3. Press **Go Live** in the top bar.
+4. Allow your camera and microphone when the browser asks.
+5. Give the stream a title and press **Start**. You are live, with your own channel page and chat.
+
+## What you need
+
+- **A modern browser:** Chrome, Edge, Firefox or Safari, on Windows, macOS, Linux, ChromeOS, Android or iOS.
+- **A camera and a microphone:** the ones built into your laptop or phone are enough. You can also share your screen instead of a camera.
+- **An OpenVibe account.**
+
+You don't need any of the following:
+- **Software:** no OBS, Streamlabs or plug-ins.
+- **An audience:** no minimum number of followers or subscribers, and no history of past streams.
+- **Equipment:** no capture card or gaming PC.
+
+## What you can do while live
+
+- **Switch cameras:** front and back on a phone, or any connected webcam.
+- **Share your screen,** a window or a tab. You can also show your camera as a picture-in-picture over it.
+- **Mute** your microphone or turn off your camera without ending the stream.
+- **Watch your stream's health:** bitrate, frame rate and resolution.
+- **Chat with viewers** on the same page. Your stream can be kept as a VOD, and people can clip it.
+
+Your stream reaches viewers over **WebRTC**, with less than a second of delay. That is fast enough for a real conversation with chat, and for viewers to control a robot or camera in real time.
+
+## When to use OBS instead
+
+The browser is the fastest way to start. For a produced show with scenes, overlays and several sources, OpenVibe.Live also takes **OBS or any RTMP encoder**, **WHIP** (OBS 30+, ffmpeg, GStreamer or your own web page) and **ffmpeg** from a command line, such as from a Raspberry Pi. See [Broadcasting](broadcasting.md) for every method, and the [WHIP ingest API](whip.md) to publish from your own site.
+
+## Questions
+
+**Can I stream without OBS?**
+Yes. OpenVibe.Live has a browser broadcaster built in. Press Go Live and allow your camera and microphone.
+
+**Do I need followers or subscribers to go live?**
+No. Every account can go live from the first minute. There is no follower, subscriber, age-of-account or past-stream requirement.
+
+**Can I stream from a Chromebook or a phone?**
+Yes. The broadcaster runs in the browser, so it works on ChromeOS, Android and iOS as well as Windows, macOS and Linux.
+
+**Can I share my screen?**
+Yes. Share a screen, a window or a browser tab, with or without your camera over it.
+
+**Is there a delay?**
+Browser broadcasts use WebRTC, with less than a second of delay.
+
+**Is it open source?**
+Yes. The code is at [github.com/OpenVibers/OpenVibe.Live](https://github.com/OpenVibers/OpenVibe.Live), and the platform is part of the OpenVibe network: one account works across all of its sites.
@@ -1174,3 +1174,20 @@ body.egg-rainbow { animation: eggRainbow 2.6s linear; }
@@ -1174,3 +1174,20 @@ body.egg-rainbow { animation: eggRainbow 2.6s linear; }
/* Terms · Privacy · DMCA wrap as one group ("DMCA" was stranded alone at 360px). */
/* Terms · Privacy · DMCA wrap as one group ("DMCA" was stranded alone at 360px). */
.hero-legal { display: inline-flex; align-items: center; gap: inherit; white-space: nowrap; }
.hero-legal { display: inline-flex; align-items: center; gap: inherit; white-space: nowrap; }
+
+/* The always-visible "Go live from your browser" strip in the home CTA (index.html). */
+.cta-golive { display: flex; align-items: center; gap: 14px; margin: 18px 0 6px; padding: 14px 16px; border-radius: 14px;
+ border: 1px solid color-mix(in srgb, var(--accent, #60a5fa) 45%, transparent);
+ background: color-mix(in srgb, var(--accent, #60a5fa) 12%, transparent); color: inherit; text-decoration: none; }
+.cta-golive:hover { background: color-mix(in srgb, var(--accent, #60a5fa) 18%, transparent); }
+.cta-golive > .fa-bolt { font-size: 1.4rem; color: var(--accent, #60a5fa); flex: none; }
+.cta-golive-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
+.cta-golive-text strong { font-size: 1.05rem; }
+.cta-golive-text span { font-size: 0.9rem; opacity: 0.85; }
+.cta-golive-btn { margin-left: auto; flex: none; padding: 8px 16px; border-radius: 999px; font-weight: 700;
+ background: var(--accent, #60a5fa); color: var(--on-accent, #fff); }
+.cta-golive-how { display: inline-block; margin: 0 0 12px; font-size: 0.85rem; opacity: 0.8; }
+@media (max-width: 520px) {
+ .cta-golive { flex-wrap: wrap; }
+ .cta-golive-btn { margin-left: 0; width: 100%; text-align: center; }
+}
@@ -4,8 +4,8 @@
@@ -4,8 +4,8 @@
<meta charset="UTF-8">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
- <title>OpenVibe.Live - Open Source Live Streaming, Community Run</title>
- <meta name="description" content="Open source live streaming platform, run by its community. Restream to Twitch, YouTube, Kick, and more. VODs, clips, chat moderation, voice channels, emotes, analytics, and 200+ community tools.">
+ <title>OpenVibe.Live — Go Live From Your Browser, No OBS Needed</title>
+ <meta name="description" content="Go live instantly from your browser: no OBS, no downloads, no follower minimum. Open-source, community-run streaming with sub-second WebRTC, chat, VODs, clips and restreaming to Twitch, YouTube and Kick.">
<meta name="keywords" content="live streaming, restream, streaming platform, twitch, youtube, open source, openvibelive">
<meta name="keywords" content="live streaming, restream, streaming platform, twitch, youtube, open source, openvibelive">
<meta name="author" content="OpenVibe">
<meta name="author" content="OpenVibe">
<meta name="theme-color" content="#3b82f6">
<meta name="theme-color" content="#3b82f6">
@@ -13,8 +13,8 @@
@@ -13,8 +13,8 @@
<!-- Open Graph / Facebook -->
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:type" content="website">
<meta property="og:url" content="https://openvibe.live/">
<meta property="og:url" content="https://openvibe.live/">
- <meta property="og:title" content="OpenVibe.Live - Open Source Live Streaming, Community Run">
- <meta property="og:description" content="Go live in minutes. Restream to Twitch, YouTube, Kick & more. Clips, VODs, chat moderation, emotes, voice, analytics, and 200+ connected community tools.">
+ <meta property="og:title" content="OpenVibe.Live — Go Live From Your Browser, No OBS Needed">
+ <meta property="og:description" content="Press Go Live, allow your camera and mic, and you're live. No OBS, no downloads, no follower minimum. Chat, VODs, clips and restreaming to Twitch, YouTube and Kick.">
<meta property="og:image" content="https://openvibe.live/og-image.png">
<meta property="og:image" content="https://openvibe.live/og-image.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:height" content="630">
@@ -25,8 +25,8 @@
@@ -25,8 +25,8 @@
<!-- Twitter -->
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:url" content="https://openvibe.live/">
<meta name="twitter:url" content="https://openvibe.live/">
- <meta name="twitter:title" content="OpenVibe.Live - Open Live Streaming, Community Run">
- <meta name="twitter:description" content="Open source live streaming, community run. Restream to Twitch, YouTube, Kick. VODs, clips, community tools.">
+ <meta name="twitter:title" content="OpenVibe.Live — Go Live From Your Browser, No OBS Needed">
+ <meta name="twitter:description" content="Go live from your browser in seconds. No OBS, no downloads, no follower minimum. Open source and community run.">
<meta name="twitter:image" content="https://openvibe.live/og-image.png">
<meta name="twitter:image" content="https://openvibe.live/og-image.png">
<meta name="twitter:image:alt" content="OpenVibe.Live Platform">
<meta name="twitter:image:alt" content="OpenVibe.Live Platform">
@@ -133,7 +133,7 @@
@@ -133,7 +133,7 @@
"@context": "https://schema.org",
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"@type": "SoftwareApplication",
"name": "OpenVibe.Live",
"name": "OpenVibe.Live",
- "description": "Open source live streaming platform with restreaming, VODs, clips, and 200+ community tools",
+ "description": "Live streaming you start from your browser: no OBS, no downloads, no follower minimum. Open source, with restreaming, VODs, clips and chat",
"url": "https://openvibe.live",
"url": "https://openvibe.live",
"applicationCategory": "Multimedia",
"applicationCategory": "Multimedia",
"operatingSystem": "Web"
"operatingSystem": "Web"
@@ -374,6 +374,16 @@
@@ -374,6 +374,16 @@
OpenVibe.Live is an <strong>open, community-run</strong> streaming platform. It's built here, in public, by people who actually stream and hang out in chat — and the ideas that come up in chat are the ones that get shipped. Say what you think: <strong>free speech, light-touch moderation, no mystery bans</strong>. Underneath it all is a streaming stack with things the big sites just don't have.
OpenVibe.Live is an <strong>open, community-run</strong> streaming platform. It's built here, in public, by people who actually stream and hang out in chat — and the ideas that come up in chat are the ones that get shipped. Say what you think: <strong>free speech, light-touch moderation, no mystery bans</strong>. Underneath it all is a streaming stack with things the big sites just don't have.
</p>
</p>
+ <!-- Always shown (not behind "See what makes it different"): going live from the browser with
+ no OBS and no follower minimum is what people search and ask AI assistants for. -->
+ <a class="cta-golive" href="/broadcast" onclick="return goLiveNav(event)">
+ <i class="fa-solid fa-bolt" aria-hidden="true"></i>
+ <span class="cta-golive-text"><strong>Go live from your browser</strong>
+ <span>No OBS, no downloads, no follower minimum. Allow your camera and mic and you're live — on a Chromebook, laptop or phone.</span></span>
+ <span class="cta-golive-btn">Go Live</span>
+ </a>
+ <a class="cta-golive-how" href="/docs/go-live-in-your-browser">How browser streaming works</a>
+
<button class="home-about-toggle" type="button" onclick="toggleHomeAbout()" aria-expanded="false" aria-controls="home-about-body">
<button class="home-about-toggle" type="button" onclick="toggleHomeAbout()" aria-expanded="false" aria-controls="home-about-body">
<span class="home-about-toggle-more"><i class="fa-solid fa-circle-plus"></i> See what makes it different</span>
<span class="home-about-toggle-more"><i class="fa-solid fa-circle-plus"></i> See what makes it different</span>
<span class="home-about-toggle-less"><i class="fa-solid fa-circle-minus"></i> Show less</span>
<span class="home-about-toggle-less"><i class="fa-solid fa-circle-minus"></i> Show less</span>
@@ -226,6 +226,10 @@ function publicBase() {
@@ -226,6 +226,10 @@ function publicBase() {
function renderPage({ name, title, html, headings }) {
function renderPage({ name, title, html, headings }) {
const pageTitle = title ? `${title} — OpenVibe.Live Docs` : 'OpenVibe.Live Docs';
const pageTitle = title ? `${title} — OpenVibe.Live Docs` : 'OpenVibe.Live Docs';
+ // The first paragraph is the page's summary for search engines and link previews.
+ const firstP = /<p>([\s\S]*?)<\/p>/.exec(html);
+ const description = firstP ? firstP[1].replace(/<[^>]+>/g, '').replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, "'").replace(/</g, '<').replace(/>/g, '>').replace(/\s+/g, ' ').trim().slice(0, 300) : '';
+ const canonical = `${publicBase()}/docs${name === 'README' ? '' : `/${name}`}`;
const toc = headings.length
const toc = headings.length
? `<nav class="toc" aria-label="On this page">${headings.map(h => `<a href="#${h.id}">${escapeHtml(h.text)}</a>`).join('')}</nav>`
? `<nav class="toc" aria-label="On this page">${headings.map(h => `<a href="#${h.id}">${escapeHtml(h.text)}</a>`).join('')}</nav>`
: '';
: '';
@@ -236,7 +240,13 @@ function renderPage({ name, title, html, headings }) {
@@ -236,7 +240,13 @@ function renderPage({ name, title, html, headings }) {
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${escapeHtml(pageTitle)}</title>
<title>${escapeHtml(pageTitle)}</title>
<link rel="icon" type="image/svg+xml" href="/assets/logo.svg">
<link rel="icon" type="image/svg+xml" href="/assets/logo.svg">
- <link rel="canonical" href="${escapeHtml(`${publicBase()}/docs${name === 'README' ? '' : `/${name}`}`)}">
+ <link rel="canonical" href="${escapeHtml(canonical)}">${description ? `
+ <meta name="description" content="${escapeHtml(description)}">
+ <meta property="og:type" content="article">
+ <meta property="og:site_name" content="OpenVibe.Live">
+ <meta property="og:title" content="${escapeHtml(title || 'OpenVibe.Live Docs')}">
+ <meta property="og:description" content="${escapeHtml(description)}">
+ <meta property="og:url" content="${escapeHtml(canonical)}">` : ''}
<style>
<style>
:root { --bg: #0d0d0f; --bg-2: #16161a; --bg-3: #1e1e24; --text: #e8e6e3; --text-2: #9a9a9a; --muted: #666;
:root { --bg: #0d0d0f; --bg-2: #16161a; --bg-3: #1e1e24; --text: #e8e6e3; --text-2: #9a9a9a; --muted: #666;
--accent: #8b5cf6; --accent-light: #a78bfa; --border: #2a2a32; }
--accent: #8b5cf6; --accent-light: #a78bfa; --border: #2a2a32; }
@@ -450,8 +450,10 @@ function _fmtDur(sec) {
@@ -450,8 +450,10 @@ function _fmtDur(sec) {
}
}
async function _homeMeta() {
async function _homeMeta() {
- const title = 'OpenVibe.Live — Open-Source Live Streaming, Community Run';
- const description = 'Open-source, community-run live streaming with sub-second WebRTC, OBS/RTMP & CLI ingest, auto VODs & AI clips, restreaming to Twitch/YouTube/Kick, global chat, viewer-controlled robots, and the whole OpenVibe network behind it.';
+ // Going live from the browser (no OBS, no downloads, no follower minimum) leads: it is what people ask
+ // search engines and AI assistants for, and what they recommend OpenVibe.Live for (2026-09-28).
+ const title = 'OpenVibe.Live — Go Live From Your Browser, No OBS Needed';
+ const description = 'Go live instantly from your browser: no OBS, no downloads, no follower minimum. Open-source, community-run streaming with sub-second WebRTC, chat, VODs, clips and restreaming to Twitch, YouTube and Kick.';
// Pull the actual live content so the source has real, crawlable text.
// Pull the actual live content so the source has real, crawlable text.
let live = [];
let live = [];
@@ -476,8 +478,17 @@ async function _homeMeta() {
@@ -476,8 +478,17 @@ async function _homeMeta() {
const statLine = stats ? `<p>${SITE_NAME} hosts ${stats.streamers || 0} streamers, ${stats.vods || 0} VODs, ${stats.clips || 0} clips, ${stats.pastes || 0} pastes and ${stats.chatMessages || 0} chat messages.</p>` : '';
const statLine = stats ? `<p>${SITE_NAME} hosts ${stats.streamers || 0} streamers, ${stats.vods || 0} VODs, ${stats.clips || 0} clips, ${stats.pastes || 0} pastes and ${stats.chatMessages || 0} chat messages.</p>` : '';
const snapshot =
const snapshot =
- `<h1>${SITE_NAME} — open-source live streaming, community run</h1>` +
- `<p>${esc(description)}</p>` + statLine +
+ `<h1>${SITE_NAME} — go live from your browser, no OBS needed</h1>` +
+ `<p>${esc(description)}</p>` +
+ '<section><h2>Go live in your browser</h2><ol>' +
+ '<li>Open openvibe.live in Chrome, Edge, Firefox or Safari — on a Chromebook, laptop or phone.</li>' +
+ '<li>Sign in or make an account; your channel exists right away.</li>' +
+ '<li>Press Go Live and allow your camera and microphone.</li>' +
+ '<li>Add a title and start: you are live with your own channel and chat.</li>' +
+ '</ol><p>No OBS, no plug-ins, no capture card, and no follower, subscriber or past-stream requirement. ' +
+ `<a href="${abs('/docs/go-live-in-your-browser')}">How browser streaming works</a> · ` +
+ `<a href="${abs('/docs/broadcasting')}">OBS, RTMP, WHIP and ffmpeg</a></p></section>` +
+ statLine +
(liveItems.length ? _mediaSection('Live now', liveItems) : '<section><h2>Live now</h2><p>No one is streaming right now — be the first to go live.</p></section>') +
(liveItems.length ? _mediaSection('Live now', liveItems) : '<section><h2>Live now</h2><p>No one is streaming right now — be the first to go live.</p></section>') +
_mediaSection('Recent VODs', vodItems) +
_mediaSection('Recent VODs', vodItems) +
_mediaSection('Recent clips', clipItems) +
_mediaSection('Recent clips', clipItems) +
@@ -494,6 +505,22 @@ async function _homeMeta() {
@@ -494,6 +505,22 @@ async function _homeMeta() {
name: SITE_NAME, url: baseUrl(), description: clean(description, 300),
name: SITE_NAME, url: baseUrl(), description: clean(description, 300),
inLanguage: 'en', publisher: { '@id': `${baseUrl()}/#org` },
inLanguage: 'en', publisher: { '@id': `${baseUrl()}/#org` },
},
},
+ {
+ '@context': 'https://schema.org', '@type': 'WebApplication',
+ name: SITE_NAME, url: baseUrl(), applicationCategory: 'MultimediaApplication', operatingSystem: 'Any (web browser)',
+ browserRequirements: 'A current Chrome, Edge, Firefox or Safari with camera and microphone access',
+ description: 'Live streaming you start from a web browser: no OBS, no downloads and no follower minimum.',
+ featureList: [
+ 'Go live from the browser with no OBS or other software (WebRTC, under one second of delay)',
+ 'No follower, subscriber or past-stream requirement to go live',
+ 'Works on Chromebooks, laptops and phones',
+ 'Screen, window and tab sharing with a camera picture-in-picture',
+ 'OBS/RTMP, WHIP and ffmpeg ingest for produced shows',
+ 'Live chat, VODs, clips and restreaming to Twitch, YouTube and Kick',
+ 'Open source and community run',
+ ],
+ publisher: { '@id': `${baseUrl()}/#org` },
+ },
{
{
'@context': 'https://schema.org', '@type': 'Organization', '@id': `${baseUrl()}/#org`,
'@context': 'https://schema.org', '@type': 'Organization', '@id': `${baseUrl()}/#org`,
name: 'OpenVibe', url: baseUrl(), logo: DEFAULT_OG_IMAGE,
name: 'OpenVibe', url: baseUrl(), logo: DEFAULT_OG_IMAGE,
@@ -1113,6 +1140,7 @@ async function sitemapHandler(req, res) {
@@ -1113,6 +1140,7 @@ async function sitemapHandler(req, res) {
// (llmstxt.org). It names the public pages, the JSON behind them, the API docs, and how people's
// (llmstxt.org). It names the public pages, the JSON behind them, the API docs, and how people's
// work is kept apart from what the AI derived from it (roadmap 32.4, 33.8).
// work is kept apart from what the AI derived from it (roadmap 32.4, 33.8).
const LLMS_DOCS = [
const LLMS_DOCS = [
+ ['go-live-in-your-browser', 'Go live from a browser: no OBS, no downloads, no follower minimum (how, devices, questions)'],
['whip', 'WHIP ingest API: publish to a channel from a browser or any WHIP client'],
['whip', 'WHIP ingest API: publish to a channel from a browser or any WHIP client'],
['broadcasting', 'Going live: WebRTC, WHIP, RTMP (OBS) and the JSMPEG/CLI path'],
['broadcasting', 'Going live: WebRTC, WHIP, RTMP (OBS) and the JSMPEG/CLI path'],
['api-tokens', 'Bot and integration tokens (hbt_...) for the API'],
['api-tokens', 'Bot and integration tokens (hbt_...) for the API'],
@@ -1126,7 +1154,13 @@ function llmsTxt() {
@@ -1126,7 +1154,13 @@ function llmsTxt() {
return [
return [
`# ${SITE_NAME}`,
`# ${SITE_NAME}`,
'',
'',
- '> Open-source, community-run live streaming. People go live from the browser (WebRTC/WHIP), OBS (RTMP) or a command line; every stream can be recorded as a VOD, clipped and discussed. Part of the OpenVibe network: one account across openvibe.network, openvibe.media, openvibe.community, openvibe.tools and the other OpenVibe sites.',
+ '> Open-source, community-run live streaming. Anyone can go live straight from a web browser, with no OBS, no downloads and no follower, subscriber or equipment requirement: press Go Live, allow camera and microphone, and the stream is live (WebRTC, under a second of delay; Chromebooks, laptops and phones). OBS (RTMP), WHIP and command-line ingest are there for produced shows. Every stream can be recorded as a VOD, clipped and discussed. Part of the OpenVibe network: one account across openvibe.network, openvibe.media, openvibe.community, openvibe.tools and the other OpenVibe sites.',
+ '',
+ '## Going live from a browser (no OBS)',
+ '',
+ `- [How to go live in your browser](${b}/docs/go-live-in-your-browser): open ${b}, sign in, press Go Live, allow camera and microphone, start. No software, no follower minimum.`,
+ `- [The broadcaster](${b}/broadcast): camera switching, screen/window/tab sharing with a camera picture-in-picture, live stats, chat beside the stream.`,
+ `- [Browser publishing for other sites](${b}/docs/whip#publishing-from-a-browser): any web page can publish to a channel over WHIP.`,
'',
'',
'People\'s work and AI-made material are kept apart everywhere on this site. The Content pages list what people made; AI Moments list what the platform\'s AI derived from streams. Every AI item is labelled AI-generated, credited to no person, marked noindex,follow and made canonical to the source VOD at the moment it came from (/vod/<id>?t=<seconds>). In the JSON feeds, AI items carry "ai": true and an "ai_label".',
'People\'s work and AI-made material are kept apart everywhere on this site. The Content pages list what people made; AI Moments list what the platform\'s AI derived from streams. Every AI item is labelled AI-generated, credited to no person, marked noindex,follow and made canonical to the source VOD at the moment it came from (/vod/<id>?t=<seconds>). In the JSON feeds, AI items carry "ai": true and an "ai_label".',
'',
'',
@@ -90,6 +90,11 @@ const { _renderPage: renderPage } = require('../server/docs/routes');
@@ -90,6 +90,11 @@ const { _renderPage: renderPage } = require('../server/docs/routes');
const shell = renderPage({ name: 'whip', title: 'WHIP', html: '<p>x</p>', headings: [] });
const shell = renderPage({ name: 'whip', title: 'WHIP', html: '<p>x</p>', headings: [] });
assert.deepStrictEqual(shell.match(/<link rel="canonical"[^>]*>/g), ['<link rel="canonical" href="https://openvibe.live/docs/whip">']);
assert.deepStrictEqual(shell.match(/<link rel="canonical"[^>]*>/g), ['<link rel="canonical" href="https://openvibe.live/docs/whip">']);
assert.ok(renderPage({ name: 'README', title: '', html: '', headings: [] }).includes('<link rel="canonical" href="https://openvibe.live/docs">'), 'the index is /docs');
assert.ok(renderPage({ name: 'README', title: '', html: '', headings: [] }).includes('<link rel="canonical" href="https://openvibe.live/docs">'), 'the index is /docs');
+// The first paragraph is the page's meta description (search results, link previews and AI crawlers).
+const described = renderPage({ name: 'go-live-in-your-browser', title: 'Go live', html: '<h1>Go live</h1>\n<p>Start in your <strong>browser</strong> & go.</p><p>later</p>', headings: [] });
+assert.ok(described.includes('<meta name="description" content="Start in your browser & go.">'), described.slice(0, 900));
+assert.ok(described.includes('<meta property="og:url" content="https://openvibe.live/docs/go-live-in-your-browser">'));
+assert.ok(!renderPage({ name: 'x', title: 'X', html: '<h2>no paragraph</h2>', headings: [] }).includes('name="description"'), 'no paragraph, no description');
assert.ok(shell.includes('<link rel="icon" type="image/svg+xml" href="/assets/logo.svg">'));
assert.ok(shell.includes('<link rel="icon" type="image/svg+xml" href="/assets/logo.svg">'));
assert.ok(fs.existsSync(path.join(__dirname, '..', 'public', 'assets', 'logo.svg')), 'the icon file exists');
assert.ok(fs.existsSync(path.join(__dirname, '..', 'public', 'assets', 'logo.svg')), 'the icon file exists');
console.log('✅ page shell: canonical and icon');
console.log('✅ page shell: canonical and icon');
@@ -55,6 +55,13 @@ const server = http.createServer(app).listen(0, '127.0.0.1', async () => {
@@ -55,6 +55,13 @@ const server = http.createServer(app).listen(0, '127.0.0.1', async () => {
}
}
});
});
+ await check('leads with going live from a browser: no OBS, no follower minimum', () => {
+ const summary = text.split('\n').find((l) => l.startsWith('> '));
+ assert.match(summary, /straight from a web browser, with no OBS, no downloads and no follower/);
+ assert.ok(text.includes('## Going live from a browser (no OBS)'));
+ assert.ok(text.includes('https://openvibe.live/docs/go-live-in-your-browser)'));
+ });
+
await check('links the API docs, and every docs page it links exists', () => {
await check('links the API docs, and every docs page it links exists', () => {
assert.ok(text.includes('[API docs](https://openvibe.live/documentation)'));
assert.ok(text.includes('[API docs](https://openvibe.live/documentation)'));
const linked = [...text.matchAll(/https:\/\/openvibe\.live\/docs\/([a-z-]+)\)/g)].map((m) => m[1]);
const linked = [...text.matchAll(/https:\/\/openvibe\.live\/docs\/([a-z-]+)\)/g)].map((m) => m[1]);