openvibers/openvibe.live Commits
openvibe-shared v4.64.0 (was v4.62.0) (#482)
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.62.0++- openvibe-shared: v4.64.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.62.0",++ "shared": "openvibe-shared v4.64.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.62.0",++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.64.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.62.0",-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.62.0",-- "integrity": "sha512-JlFI7rOngOwpRC3lZXRkKsOv4CM5boPJqhm7URMVXq9VMMczyf9FdOw9tn3017pzquMVYYc3fz63v1B1mhSxsw==",++ "version": "4.64.0",++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.64.0",++ "integrity": "sha512-oQwj8SpCqVzVMyeX5ayXvL0LtYi4355f1s7OB99RpxIxGU9ITYVnTJraXGWJtHor1mHCiLWeOiyR0Z5pee5apQ==","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.62.0",++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.64.0","pg": "^8.23.1","sanitize-html": "^2.17.7","sdp-transform": "^3.0.0",@@@ -39,23 +39,21 @@<link rel="apple-touch-icon" href="/assets/logo-192.png"><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-- render the default palette. theme-loader.js used to be the first thing to touch the-- theme, but it is fetched over the network and loaded with defer, so it ran after the-- page had already painted — that gap is the purple flash. This reads localStorage-- only: no network, no parse blocking, works offline and on the very first paint. -->++ <!-- The look before first paint (ov-theme-boot): MUST stay ABOVE the stylesheets. server/web/assets.js puts++ openvibe-shared's look-boot here: it paints the look this browser last painted on Live, or the one a link from++ another OpenVibe page carried, with the display settings (seasonal off, Calm, text size). theme-loader.js loads++ with defer, so without it the default palette (or an old season) showed first. localStorage only, no network. -->++ <!--ov:look-boot--><script>++ // A browser from before look-boot has only its theme (ov_theme), not yet a painted look (ov_paint): paint that once.(function () {try {-- var raw = localStorage.getItem('ov_theme');-- if (!raw) return;-- var t = JSON.parse(raw), v = t && t.variables;++ if (localStorage.getItem('ov_paint')) return;++ var t = JSON.parse(localStorage.getItem('ov_theme') || 'null'), v = t && t.variables, el = document.documentElement;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 (_) { /* cold cache or private mode — theme-loader.js resolves it shortly */ }++ for (var k in v) if (k.charAt(0) === '-' && /^[#0-9a-z(),.%\s-]{1,80}$/i.test(String(v[k])) && !/url|expression/i.test(String(v[k]))) el.style.setProperty(k, v[k]);++ if (t.id && /^[a-z0-9-]{1,40}$/.test(t.id)) el.setAttribute('data-theme', t.id);++ } catch (_) { /* nothing kept: theme-loader.js paints shortly */ }})();// "Lite" rendering for phones, coarse pointers and low-memory devices. Stylesheets on every// route key off .rs-lite, so it is decided here, before first paint, rather than by the home@@@ -22,7 +22,7 @@ const BUDGETS = {htmlRawKB: 120, // measured 94.9htmlBrotliKB: 30,jsFiles: 26, // measured 23 (incl. route scripts for "/")-- 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)++ jsRawKB: 1244, // 1243.5 with openvibe-shared 4.64.0: the look travels between sites, the Look panel in the menu (2026-10-31); 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)@@@ -38,6 +38,10 @@ const critical = require('./critical-css');const CORE_CSS = '/css/style.core.css';const REF_RE = /(["'])(\/(?:js|css|shared|fragments)\/[A-Za-z0-9_./-]+?\.(?:js|css|html))(?:\?v=[A-Za-z0-9_.-]*)?\1/g;const MANIFEST_MARK = '<!--ov:asset-manifest-->';++// The look before first paint (openvibe-shared look-boot, plan L42): this browser's last painted look on this site, or++// the one a link from another OpenVibe page carried, with the display settings (the season switch among them).++const LOOK_BOOT_MARK = '<!--ov:look-boot-->';++const { BOOT: LOOK_BOOT } = require('openvibe-shared/look-boot');const ROUTE_CSS_MARK = '<!--ov:route-css-->';const ROUTE_JS_MARK = '<!--ov:route-js-->';const FEATURES_PATH = path.join(PUBLIC_DIR, 'features.json');@@@ -240,6 +244,7 @@ function rewriteHtml(html) {const h = hashOf(urlPath);return h ? `${q}${urlPath}?v=${h}${q}` : m;});++ if (out.includes(LOOK_BOOT_MARK)) out = out.replace(LOOK_BOOT_MARK, () => `<script>${LOOK_BOOT}</script>`);if (out.includes(MANIFEST_MARK)) {const reg = features();const payload = {nnew file mode 100644@@@ -0,0 +1,24 @@++'use strict';++// The look before first paint (openvibe-shared 4.64.0 look-boot, plan L42; the owner, 10-31: seasonal turned off on++// Network was still on, and orange, on Live). theme-loader.js loads with defer here, so the document's head carries++// look-boot: the look this browser last painted on Live (ov_paint), or the one a link from another OpenVibe page just++// carried (?ov_look=), with the display settings. It sits above every stylesheet, and the marker never reaches a page.++const assert = require('assert');++const assets = require('../server/web/assets');++const { BOOT } = require('openvibe-shared/look-boot');++++const doc = assets.document('index.html').html;++const at = doc.indexOf(BOOT);++assert.ok(at > 0, 'the head carries look-boot');++assert.ok(!doc.includes('<!--ov:look-boot-->'), 'the marker is replaced');++const firstSheet = doc.search(/<link[^>]+rel="stylesheet"/);++assert.ok(firstSheet > 0 && at < firstSheet, 'it paints before any stylesheet');++assert.ok(at < doc.indexOf('/shared/theme-loader.js'), 'and before the loader');++assert.strictEqual(doc.split(BOOT).length, 2, 'once');++// A browser from before look-boot (ov_theme only) is painted once from its theme, colours only.++const legacy = doc.slice(at, firstSheet);++assert.match(legacy, /if \(localStorage\.getItem\('ov_paint'\)\) return;/);++assert.match(legacy, /!\/url\|expression\/i\.test/);++// Every route's document keeps it (renderRoute works on the same base).++assert.ok(assets.renderRoute(doc, '/@someone').includes(BOOT), 'a channel page too');++console.log('look boot: the head paints the kept or carried look before any stylesheet, once, on every 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.62.0
+- openvibe-shared: v4.64.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.62.0",
+ "shared": "openvibe-shared v4.64.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.62.0",
+ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.64.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.62.0",
- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.62.0",
- "integrity": "sha512-JlFI7rOngOwpRC3lZXRkKsOv4CM5boPJqhm7URMVXq9VMMczyf9FdOw9tn3017pzquMVYYc3fz63v1B1mhSxsw==",
+ "version": "4.64.0",
+ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.64.0",
+ "integrity": "sha512-oQwj8SpCqVzVMyeX5ayXvL0LtYi4355f1s7OB99RpxIxGU9ITYVnTJraXGWJtHor1mHCiLWeOiyR0Z5pee5apQ==",
"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.62.0",
+ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.64.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",
@@ -39,23 +39,21 @@
@@ -39,23 +39,21 @@
<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-192.png">
<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
- render the default palette. theme-loader.js used to be the first thing to touch the
- theme, but it is fetched over the network and loaded with defer, so it ran after the
- page had already painted — that gap is the purple flash. This reads localStorage
- only: no network, no parse blocking, works offline and on the very first paint. -->
+ <!-- The look before first paint (ov-theme-boot): MUST stay ABOVE the stylesheets. server/web/assets.js puts
+ openvibe-shared's look-boot here: it paints the look this browser last painted on Live, or the one a link from
+ another OpenVibe page carried, with the display settings (seasonal off, Calm, text size). theme-loader.js loads
+ with defer, so without it the default palette (or an old season) showed first. localStorage only, no network. -->
+ <!--ov:look-boot-->
<script>
<script>
+ // A browser from before look-boot has only its theme (ov_theme), not yet a painted look (ov_paint): paint that once.
(function () {
(function () {
try {
try {
- var raw = localStorage.getItem('ov_theme');
- if (!raw) return;
- var t = JSON.parse(raw), v = t && t.variables;
+ if (localStorage.getItem('ov_paint')) return;
+ var t = JSON.parse(localStorage.getItem('ov_theme') || 'null'), v = t && t.variables, el = document.documentElement;
if (!v) return;
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 (_) { /* cold cache or private mode — theme-loader.js resolves it shortly */ }
+ for (var k in v) if (k.charAt(0) === '-' && /^[#0-9a-z(),.%\s-]{1,80}$/i.test(String(v[k])) && !/url|expression/i.test(String(v[k]))) el.style.setProperty(k, v[k]);
+ if (t.id && /^[a-z0-9-]{1,40}$/.test(t.id)) el.setAttribute('data-theme', t.id);
+ } catch (_) { /* nothing kept: theme-loader.js paints shortly */ }
})();
})();
// "Lite" rendering for phones, coarse pointers and low-memory devices. Stylesheets on every
// "Lite" rendering for phones, coarse pointers and low-memory devices. Stylesheets on every
// route key off .rs-lite, so it is decided here, before first paint, rather than by the home
// route key off .rs-lite, so it is decided here, before first paint, rather than by the home
@@ -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: 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)
+ jsRawKB: 1244, // 1243.5 with openvibe-shared 4.64.0: the look travels between sites, the Look panel in the menu (2026-10-31); 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)
@@ -38,6 +38,10 @@ const critical = require('./critical-css');
@@ -38,6 +38,10 @@ const critical = require('./critical-css');
const CORE_CSS = '/css/style.core.css';
const CORE_CSS = '/css/style.core.css';
const REF_RE = /(["'])(\/(?:js|css|shared|fragments)\/[A-Za-z0-9_./-]+?\.(?:js|css|html))(?:\?v=[A-Za-z0-9_.-]*)?\1/g;
const REF_RE = /(["'])(\/(?:js|css|shared|fragments)\/[A-Za-z0-9_./-]+?\.(?:js|css|html))(?:\?v=[A-Za-z0-9_.-]*)?\1/g;
const MANIFEST_MARK = '<!--ov:asset-manifest-->';
const MANIFEST_MARK = '<!--ov:asset-manifest-->';
+// The look before first paint (openvibe-shared look-boot, plan L42): this browser's last painted look on this site, or
+// the one a link from another OpenVibe page carried, with the display settings (the season switch among them).
+const LOOK_BOOT_MARK = '<!--ov:look-boot-->';
+const { BOOT: LOOK_BOOT } = require('openvibe-shared/look-boot');
const ROUTE_CSS_MARK = '<!--ov:route-css-->';
const ROUTE_CSS_MARK = '<!--ov:route-css-->';
const ROUTE_JS_MARK = '<!--ov:route-js-->';
const ROUTE_JS_MARK = '<!--ov:route-js-->';
const FEATURES_PATH = path.join(PUBLIC_DIR, 'features.json');
const FEATURES_PATH = path.join(PUBLIC_DIR, 'features.json');
@@ -240,6 +244,7 @@ function rewriteHtml(html) {
@@ -240,6 +244,7 @@ function rewriteHtml(html) {
const h = hashOf(urlPath);
const h = hashOf(urlPath);
return h ? `${q}${urlPath}?v=${h}${q}` : m;
return h ? `${q}${urlPath}?v=${h}${q}` : m;
});
});
+ if (out.includes(LOOK_BOOT_MARK)) out = out.replace(LOOK_BOOT_MARK, () => `<script>${LOOK_BOOT}</script>`);
if (out.includes(MANIFEST_MARK)) {
if (out.includes(MANIFEST_MARK)) {
const reg = features();
const reg = features();
const payload = {
const payload = {
new file mode 100644
new file mode 100644
@@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
+'use strict';
+// The look before first paint (openvibe-shared 4.64.0 look-boot, plan L42; the owner, 10-31: seasonal turned off on
+// Network was still on, and orange, on Live). theme-loader.js loads with defer here, so the document's head carries
+// look-boot: the look this browser last painted on Live (ov_paint), or the one a link from another OpenVibe page just
+// carried (?ov_look=), with the display settings. It sits above every stylesheet, and the marker never reaches a page.
+const assert = require('assert');
+const assets = require('../server/web/assets');
+const { BOOT } = require('openvibe-shared/look-boot');
+
+const doc = assets.document('index.html').html;
+const at = doc.indexOf(BOOT);
+assert.ok(at > 0, 'the head carries look-boot');
+assert.ok(!doc.includes('<!--ov:look-boot-->'), 'the marker is replaced');
+const firstSheet = doc.search(/<link[^>]+rel="stylesheet"/);
+assert.ok(firstSheet > 0 && at < firstSheet, 'it paints before any stylesheet');
+assert.ok(at < doc.indexOf('/shared/theme-loader.js'), 'and before the loader');
+assert.strictEqual(doc.split(BOOT).length, 2, 'once');
+// A browser from before look-boot (ov_theme only) is painted once from its theme, colours only.
+const legacy = doc.slice(at, firstSheet);
+assert.match(legacy, /if \(localStorage\.getItem\('ov_paint'\)\) return;/);
+assert.match(legacy, /!\/url\|expression\/i\.test/);
+// Every route's document keeps it (renderRoute works on the same base).
+assert.ok(assets.renderRoute(doc, '/@someone').includes(BOOT), 'a channel page too');
+console.log('look boot: the head paints the kept or carried look before any stylesheet, once, on every route');