openvibers/openvibe.live Commits
openvibe-shared v4.59.0 (was v4.57.1) (#479)
Changes
@@@ -177,5 +177,5 @@ Minimum `.env`: `BASE_URL`, `JWT_SECRET`, `OV_NETWORK_URL`, `OV_NETWORK_INTERNAL<!-- versions:start -->- openvibe-contracts: v0.222.0- openvibe-sdk: v0.74.0--- openvibe-shared: v4.57.1++- openvibe-shared: v4.59.0<!-- versions:end -->@@@ -7,7 +7,7 @@"domain": "openvibe.live (www, ingest, whip)","contracts": "openvibe-contracts v0.222.0","sdk": "openvibe-sdk v0.74.0",-- "shared": "openvibe-shared v4.57.1",++ "shared": "openvibe-shared v4.59.0","capabilities": ["live.chat_context.read","live.chat_effects.write",@@@ -25,7 +25,7 @@"onnxruntime-node": "^1.20.0","openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.222.0","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.74.0",-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.57.1",++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.59.0","pg": "^8.23.1","sanitize-html": "^2.17.7","sdp-transform": "^3.0.0",@@@ -2884,9 +2884,9 @@}},"node_modules/openvibe-shared": {-- "version": "4.57.1",-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.57.1",-- "integrity": "sha512-zlU7F9H9E/5gqzklyGPJl7SH+WQ/+wn3e9Z7ErI3FbKxQ3caaVEGdZyX4Uww0PbvpgcXs2i6AnwNBi0JSOMlXQ==",++ "version": "4.59.0",++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.59.0",++ "integrity": "sha512-kaJ6Tcz7WCewK/kCx4NzNWRNI4U1Z1lpwCQHWD115YtcaJps8Ulqpu1y2ArLpywARHtYf3ddPH/hL9wkb6MJlw==","license": "MIT","dependencies": {"jsonwebtoken": "^9.0.0",@@@ -44,7 +44,7 @@"onnxruntime-node": "^1.20.0","openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.222.0","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.74.0",-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.57.1",++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.59.0","pg": "^8.23.1","sanitize-html": "^2.17.7","sdp-transform": "^3.0.0",BBinary files a/public/assets/logo-192.png and b/public/assets/logo-192.png differBBinary files a/public/assets/logo-512.png and b/public/assets/logo-512.png differBBinary files a/public/assets/logo-72.png and b/public/assets/logo-72.png differBBinary files a/public/assets/logo-maskable-192.png and b/public/assets/logo-maskable-192.png differBBinary files a/public/assets/logo-maskable-512.png and b/public/assets/logo-maskable-512.png differ@@@ -1,8 +1,3 @@--<svg xmlns="http://www.w3.org/2000/svg" viewBox="-32 -32 64 64"><defs><linearGradient id="ring" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#60a5fa"/><stop offset="1" stop-color="#2563eb"/></linearGradient>--<radialGradient id="glow"><stop offset="0" stop-color="#60a5fa" stop-opacity=".34"/><stop offset="1" stop-color="#60a5fa" stop-opacity="0"/></radialGradient>--<radialGradient id="bg" cx=".5" cy=".38" r=".8"><stop offset="0" stop-color="#16223a"/><stop offset=".6" stop-color="#0a0f1c"/><stop offset="1" stop-color="#060912"/></radialGradient></defs><rect x="-32" y="-32" width="64" height="64" rx="15" fill="url(#bg)"/><g transform="scale(1.22)">--<circle r="21" fill="url(#glow)"/>--<circle r="18" fill="none" stroke="url(#ring)" stroke-width="4" opacity=".38"/>--<path d="M0,-18 A18,18 0 0,1 17.4,4.6" fill="none" stroke="url(#ring)" stroke-width="4.4" stroke-linecap="round"/>--<path d="M-9.5,-7 L0,10 L9.5,-7" fill="none" stroke="#fff" stroke-width="4.8" stroke-linecap="round" stroke-linejoin="round"/>--<circle cx="17.4" cy="4.6" r="3.2" fill="#ef4444"/></g></svg>\\ No newline at end of file++<svg xmlns="http://www.w3.org/2000/svg" viewBox="-32 -32 64 64"><defs><mask id="ovh" maskUnits="userSpaceOnUse" x="-20" y="-20" width="140" height="140"><rect x="-20" y="-20" width="140" height="140" fill="#fff"/><path d="M70.59 68.5L53.31 31.5M70.59 68.5L88.41 31.5" fill="none" stroke="#000" stroke-width="24" stroke-linecap="round"/></mask>++<radialGradient id="glow"><stop offset="0" stop-color="#60a5fa" stop-opacity=".3"/><stop offset="1" stop-color="#60a5fa" stop-opacity="0"/></radialGradient>++<radialGradient id="bg" cx=".5" cy=".38" r=".8"><stop offset="0" stop-color="#16223a"/><stop offset=".6" stop-color="#0a0f1c"/><stop offset="1" stop-color="#060912"/></radialGradient></defs><rect x="-32" y="-32" width="64" height="64" rx="15" fill="url(#bg)"/><g transform="scale(0.58) translate(-50 -50)"><ellipse cx="50" cy="50" rx="52" ry="40" fill="url(#glow)"/><circle cx="30.09" cy="50" r="18" fill="none" stroke="#4f7cff" stroke-width="18" mask="url(#ovh)"/><path d="M70.59 68.5L53.31 31.5M70.59 68.5L88.41 31.5" fill="none" stroke="#8b5cf6" stroke-width="17" stroke-linecap="round" stroke-linejoin="round"/><circle cx="30.09" cy="50" r="5.58" fill="#ef4444"/></g></svg>\\ No newline at end of file@@@ -37,7 +37,7 @@<meta name="apple-mobile-web-app-capable" content="yes"><meta name="mobile-web-app-capable" content="yes"><link rel="apple-touch-icon" href="/assets/logo-192.png">-- <link rel="apple-touch-icon" href="/assets/logo.svg">++ <link rel="apple-touch-icon" href="/assets/logo-192.png"><!-- Critical theme bootstrap (ov-theme-boot) — MUST stay inline and stay ABOVE the stylesheets.Paints the user's cached theme synchronously, before the browser has any chance to@@@ -970,6 +970,19 @@ function sameSitePath(url) {try { const u = new URL(url); return u.origin === location.origin ? `${u.pathname}${u.search}${u.hash}` : url; } catch { return url; }}++// The navbar's OpenVibe mark draws its ring round while one of Live's own page moves loads, at the pace this browser++// learned for them, and closes it when the route has rendered (ov-mark.js, OVMark.navStart/navEnd). A route that++// renders without whenRouteReady closes it after the move's own turn of the event loop; none waits past 8 s.++let _ovNavSeq = 0, _ovNavOn = 0, _ovNavWaiting = false;++function _ovNavStart() {++ const me = _ovNavOn = ++_ovNavSeq;++ _ovNavWaiting = false;++ try { window.OVMark && window.OVMark.navStart('app'); } catch { /* */ }++ setTimeout(() => { if (_ovNavOn === me && !_ovNavWaiting) _ovNavEnd(); }, 0);++ setTimeout(() => { if (_ovNavOn === me) _ovNavEnd(); }, 8000);++}++function _ovNavEnd() { if (!_ovNavOn) return; _ovNavOn = 0; _ovNavWaiting = false; try { window.OVMark && window.OVMark.navEnd('app'); } catch { /* */ } }++function navigate(urlPath, replace = false) {if (isOffSite(urlPath)) { if (replace) location.replace(urlPath); else location.href = urlPath; return; }urlPath = sameSitePath(urlPath);@@@ -980,6 +993,7 @@ function navigate(urlPath, replace = false) {return;}teardownRoute(urlPath);++ _ovNavStart();// Normalize pathif (!urlPath.startsWith('/')) urlPath = '/' + urlPath;@@@ -1057,10 +1071,13 @@ function whenRouteReady(pageId, render) {console.error(`[route] ${path} failed to render:`, err);if (window.ov) ov.showRouteError(`page-${pageId}`, err, () => whenRouteReady(pageId, render));}++ _ovNavEnd();};if (!window.ov) return run();++ if (_ovNavOn) _ovNavWaiting = true;ov.route(path).then(run, (err) => {if (!ov.isCurrent(gen)) return;++ _ovNavEnd();ov.showRouteError(`page-${pageId}`, err, () => whenRouteReady(pageId, render));});}@@@ -2087,7 +2104,7 @@ async function handleThumbnailError(img) {function thumbImg(thumbnailUrl, fallbackIcon, alt, regenerateUrl = null) {// The old brand glyph as a placeholder → the OV mark (static, muted).const iconHtml = (extra) => fallbackIcon === 'fa-circle-nodes'-- ? `<span class="ov-mark ov-mark--ph" data-size="44" data-static="1"${extra || ''}></span>`++ ? `<span class="ov-mark ov-mark--ph" data-size="44" data-tone="ink" data-static="1"${extra || ''}></span>`: `<i class="fa-solid ${fallbackIcon}"${extra || ''}></i>`;if (thumbnailUrl) {// openvibe.media thumbnails come in sizes (Media's /t/:id?w=&fmt=): a card loads a WebP near its width.@@@ -59,7 +59,7 @@<div class="tour-core-wrap"><div class="tour-core" data-node="core"><span class="tour-core-ring"></span><span class="tour-core-ring tour-core-ring--2"></span>-- <span class="tour-core-logo"><span class="ov-mark" data-size="30" style="color:#fff"></span></span>++ <span class="tour-core-logo"><span class="ov-mark" data-size="34" data-tone="white"></span></span><b>OpenVibe.Live</b><!-- The old feature line here ("<1s latency · chat · emotes · …") listed the samethings the chip grid below spells out properly. Two statements of the same@@@ -22,7 +22,7 @@ const BUDGETS = {htmlRawKB: 120, // measured 94.9htmlBrotliKB: 30,jsFiles: 26, // measured 23 (incl. route scripts for "/")-- jsRawKB: 1240, // 1238.8 with the home's featured stream once and the intro closed on phones (2026-10-31); 1237.4 with the home's two more tab blocks on phones (2026-10-30); 1233.9 with the home's Catch up tabs on phones (2026-10-30); 1230.8 with openvibe-shared 4.53.0: the footer's columns fold on phones (2026-10-30); 1227.8 with openvibe-shared 4.52.0: the Dock's loader and its Chats tab (2026-10-30); 1223.5 with openvibe-shared 4.48.0 (the site switcher on the mark, the menu's Start tab and quick tools; Kit's touch hit areas and the phone navbar fix, 4.44-4.47.3); 1215.4 with openvibe-shared 4.43.0 (room.css carries the kit tokens, 4.39.1; the kit's 4.39.0 rules); measured 1203.9 (2026-10-28: openvibe-shared 4.30.0, the bell center: tabs with counts, the Unread filter, thumbnails, swipe, the phone sheet; 4.31.0's ✦ adds about 3 KB); 1187.2 (2026-10-28: openvibe-shared 4.27.0, Notifications 2.0: opaque themed toasts held while a menu is open, grouping, priority, System cards and the rich bell panel); 1158.8 (2026-10-28: openvibe-shared 4.25.0, the menu's orb, messages, the phone sheet and auto-hide in the navbar; the messenger opens from the bar)++ jsRawKB: 1243, // 1242.7 with openvibe-shared 4.59.0: the Pair mark beside the name, set in the brand face, and the ring on page moves (2026-10-31); 1238.8 with the home's featured stream once and the intro closed on phones (2026-10-31); 1237.4 with the home's two more tab blocks on phones (2026-10-30); 1233.9 with the home's Catch up tabs on phones (2026-10-30); 1230.8 with openvibe-shared 4.53.0: the footer's columns fold on phones (2026-10-30); 1227.8 with openvibe-shared 4.52.0: the Dock's loader and its Chats tab (2026-10-30); 1223.5 with openvibe-shared 4.48.0 (the site switcher on the mark, the menu's Start tab and quick tools; Kit's touch hit areas and the phone navbar fix, 4.44-4.47.3); 1215.4 with openvibe-shared 4.43.0 (room.css carries the kit tokens, 4.39.1; the kit's 4.39.0 rules); measured 1203.9 (2026-10-28: openvibe-shared 4.30.0, the bell center: tabs with counts, the Unread filter, thumbnails, swipe, the phone sheet; 4.31.0's ✦ adds about 3 KB); 1187.2 (2026-10-28: openvibe-shared 4.27.0, Notifications 2.0: opaque themed toasts held while a menu is open, grouping, priority, System cards and the rich bell panel); 1158.8 (2026-10-28: openvibe-shared 4.25.0, the menu's orb, messages, the phone sheet and auto-hide in the navbar; the messenger opens from the bar)jsBrotliKB: 292, // 291.1 with openvibe-shared 4.57.1 (the Dock's async token and scope-aware controls, 4.57.0; the tool frame's facts, 4.56.0) (2026-10-31); 290.6 with the home's two more tab blocks on phones (2026-10-30); 289.8 with the home's Catch up tabs on phones (2026-10-30); 288.2 with openvibe-shared 4.52.0: the Dock's loader and its Chats tab (2026-10-30); 287.4 with openvibe-shared 4.48.0 (the site switcher on the mark, the menu's Start tab and quick tools; Kit's touch hit areas and the phone navbar fix, 4.44-4.47.3); measured 283.2 (2026-10-28: openvibe-shared 4.30.0, the bell center as above); 279.6 (2026-10-28: openvibe-shared 4.27.0, Notifications 2.0 as above); 273.1 (2026-10-28: openvibe-shared 4.25.0 as above); 270.5 (2026-10-28: openvibe-shared 4.22.0, the navbar's search magnifier with / and Ctrl+K and the More menu; search.js and loading.js load only when used); 269.6 (2026-10-28: openvibe-shared 4.19.0, the account menu's gear and people-group icons inline; 268 on 2026-10-27: openvibe-shared 4.16.0, the folded balance chip, Across OpenVibe with site marks and the icon preload in the navbar); 265.3 (2026-10-27: openvibe-shared 4.15.0, the compact footer opens into the whole one, and the pulse line); 263.3 on 10-23 (openvibe-shared 4.9.0, status text twins in every theme); 262.5 on 10-17 (openvibe-shared 4.4.0, every site in the launcher)cssRawKB: 270, // measured ~243 since the first-paint subset (style.core.css) replaced style.css (~717 before)cssBrotliKB: 55, // measured ~47.5 (was ~130)@@@ -595,8 +595,10 @@ console.log(`[Server] /shared: serving ${SHARED_BROWSER_FILES.length} browser fi});// The share cards (og:image on every page), before the browser-file allowlist below.require('./web/share-cards').register(app);-- // Serve only the whitelisted browser files — don't expose the entire package-- const sharedFileSet = new Set(SHARED_BROWSER_FILES);++ // Serve only the whitelisted browser files — don't expose the entire package — and the brand face the navbar++ // declares beside itself (files.FONTS, Shared 4.59.0).++ const SHARED_FONTS = sharedFiles.FONTS || [];++ const sharedFileSet = new Set([...SHARED_BROWSER_FILES, ...SHARED_FONTS]);app.use('/shared', (req, res, next) => {const fileName = path.basename(req.path);if (!sharedFileSet.has(fileName)) {@@@ -609,7 +611,7 @@ console.log(`[Server] /shared: serving ${SHARED_BROWSER_FILES.length} browser ficonst hashed = Boolean(req.query.v) && req.query.v === assets.hashOf('/shared/' + fileName);res.setHeader('Cache-Control', cache.assetHeaders(req.originalUrl, { hashed }));if (hashed) res.setHeader('CDN-Cache-Control', cache.IMMUTABLE);-- res.setHeader('Content-Type', 'application/javascript; charset=utf-8');++ res.setHeader('Content-Type', SHARED_FONTS.includes(fileName) ? 'font/woff2' : 'application/javascript; charset=utf-8');res.sendFile(filePath, (err) => {// A listed file that cannot be read is this server's fault, and passing: never a cacheable answer// (its headers above said immutable; Cloudflare kept a 404 navbar through a deploy on 2026-10-17).@@@ -47,6 +47,7 @@ function sandbox({ loaded = 'aaaaaaaaaaaa', current = 'bbbbbbbbbbbb', stored = n},sessionStorage: { getItem: (k) => (store.has(k) ? store.get(k) : null), setItem: (k, v) => store.set(k, String(v)) },fetch: async (url) => { calls.push(['fetch', url]); return { ok: true, json: async () => ({ release: current }) }; },++ setTimeout: () => 0,teardownRoute: () => calls.push(['teardown']),routeFromURL: () => calls.push(['route']),};
@@ -177,5 +177,5 @@ Minimum `.env`: `BASE_URL`, `JWT_SECRET`, `OV_NETWORK_URL`, `OV_NETWORK_INTERNAL
@@ -177,5 +177,5 @@ Minimum `.env`: `BASE_URL`, `JWT_SECRET`, `OV_NETWORK_URL`, `OV_NETWORK_INTERNAL
<!-- versions:start -->
<!-- versions:start -->
- openvibe-contracts: v0.222.0
- openvibe-contracts: v0.222.0
- openvibe-sdk: v0.74.0
- openvibe-sdk: v0.74.0
-- openvibe-shared: v4.57.1
+- openvibe-shared: v4.59.0
<!-- versions:end -->
<!-- versions:end -->
@@ -7,7 +7,7 @@
@@ -7,7 +7,7 @@
"domain": "openvibe.live (www, ingest, whip)",
"domain": "openvibe.live (www, ingest, whip)",
"contracts": "openvibe-contracts v0.222.0",
"contracts": "openvibe-contracts v0.222.0",
"sdk": "openvibe-sdk v0.74.0",
"sdk": "openvibe-sdk v0.74.0",
- "shared": "openvibe-shared v4.57.1",
+ "shared": "openvibe-shared v4.59.0",
"capabilities": [
"capabilities": [
"live.chat_context.read",
"live.chat_context.read",
"live.chat_effects.write",
"live.chat_effects.write",
@@ -25,7 +25,7 @@
@@ -25,7 +25,7 @@
"onnxruntime-node": "^1.20.0",
"onnxruntime-node": "^1.20.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.222.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.222.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.74.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.74.0",
- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.57.1",
+ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.59.0",
"pg": "^8.23.1",
"pg": "^8.23.1",
"sanitize-html": "^2.17.7",
"sanitize-html": "^2.17.7",
"sdp-transform": "^3.0.0",
"sdp-transform": "^3.0.0",
@@ -2884,9 +2884,9 @@
@@ -2884,9 +2884,9 @@
}
}
},
},
"node_modules/openvibe-shared": {
"node_modules/openvibe-shared": {
- "version": "4.57.1",
- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.57.1",
- "integrity": "sha512-zlU7F9H9E/5gqzklyGPJl7SH+WQ/+wn3e9Z7ErI3FbKxQ3caaVEGdZyX4Uww0PbvpgcXs2i6AnwNBi0JSOMlXQ==",
+ "version": "4.59.0",
+ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.59.0",
+ "integrity": "sha512-kaJ6Tcz7WCewK/kCx4NzNWRNI4U1Z1lpwCQHWD115YtcaJps8Ulqpu1y2ArLpywARHtYf3ddPH/hL9wkb6MJlw==",
"license": "MIT",
"license": "MIT",
"dependencies": {
"dependencies": {
"jsonwebtoken": "^9.0.0",
"jsonwebtoken": "^9.0.0",
@@ -44,7 +44,7 @@
@@ -44,7 +44,7 @@
"onnxruntime-node": "^1.20.0",
"onnxruntime-node": "^1.20.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.222.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.222.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.74.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.74.0",
- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.57.1",
+ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.59.0",
"pg": "^8.23.1",
"pg": "^8.23.1",
"sanitize-html": "^2.17.7",
"sanitize-html": "^2.17.7",
"sdp-transform": "^3.0.0",
"sdp-transform": "^3.0.0",
Binary files a/public/assets/logo-192.png and b/public/assets/logo-192.png differ
Binary files a/public/assets/logo-192.png and b/public/assets/logo-192.png differ
Binary files a/public/assets/logo-512.png and b/public/assets/logo-512.png differ
Binary files a/public/assets/logo-512.png and b/public/assets/logo-512.png differ
Binary files a/public/assets/logo-72.png and b/public/assets/logo-72.png differ
Binary files a/public/assets/logo-72.png and b/public/assets/logo-72.png differ
Binary files a/public/assets/logo-maskable-192.png and b/public/assets/logo-maskable-192.png differ
Binary files a/public/assets/logo-maskable-192.png and b/public/assets/logo-maskable-192.png differ
Binary files a/public/assets/logo-maskable-512.png and b/public/assets/logo-maskable-512.png differ
Binary files a/public/assets/logo-maskable-512.png and b/public/assets/logo-maskable-512.png differ
@@ -1,8 +1,3 @@
@@ -1,8 +1,3 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="-32 -32 64 64"><defs><linearGradient id="ring" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#60a5fa"/><stop offset="1" stop-color="#2563eb"/></linearGradient>
-<radialGradient id="glow"><stop offset="0" stop-color="#60a5fa" stop-opacity=".34"/><stop offset="1" stop-color="#60a5fa" stop-opacity="0"/></radialGradient>
-<radialGradient id="bg" cx=".5" cy=".38" r=".8"><stop offset="0" stop-color="#16223a"/><stop offset=".6" stop-color="#0a0f1c"/><stop offset="1" stop-color="#060912"/></radialGradient></defs><rect x="-32" y="-32" width="64" height="64" rx="15" fill="url(#bg)"/><g transform="scale(1.22)">
-<circle r="21" fill="url(#glow)"/>
-<circle r="18" fill="none" stroke="url(#ring)" stroke-width="4" opacity=".38"/>
-<path d="M0,-18 A18,18 0 0,1 17.4,4.6" fill="none" stroke="url(#ring)" stroke-width="4.4" stroke-linecap="round"/>
-<path d="M-9.5,-7 L0,10 L9.5,-7" fill="none" stroke="#fff" stroke-width="4.8" stroke-linecap="round" stroke-linejoin="round"/>
-<circle cx="17.4" cy="4.6" r="3.2" fill="#ef4444"/></g></svg>
\ No newline at end of file
\ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="-32 -32 64 64"><defs><mask id="ovh" maskUnits="userSpaceOnUse" x="-20" y="-20" width="140" height="140"><rect x="-20" y="-20" width="140" height="140" fill="#fff"/><path d="M70.59 68.5L53.31 31.5M70.59 68.5L88.41 31.5" fill="none" stroke="#000" stroke-width="24" stroke-linecap="round"/></mask>
+<radialGradient id="glow"><stop offset="0" stop-color="#60a5fa" stop-opacity=".3"/><stop offset="1" stop-color="#60a5fa" stop-opacity="0"/></radialGradient>
+<radialGradient id="bg" cx=".5" cy=".38" r=".8"><stop offset="0" stop-color="#16223a"/><stop offset=".6" stop-color="#0a0f1c"/><stop offset="1" stop-color="#060912"/></radialGradient></defs><rect x="-32" y="-32" width="64" height="64" rx="15" fill="url(#bg)"/><g transform="scale(0.58) translate(-50 -50)"><ellipse cx="50" cy="50" rx="52" ry="40" fill="url(#glow)"/><circle cx="30.09" cy="50" r="18" fill="none" stroke="#4f7cff" stroke-width="18" mask="url(#ovh)"/><path d="M70.59 68.5L53.31 31.5M70.59 68.5L88.41 31.5" fill="none" stroke="#8b5cf6" stroke-width="17" stroke-linecap="round" stroke-linejoin="round"/><circle cx="30.09" cy="50" r="5.58" fill="#ef4444"/></g></svg>
\ No newline at end of file
\ No newline at end of file
@@ -37,7 +37,7 @@
@@ -37,7 +37,7 @@
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<link rel="apple-touch-icon" href="/assets/logo-192.png">
<link rel="apple-touch-icon" href="/assets/logo-192.png">
- <link rel="apple-touch-icon" href="/assets/logo.svg">
+ <link rel="apple-touch-icon" href="/assets/logo-192.png">
<!-- Critical theme bootstrap (ov-theme-boot) — MUST stay inline and stay ABOVE the stylesheets.
<!-- Critical theme bootstrap (ov-theme-boot) — MUST stay inline and stay ABOVE the stylesheets.
Paints the user's cached theme synchronously, before the browser has any chance to
Paints the user's cached theme synchronously, before the browser has any chance to
@@ -970,6 +970,19 @@ function sameSitePath(url) {
@@ -970,6 +970,19 @@ function sameSitePath(url) {
try { const u = new URL(url); return u.origin === location.origin ? `${u.pathname}${u.search}${u.hash}` : url; } catch { return url; }
try { const u = new URL(url); return u.origin === location.origin ? `${u.pathname}${u.search}${u.hash}` : url; } catch { return url; }
}
}
+// The navbar's OpenVibe mark draws its ring round while one of Live's own page moves loads, at the pace this browser
+// learned for them, and closes it when the route has rendered (ov-mark.js, OVMark.navStart/navEnd). A route that
+// renders without whenRouteReady closes it after the move's own turn of the event loop; none waits past 8 s.
+let _ovNavSeq = 0, _ovNavOn = 0, _ovNavWaiting = false;
+function _ovNavStart() {
+ const me = _ovNavOn = ++_ovNavSeq;
+ _ovNavWaiting = false;
+ try { window.OVMark && window.OVMark.navStart('app'); } catch { /* */ }
+ setTimeout(() => { if (_ovNavOn === me && !_ovNavWaiting) _ovNavEnd(); }, 0);
+ setTimeout(() => { if (_ovNavOn === me) _ovNavEnd(); }, 8000);
+}
+function _ovNavEnd() { if (!_ovNavOn) return; _ovNavOn = 0; _ovNavWaiting = false; try { window.OVMark && window.OVMark.navEnd('app'); } catch { /* */ } }
+
function navigate(urlPath, replace = false) {
function navigate(urlPath, replace = false) {
if (isOffSite(urlPath)) { if (replace) location.replace(urlPath); else location.href = urlPath; return; }
if (isOffSite(urlPath)) { if (replace) location.replace(urlPath); else location.href = urlPath; return; }
urlPath = sameSitePath(urlPath);
urlPath = sameSitePath(urlPath);
@@ -980,6 +993,7 @@ function navigate(urlPath, replace = false) {
@@ -980,6 +993,7 @@ function navigate(urlPath, replace = false) {
return;
return;
}
}
teardownRoute(urlPath);
teardownRoute(urlPath);
+ _ovNavStart();
// Normalize path
// Normalize path
if (!urlPath.startsWith('/')) urlPath = '/' + urlPath;
if (!urlPath.startsWith('/')) urlPath = '/' + urlPath;
@@ -1057,10 +1071,13 @@ function whenRouteReady(pageId, render) {
@@ -1057,10 +1071,13 @@ function whenRouteReady(pageId, render) {
console.error(`[route] ${path} failed to render:`, err);
console.error(`[route] ${path} failed to render:`, err);
if (window.ov) ov.showRouteError(`page-${pageId}`, err, () => whenRouteReady(pageId, render));
if (window.ov) ov.showRouteError(`page-${pageId}`, err, () => whenRouteReady(pageId, render));
}
}
+ _ovNavEnd();
};
};
if (!window.ov) return run();
if (!window.ov) return run();
+ if (_ovNavOn) _ovNavWaiting = true;
ov.route(path).then(run, (err) => {
ov.route(path).then(run, (err) => {
if (!ov.isCurrent(gen)) return;
if (!ov.isCurrent(gen)) return;
+ _ovNavEnd();
ov.showRouteError(`page-${pageId}`, err, () => whenRouteReady(pageId, render));
ov.showRouteError(`page-${pageId}`, err, () => whenRouteReady(pageId, render));
});
});
}
}
@@ -2087,7 +2104,7 @@ async function handleThumbnailError(img) {
@@ -2087,7 +2104,7 @@ async function handleThumbnailError(img) {
function thumbImg(thumbnailUrl, fallbackIcon, alt, regenerateUrl = null) {
function thumbImg(thumbnailUrl, fallbackIcon, alt, regenerateUrl = null) {
// The old brand glyph as a placeholder → the OV mark (static, muted).
// The old brand glyph as a placeholder → the OV mark (static, muted).
const iconHtml = (extra) => fallbackIcon === 'fa-circle-nodes'
const iconHtml = (extra) => fallbackIcon === 'fa-circle-nodes'
- ? `<span class="ov-mark ov-mark--ph" data-size="44" data-static="1"${extra || ''}></span>`
+ ? `<span class="ov-mark ov-mark--ph" data-size="44" data-tone="ink" data-static="1"${extra || ''}></span>`
: `<i class="fa-solid ${fallbackIcon}"${extra || ''}></i>`;
: `<i class="fa-solid ${fallbackIcon}"${extra || ''}></i>`;
if (thumbnailUrl) {
if (thumbnailUrl) {
// openvibe.media thumbnails come in sizes (Media's /t/:id?w=&fmt=): a card loads a WebP near its width.
// openvibe.media thumbnails come in sizes (Media's /t/:id?w=&fmt=): a card loads a WebP near its width.
@@ -59,7 +59,7 @@
@@ -59,7 +59,7 @@
<div class="tour-core-wrap">
<div class="tour-core-wrap">
<div class="tour-core" data-node="core">
<div class="tour-core" data-node="core">
<span class="tour-core-ring"></span><span class="tour-core-ring tour-core-ring--2"></span>
<span class="tour-core-ring"></span><span class="tour-core-ring tour-core-ring--2"></span>
- <span class="tour-core-logo"><span class="ov-mark" data-size="30" style="color:#fff"></span></span>
+ <span class="tour-core-logo"><span class="ov-mark" data-size="34" data-tone="white"></span></span>
<b>OpenVibe.Live</b>
<b>OpenVibe.Live</b>
<!-- The old feature line here ("<1s latency · chat · emotes · …") listed the same
<!-- The old feature line here ("<1s latency · chat · emotes · …") listed the same
things the chip grid below spells out properly. Two statements of the same
things the chip grid below spells out properly. Two statements of the same
@@ -22,7 +22,7 @@ const BUDGETS = {
@@ -22,7 +22,7 @@ const BUDGETS = {
htmlRawKB: 120, // measured 94.9
htmlRawKB: 120, // measured 94.9
htmlBrotliKB: 30,
htmlBrotliKB: 30,
jsFiles: 26, // measured 23 (incl. route scripts for "/")
jsFiles: 26, // measured 23 (incl. route scripts for "/")
- jsRawKB: 1240, // 1238.8 with the home's featured stream once and the intro closed on phones (2026-10-31); 1237.4 with the home's two more tab blocks on phones (2026-10-30); 1233.9 with the home's Catch up tabs on phones (2026-10-30); 1230.8 with openvibe-shared 4.53.0: the footer's columns fold on phones (2026-10-30); 1227.8 with openvibe-shared 4.52.0: the Dock's loader and its Chats tab (2026-10-30); 1223.5 with openvibe-shared 4.48.0 (the site switcher on the mark, the menu's Start tab and quick tools; Kit's touch hit areas and the phone navbar fix, 4.44-4.47.3); 1215.4 with openvibe-shared 4.43.0 (room.css carries the kit tokens, 4.39.1; the kit's 4.39.0 rules); measured 1203.9 (2026-10-28: openvibe-shared 4.30.0, the bell center: tabs with counts, the Unread filter, thumbnails, swipe, the phone sheet; 4.31.0's ✦ adds about 3 KB); 1187.2 (2026-10-28: openvibe-shared 4.27.0, Notifications 2.0: opaque themed toasts held while a menu is open, grouping, priority, System cards and the rich bell panel); 1158.8 (2026-10-28: openvibe-shared 4.25.0, the menu's orb, messages, the phone sheet and auto-hide in the navbar; the messenger opens from the bar)
+ jsRawKB: 1243, // 1242.7 with openvibe-shared 4.59.0: the Pair mark beside the name, set in the brand face, and the ring on page moves (2026-10-31); 1238.8 with the home's featured stream once and the intro closed on phones (2026-10-31); 1237.4 with the home's two more tab blocks on phones (2026-10-30); 1233.9 with the home's Catch up tabs on phones (2026-10-30); 1230.8 with openvibe-shared 4.53.0: the footer's columns fold on phones (2026-10-30); 1227.8 with openvibe-shared 4.52.0: the Dock's loader and its Chats tab (2026-10-30); 1223.5 with openvibe-shared 4.48.0 (the site switcher on the mark, the menu's Start tab and quick tools; Kit's touch hit areas and the phone navbar fix, 4.44-4.47.3); 1215.4 with openvibe-shared 4.43.0 (room.css carries the kit tokens, 4.39.1; the kit's 4.39.0 rules); measured 1203.9 (2026-10-28: openvibe-shared 4.30.0, the bell center: tabs with counts, the Unread filter, thumbnails, swipe, the phone sheet; 4.31.0's ✦ adds about 3 KB); 1187.2 (2026-10-28: openvibe-shared 4.27.0, Notifications 2.0: opaque themed toasts held while a menu is open, grouping, priority, System cards and the rich bell panel); 1158.8 (2026-10-28: openvibe-shared 4.25.0, the menu's orb, messages, the phone sheet and auto-hide in the navbar; the messenger opens from the bar)
jsBrotliKB: 292, // 291.1 with openvibe-shared 4.57.1 (the Dock's async token and scope-aware controls, 4.57.0; the tool frame's facts, 4.56.0) (2026-10-31); 290.6 with the home's two more tab blocks on phones (2026-10-30); 289.8 with the home's Catch up tabs on phones (2026-10-30); 288.2 with openvibe-shared 4.52.0: the Dock's loader and its Chats tab (2026-10-30); 287.4 with openvibe-shared 4.48.0 (the site switcher on the mark, the menu's Start tab and quick tools; Kit's touch hit areas and the phone navbar fix, 4.44-4.47.3); measured 283.2 (2026-10-28: openvibe-shared 4.30.0, the bell center as above); 279.6 (2026-10-28: openvibe-shared 4.27.0, Notifications 2.0 as above); 273.1 (2026-10-28: openvibe-shared 4.25.0 as above); 270.5 (2026-10-28: openvibe-shared 4.22.0, the navbar's search magnifier with / and Ctrl+K and the More menu; search.js and loading.js load only when used); 269.6 (2026-10-28: openvibe-shared 4.19.0, the account menu's gear and people-group icons inline; 268 on 2026-10-27: openvibe-shared 4.16.0, the folded balance chip, Across OpenVibe with site marks and the icon preload in the navbar); 265.3 (2026-10-27: openvibe-shared 4.15.0, the compact footer opens into the whole one, and the pulse line); 263.3 on 10-23 (openvibe-shared 4.9.0, status text twins in every theme); 262.5 on 10-17 (openvibe-shared 4.4.0, every site in the launcher)
jsBrotliKB: 292, // 291.1 with openvibe-shared 4.57.1 (the Dock's async token and scope-aware controls, 4.57.0; the tool frame's facts, 4.56.0) (2026-10-31); 290.6 with the home's two more tab blocks on phones (2026-10-30); 289.8 with the home's Catch up tabs on phones (2026-10-30); 288.2 with openvibe-shared 4.52.0: the Dock's loader and its Chats tab (2026-10-30); 287.4 with openvibe-shared 4.48.0 (the site switcher on the mark, the menu's Start tab and quick tools; Kit's touch hit areas and the phone navbar fix, 4.44-4.47.3); measured 283.2 (2026-10-28: openvibe-shared 4.30.0, the bell center as above); 279.6 (2026-10-28: openvibe-shared 4.27.0, Notifications 2.0 as above); 273.1 (2026-10-28: openvibe-shared 4.25.0 as above); 270.5 (2026-10-28: openvibe-shared 4.22.0, the navbar's search magnifier with / and Ctrl+K and the More menu; search.js and loading.js load only when used); 269.6 (2026-10-28: openvibe-shared 4.19.0, the account menu's gear and people-group icons inline; 268 on 2026-10-27: openvibe-shared 4.16.0, the folded balance chip, Across OpenVibe with site marks and the icon preload in the navbar); 265.3 (2026-10-27: openvibe-shared 4.15.0, the compact footer opens into the whole one, and the pulse line); 263.3 on 10-23 (openvibe-shared 4.9.0, status text twins in every theme); 262.5 on 10-17 (openvibe-shared 4.4.0, every site in the launcher)
cssRawKB: 270, // measured ~243 since the first-paint subset (style.core.css) replaced style.css (~717 before)
cssRawKB: 270, // measured ~243 since the first-paint subset (style.core.css) replaced style.css (~717 before)
cssBrotliKB: 55, // measured ~47.5 (was ~130)
cssBrotliKB: 55, // measured ~47.5 (was ~130)
@@ -595,8 +595,10 @@ console.log(`[Server] /shared: serving ${SHARED_BROWSER_FILES.length} browser fi
@@ -595,8 +595,10 @@ console.log(`[Server] /shared: serving ${SHARED_BROWSER_FILES.length} browser fi
});
});
// The share cards (og:image on every page), before the browser-file allowlist below.
// The share cards (og:image on every page), before the browser-file allowlist below.
require('./web/share-cards').register(app);
require('./web/share-cards').register(app);
- // Serve only the whitelisted browser files — don't expose the entire package
- const sharedFileSet = new Set(SHARED_BROWSER_FILES);
+ // Serve only the whitelisted browser files — don't expose the entire package — and the brand face the navbar
+ // declares beside itself (files.FONTS, Shared 4.59.0).
+ const SHARED_FONTS = sharedFiles.FONTS || [];
+ const sharedFileSet = new Set([...SHARED_BROWSER_FILES, ...SHARED_FONTS]);
app.use('/shared', (req, res, next) => {
app.use('/shared', (req, res, next) => {
const fileName = path.basename(req.path);
const fileName = path.basename(req.path);
if (!sharedFileSet.has(fileName)) {
if (!sharedFileSet.has(fileName)) {
@@ -609,7 +611,7 @@ console.log(`[Server] /shared: serving ${SHARED_BROWSER_FILES.length} browser fi
@@ -609,7 +611,7 @@ console.log(`[Server] /shared: serving ${SHARED_BROWSER_FILES.length} browser fi
const hashed = Boolean(req.query.v) && req.query.v === assets.hashOf('/shared/' + fileName);
const hashed = Boolean(req.query.v) && req.query.v === assets.hashOf('/shared/' + fileName);
res.setHeader('Cache-Control', cache.assetHeaders(req.originalUrl, { hashed }));
res.setHeader('Cache-Control', cache.assetHeaders(req.originalUrl, { hashed }));
if (hashed) res.setHeader('CDN-Cache-Control', cache.IMMUTABLE);
if (hashed) res.setHeader('CDN-Cache-Control', cache.IMMUTABLE);
- res.setHeader('Content-Type', 'application/javascript; charset=utf-8');
+ res.setHeader('Content-Type', SHARED_FONTS.includes(fileName) ? 'font/woff2' : 'application/javascript; charset=utf-8');
res.sendFile(filePath, (err) => {
res.sendFile(filePath, (err) => {
// A listed file that cannot be read is this server's fault, and passing: never a cacheable answer
// A listed file that cannot be read is this server's fault, and passing: never a cacheable answer
// (its headers above said immutable; Cloudflare kept a 404 navbar through a deploy on 2026-10-17).
// (its headers above said immutable; Cloudflare kept a 404 navbar through a deploy on 2026-10-17).
@@ -47,6 +47,7 @@ function sandbox({ loaded = 'aaaaaaaaaaaa', current = 'bbbbbbbbbbbb', stored = n
@@ -47,6 +47,7 @@ function sandbox({ loaded = 'aaaaaaaaaaaa', current = 'bbbbbbbbbbbb', stored = n
},
},
sessionStorage: { getItem: (k) => (store.has(k) ? store.get(k) : null), setItem: (k, v) => store.set(k, String(v)) },
sessionStorage: { getItem: (k) => (store.has(k) ? store.get(k) : null), setItem: (k, v) => store.set(k, String(v)) },
fetch: async (url) => { calls.push(['fetch', url]); return { ok: true, json: async () => ({ release: current }) }; },
fetch: async (url) => { calls.push(['fetch', url]); return { ok: true, json: async () => ({ release: current }) }; },
+ setTimeout: () => 0,
teardownRoute: () => calls.push(['teardown']),
teardownRoute: () => calls.push(['teardown']),
routeFromURL: () => calls.push(['route']),
routeFromURL: () => calls.push(['route']),
};
};