openvibers/openvibe.network Commits

The OpenVibe menu groups sites into the plan's six neighbourhoods (Streams & places, Games & laughs, News & answers, Make & build, Shop & swap, People & you) with For developers last; the rooms not open yet are named so they land in place when their manifests open (#382)

OP OpenVibers committed 16 days ago · ce01468503 · 3 files, +16 −17

Changes

ddiff --git a/server/frame/sites.js b/server/frame/sites.js
iindex 06637072..71dc81db 100644
---- a/server/frame/sites.js
++++ b/server/frame/sites.js
@@@ -35,19 +35,18 @@ const fullName = (s) => (/^Open[A-Z]/.test(String(s && s.name)) ? s.name : `Open
// The launcher (openvibe-shared navbar) lists every open site under one of these groups, most used first within
// each. A site missing here lands in the last group, so a new manifest is never left out of the menu.
--// Grouped by what a person came to do (the owner, 2026-10-25: "reorganize this whole menu and make it more clean and
--// clear and organized and easier to understand"): watching first (Live is the flagship), then talking, playing,
--// building with AI, everyday errands, their own account and items, and the building blocks last "For developers"
--// (plan track K). Alerts (watch) is an everyday tool; Download sits with Video and Pics; Inventory with the account,
--// so a person's items are one tap away on every site.
++// The six neighbourhoods of the 2026-10-28 plan (§3.1): each label is two words, so it never collides with a site's own
++// name, and they follow what a person came to do. Rooms not open yet (Cam, Tours, Surf, Fun, Meme, Casino, Today, Report,
++// Vision, Website, Design, Domains, open.shoes, Exchange) are named here so they land in their neighbourhood the day
++// their manifest opens. The building blocks stay last, "For developers" (the tail of Make & build).
const GROUPS = [
-- { id: 'watch', name: 'Watch & stream', sites: ['live', 'media-hub', 'stream', 'pics', 'download', 'tips', 'vip'] },
-- { id: 'talk', name: 'Chat & community', sites: ['chat', 'community', 'blog', 'news', 'wiki'] },
-- { id: 'play', name: 'Games', sites: ['games', 'quest'] },
-- { id: 'make', name: 'Build with AI', sites: ['codes', 'actor', 'space', 'tools', 'bot'] },
-- { id: 'everyday', name: 'Everyday', sites: ['deals', 'coupons', 'reviews', 'work', 'rent', 'homes', 'food', 'help', 'trade', 'watch', 'search', 'host'] },
-- { id: 'you', name: 'Your account', sites: ['network', 'inventory'] },
-- { id: 'build', name: 'For developers', sites: ['services', 'ai', 'run', 'zone', 'events', 'media', 'play'] },
++ { id: 'streams', name: 'Streams & places', sites: ['live', 'media-hub', 'stream', 'pics', 'download', 'cam', 'tours'] },
++ { id: 'games', name: 'Games & laughs', sites: ['games', 'surf', 'fun', 'meme', 'casino', 'quest'] },
++ { id: 'answers', name: 'News & answers', sites: ['today', 'report', 'news', 'search', 'wiki', 'blog', 'reviews', 'vision'] },
++ { id: 'make', name: 'Make & build', sites: ['website', 'design', 'domains', 'codes', 'space', 'tools', 'host', 'actor', 'bot'] },
++ { id: 'shop', name: 'Shop & swap', sites: ['deals', 'coupons', 'shoes', 'exchange', 'rent', 'homes', 'work', 'food', 'trade'] },
++ { id: 'people', name: 'People & you', sites: ['chat', 'community', 'tips', 'vip', 'help', 'network', 'inventory'] },
++ { id: 'build', name: 'For developers', sites: ['services', 'ai', 'run', 'zone', 'events', 'media', 'watch', 'play'] },
];
// What each site is, in a few words, for the menus (the launcher's rows are two to a line on a phone: about 22
// characters fit). The manifests' taglines stay the sites' own sentences everywhere else; a site missing here shows
ddiff --git a/test/frame.test.js b/test/frame.test.js
iindex 65886f44..a45cdb32 100644
---- a/test/frame.test.js
++++ b/test/frame.test.js
@@@ -17,16 +17,16 @@ let p = svc.payloadFor('openvibe.media');
assert.deepEqual(p.nav.filter(n => !n.of).map(n => n.id), ['live', 'tools', 'space', 'community', 'games', 'media', 'network', 'chat', 'services', 'blog', 'wiki', 'news', 'reviews', 'tips', 'vip', 'trade', 'host', 'deals', 'coupons', 'stream', 'media-hub', 'bot', 'codes', 'actor', 'food', 'help', 'work', 'quest', 'rent', 'watch', 'inventory', 'events', 'ai', 'search', 'run', 'play', 'zone'], 'cold start follows the base order');
// The launcher: every open site in one of the groups, and the products other services serve on their own domains
// right after their site (Pics and Download after Video, Homes after Rent).
--assert.deepStrictEqual(p.groups.map(g => g.name), ['Watch & stream', 'Chat & community', 'Games', 'Build with AI', 'Everyday', 'Your account', 'For developers'], 'by what a person came to do, the building blocks last (the owner, 2026-10-25)');
++assert.deepStrictEqual(p.groups.map(g => g.name), ['Streams & places', 'Games & laughs', 'News & answers', 'Make & build', 'Shop & swap', 'People & you', 'For developers'], 'the six neighbourhoods (plan 2026-10-28 §3.1), the building blocks last');
assert.strictEqual(p.groups.find(g => g.id === 'build').name, 'For developers');
assert.ok(p.nav.every(n => p.groups.some(g => g.id === n.group)), 'every entry has a group');
assert.deepStrictEqual(p.nav.filter(n => n.of).map(n => [n.id, n.of, n.url]), [['pics', 'media-hub', 'https://openvibe.pics/'], ['download', 'media-hub', 'https://openvibe.download/'], ['homes', 'rent', 'https://openvibe.homes/']]);
const at = (id) => p.nav.findIndex(n => n.id === id);
assert.ok(at('pics') === at('media-hub') + 1 && at('homes') === at('rent') + 1, 'a product follows its site');
--assert.deepStrictEqual([p.nav[at('media-hub')].icon, p.nav[at('media-hub')].group, p.nav[at('homes')].group, p.nav[at('tools')].group], ['video', 'watch', 'everyday', 'make'], 'Video draws the video icon (there is no media-hub icon)');
++assert.deepStrictEqual([p.nav[at('media-hub')].icon, p.nav[at('media-hub')].group, p.nav[at('homes')].group, p.nav[at('tools')].group], ['video', 'streams', 'shop', 'make'], 'Video draws the video icon (there is no media-hub icon)');
assert.deepStrictEqual(['actor', 'bot', 'run', 'zone'].map((id) => p.nav[at(id)].group), ['make', 'make', 'build', 'build'], 'agents and robots for people, compute and storage for developers');
--// Games together, items with the account, Alerts as an everyday tool, files beside Video (each when its site is open).
--[['games', 'play'], ['quest', 'play'], ['inventory', 'you'], ['watch', 'everyday'], ['download', 'watch']]
++// Games together, items with the account, Alerts with the building blocks, files beside Video (each when its site is open).
++[['games', 'games'], ['quest', 'games'], ['inventory', 'people'], ['watch', 'build'], ['download', 'streams'], ['search', 'answers'], ['chat', 'people']]
.filter(([id]) => at(id) >= 0).forEach(([id, group]) => assert.strictEqual(p.nav[at(id)].group, group, `${id} is in ${group}`));
assert.strictEqual(p.nav.length, 40);
assert.deepStrictEqual([p.nav[at('stream')].name, p.nav[at('pics')].name], ['Restream', 'Pics'], 'OpenRestream is "Restream" among the menu\'s short names (owner, 2026-10-28)');
ddiff --git a/test/home-front-door.test.js b/test/home-front-door.test.js
iindex ab13572d..04cc3c4a 100644
---- a/test/home-front-door.test.js
++++ b/test/home-front-door.test.js
@@@ -112,7 +112,7 @@ assert.ok(faqLd.mainEntity.length >= 5, 'the FAQ has its questions');
faqLd.mainEntity.forEach((q) => assert.ok(html.includes(`<h3>${q.name.replace(/'/g, '&#39;')}</h3>`), `the FAQ shows "${q.name}"`));
assert.ok(faqLd.mainEntity.some((q) => /separate account/.test(q.name)), "Contracts' network FAQ is included");
// The service map groups the sites the way the launcher does; numbers say only what was read.
--assert.ok(/<h3 class="home-group">Watch &amp; stream<\/h3>/.test(html) && /<h3 class="home-group">For developers<\/h3>/.test(html) && /<h3 class="home-group">Build with AI<\/h3>/.test(html), 'the sites are grouped');
++assert.ok(/<h3 class="home-group">Streams &amp; places<\/h3>/.test(html) && /<h3 class="home-group">For developers<\/h3>/.test(html) && /<h3 class="home-group">Make &amp; build<\/h3>/.test(html), 'the sites are grouped');
assert.ok(/<section class="net-num"/.test(html) && /sites, one account/.test(html), 'the numbers panel renders');
assert.ok(!/services up/.test(html) && !/accounts<\/span>/.test(html), 'numbers nobody read are left out');
assert.ok(!/Latest recordings|New jobs|Fresh coupon codes/.test(html), 'an empty column is left out');