openvibers/openvibe.shared rooms.js
rooms.js
| 1 | /** |
| 2 | * openvibe-shared/rooms — OpenVibe's rooms (plan 2026-10-28 §3.1, §3.5): one table every site reads for a room's |
| 3 | * neighbourhood, its accent, its hero line and its motif, so a room looks like itself on every page that shows it. |
| 4 | * |
| 5 | * The accents sit every 25° of OKLCH hue. Each `dark` value passes AA against #0B0D12 (text, icons and fills on dark |
| 6 | * themes, with dark text on the fill); each `light` value passes AA against white (text and filled buttons on light |
| 7 | * themes, with white text). Put rooms.style(id) on the room's wrapper with the class ov-room: room.css then gives |
| 8 | * --room-accent (the right one for the theme's mode), --room-strong (text on the page) and --room-on (text on a fill). |
| 9 | * |
| 10 | * const rooms = require('openvibe-shared/rooms'); |
| 11 | * rooms.get('surf') → { id, name, host, hood, hue, dark, light, line, motif, icon } |
| 12 | * rooms.style('surf') → '--room-dark:#00BEF6;--room-light:#0072AB' |
| 13 | * rooms.HOODS → { streams: 'Streams & places', … } (the menu's neighbourhoods; Network's frame is the authority) |
| 14 | * In the browser: window.OpenVibeRooms, the same. |
| 15 | */ |
| 16 | (function (root, factory) { |
| 17 | const api = factory(); |
| 18 | if (typeof module === 'object' && module.exports) { module.exports = api; return; } |
| 19 | root.OpenVibeRooms = api; |
| 20 | })(typeof globalThis !== 'undefined' ? globalThis : this, function () { |
| 21 | ; |
| 22 | |
| 23 | const HOODS = Object.freeze({ |
| 24 | watch: 'Watch & stream', talk: 'Talk & belong', play: 'Play', read: 'Read & ask', |
| 25 | shop: 'Shop & money', tools: 'Free tools', make: 'Make with AI', build: 'For developers', |
| 26 | }); |
| 27 | |
| 28 | // id, name in menus, host, neighbourhood, OKLCH hue, dark accent, light accent, hero line (≤ 8 words), kit icon, motif |
| 29 | const ROWS = [ |
| 30 | ['fun', 'Fun', 'openvibe.fun', 'play', 350, '#F47DB9', '#A42C71', 'Something to do, alone, together, or live', 'spark', 'a city map where idea pins pop up and a quest card flips'], |
| 31 | ['shoes', 'Shoes', 'open.shoes', 'shop', 25, '#FF7E76', '#B02A2D', 'Every shoe, every market, the right price', 'shoe', 'a shoe drawn as one line, price tags from several stores sliding into one all-in price'], |
| 32 | ['tours', 'Tours', 'openvibe.tours', 'watch', 50, '#F98942', '#AA3900', 'Go anywhere: fly, stay, walk, watch', 'map', 'a plane\'s dotted arc landing on a map, then the walking route drawing itself'], |
| 33 | ['today', 'Today', 'openvibe.today', 'read', 75, '#E49900', '#994E00', 'Everything happening for you, today', 'calendar', 'the day\'s ring with events as dots and "now" sweeping; the brief\'s lines typing in'], |
| 34 | ['meme', 'Meme', 'openvibe.meme', 'play', 100, '#C3AC00', '#7B6100', 'The internet\'s meme database, rebuilt with AI', 'image', 'a family tree of memes growing branch by branch, stickers fanning out'], |
| 35 | ['domains', 'Domains', 'openvibe.domains', 'tools', 125, '#94BB3B', '#4D7100', 'Name it, price it, run it', 'globe', 'a name typing itself while extensions cycle, prices settling into a sorted list'], |
| 36 | ['casino', 'Casino', 'openvibe.casino', 'play', 150, '#51C672', '#007C25', 'Learn it, play it, never pay it', 'game', 'a card fan and chips, with a probability curve drawing beneath'], |
| 37 | ['exchange', 'Exchange', 'openvibe.exchange', 'build', 175, '#00CAA5', '#007F5E', 'Trade what people make', 'swap', 'two arrows looping an item between makers, and a passport card stamping "safe"'], |
| 38 | ['cam', 'Cam', 'openvibe.cam', 'watch', 200, '#00C7D2', '#007C89', 'Your camera, the world\'s cams, face to face', 'video', 'a shutter iris opening onto a grid of live cams, a flash, the photo flying to a gallery'], |
| 39 | ['surf', 'Surf', 'openvibe.surf', 'play', 225, '#00BEF6', '#0072AB', 'Ride maps, surf the web, surf what\'s on', 'wave', 'a first-person surf run: ramps, speed lines, the timer ticking'], |
| 40 | ['report', 'Report', 'openvibe.report', 'read', 250, '#50B0FF', '#0064BE', 'Every number on OpenVibe, honest', 'chart', 'live counters ticking, a line chart drawing itself, the after-show card sliding in'], |
| 41 | ['website', 'Website', 'openvibe.website', 'make', 275, '#8EA0FF', '#4B53C2', 'Serious sites, no login needed', 'computer', 'a browser frame assembling a real site from blocks while a cursor types the prompt'], |
| 42 | ['vision', 'Vision', 'openvibe.vision', 'read', 300, '#BB91FF', '#7444B4', 'See with the best model for the job', 'eye', 'an aperture with two models\' boxes racing on the same image, cost and time ticking'], |
| 43 | ['design', 'Design', 'openvibe.design', 'tools', 325, '#DD84E2', '#913797', 'Make it yours, find the best AI designer', 'palette', 'the theme orb: drag it and the whole page recolours live; an A/B vote flips'], |
| 44 | ]; |
| 45 | const ROOMS = Object.freeze(Object.fromEntries(ROWS.map(([id, name, host, hood, hue, dark, light, line, icon, motif]) => |
| 46 | [id, Object.freeze({ id, name, host, hood, hue, dark, light, line, icon, motif })]))); |
| 47 | const IDS = Object.freeze(ROWS.map((r) => r[0])); |
| 48 | |
| 49 | const byHost = new Map(ROWS.map((r) => [r[2], r[0]])); |
| 50 | /** A room by id or host ('surf', 'openvibe.surf', 'www.open.shoes'); null when it is not a room. */ |
| 51 | function get(key) { |
| 52 | const k = String(key || '').toLowerCase().replace(/^www\./, ''); |
| 53 | return ROOMS[k] || ROOMS[byHost.get(k)] || null; |
| 54 | } |
| 55 | /** The custom properties a room's wrapper carries (class ov-room); '' for an unknown room (the theme's accent stays). */ |
| 56 | function style(key) { |
| 57 | const r = get(key); |
| 58 | return r ? `--room-dark:${r.dark};--room-light:${r.light}` : ''; |
| 59 | } |
| 60 | |
| 61 | return { HOODS, ROOMS, IDS, get, style, VERSION: 1 }; |
| 62 | }); |
| 63 |