# Changelog ## 4.242.0 — 2026-11-13 **One agent you can watch work, cards that act, and a + that blooms** (the owner, 11-13: "it needs to use a universal agent system … your actor is just your agent"; "this doesn't work … typing test … nothing happens … not seamless and sleek"; "why don't the avatars show up properly"; "I don't really like the plus … reanalyze and make it a better one … way more animated, better effects"). - **The run thread (ov-run.js).** Quiet tool steps fold into one line ("Ran 6 steps", open to see each). Words you send while it works wait as queued messages (Send now, or they go when the turn ends). The list counts what is working now. - **Your agents in the menu (search.js, dock.js).** The stack and You's agent card read through Network's Frame (`/api/frame/actor`, `/api/frame/actor/faces`). Your agents at work show with their faces among the active rows; a tap opens their tasks. - **Faces that fail to load show the initial** (the feed, the chat list, the Dock), never an empty circle. - **The user card acts (ov-user.js).** It reads with the viewer's token (`options.token`, else the bar's new `OpenVibeNavbar.viewerToken()`) and draws the actions Network computed for that viewer: Message, Follow, Add friend, Tip, Watch together, Mute, Block, Report and staff tools. An action calls Network, then the card reads itself again (plan §Y.1 A2). - **An empty table is the designed empty card** (kit.js `table(…, { empty })`, rule 141; plan §Y.1 A10). - **The composer's + is its own mark (ov-composer.js).** - At rest: a bold rounded plus in a softly lit disc (nothing moves). - Under the pointer, or focused: the arms reach and four petals peek from the diagonals (the tiles it holds). - Pressed: it sinks. - Open: it springs a turn and a half of a quarter into an ×; the disc fills with the accent, rings once, and the petals burst outward in the disc's white. - Calm keeps all of it, slower, a third as far, with no overshoot. Off stills it. ## 4.241.0 — 2026-11-13 **The composer's + is what you can add, and the feed reads like posts by people** (the owner, 11-13: "the plus button on the composer … camera, photos, files … our own custom style … a modular system … it can still open this choose an action … share … each site can choose … highly configurable"; on openvibe.community's feed: "add icons to those [tags] and make those buttons nicer … make it more like a social media … it should say who posted it … their level … their username effects … update the listings for deals … way better on mobile, but also great on desktop"). - **The + (ov-composer.js).** - Big tiles for what you add: Camera (the shared capture core), Photos (pictures and videos), Files (any file; on Android the system's Choose an action). Then rows: Paste (a picture or words you copied), Screenshot (a screen, window or tab; desktop), Camera app (the phone's own camera), Share to an app (what you wrote, with its files), Timer, GitHub, a site's own tools, and what a narrow row hides. Each row says what it does in a second line. - A phone gets a sheet from the bottom (the top layer: no panel clips it; swipe it down, tap outside, or the ×); a wide screen a panel under the row with the rows in columns. Tiles rise in turn; a press sinks them. - What the + holds as a tile is not also a button in the row (rule: never twice); a file tool's input stays in the form so the files still go with it. - Configurable: `mount(host, { plus: { tiles, rows, only } })`, a form's `data-ovc-plus`, the site's `OpenVibeComposer.configure({ plus, tools })`; a tool says where it fits with `sub`, `tile`, `accept`, `capture` and `when(env)` (env: files, anyFile, touch, camera, screen, share, clip). `noPlus` leaves the + out. - **The feed (ov-home.js).** - Each chip has its glyph (For you, Following, Live, Videos, Clips, Pics, Posts, Rundown, Memes, Games, Chat, Events, Jobs, Deals, Stats, Wiki, Quests, Updates); the chosen one is tinted, not a white block. - A person's card names them: their face, their name wearing its effect (`actor.fx`, drawn by items.css; Inventory by `subject` where the page has items.js), their level badge, @handle, the site and when (feed.item@1 1.1.0, Contracts 0.425.0). "System" is nobody: a site's own card is the site's name and what it is, never "Community · Community". - A post, a picture, a clip, a video, a meme or the Rundown is its card and, under it (outside its link), Comment with the count, likes, and Share (the phone's share sheet, or the link copied). - A run of deals is a listing: each with its picture (or a tag), its price, the old price struck through with the saving, and the store; two columns on a wide screen; "See all 37 deals". - Tests: `composer-plus-chrome` (new: tiles and rows, the sheet and the panel, per box and per site, a site's tool, picked files in the box); `composer-v2-chrome`, `dock-chrome` and `menu-feed-v2-chrome` follow the new markup. ## 4.240.0 — 2026-11-13 **One agent in the menu's Vibe, and a menu button drawn from the menu** (the owner, 11-13: "all this separation of tasks and codes and chats … we shouldn't even have that. It's just like filters … your actor is just your agent … it can orchestrate to openvibe.codes, or timer, task, desktop, browser"; "I tried typing test in and just like nothing happens … not seamless and sleek"; "regenerate this icon … based on what the menu actually looks like and what the menu has to offer … good animations and effects … highlight differently and glow"). - **The menu's Vibe is one agent (ov-run.js, search.js).** - Your agent heads the list (`o.agent`): its face with a state dot (ready, working, asks you, paused), its name, what it is doing and today's spend, and Pause or Resume. A tap shows its work. It reads the Frame's `/actor`. - All · Chats · Tasks · Code are filter chips over one list, never modes: the Dock's Chat, Agents and Code panels and its Actor card are no longer lent into the menu (only Now and the live view of an agent at work, the Dock's new `part: 'live'`). - One box starts everything ("Ask, or say what to do"); the Frame places the words (Network #911: Codes for a change to code, your computer for "on my computer", Vibe for the rest). The thread opens at once with your words and your agent typing until it answers; a run your agent handed on says where it went ("Sent to Codes"). A start that fails goes back to the list with the words in the box and why. - Now (timers, what is on) shows above the list on every filter; Ask your agent (`[data-ov-ask]`, the Dock's `ask()`) puts the words in the one box, unsent; words put in the box before the shared composer loads carry over. - **The menu button (navbar.js)** is the menu, small: the ask bar you lead (your face, the words, Vibe's spark) over the place tabs, one lit. Now and then the light walks across the tabs; under the pointer the tabs lift and light, the spark turns and the mark glows; while an agent works the spark turns slowly (`.is-working`); open, the bar and the tabs fold into the ×. Calm and Off keep it still. Class names are M57's, so callers and tests are unchanged. - Tests: `run-thread-chrome` (a new run opens with your words and the typing), `dock-chrome` (the menu's Vibe is one list with your agent; Tasks is a filter; the live view above it). ## 4.239.0 — 2026-11-13 **One floating action, a composer that fits its column, a close button with depth** (the owner, 11-13: "this button is buggy … it disappears when you scroll … it should just use a floating button that actually moves its position … it's one button, it's not jumping around, it's transitioning"; "this camera button will flash in and out"; "improve composer … better responsive support and size on mobile to fit better"; "make the close button look slightly 3D and … glowing … make it look kind of cool"). - **`OVFloat.action(el, opts)` (ov-float.js), the floating action.** One element with a home in the page: while its home is on screen it sits there; when the home scrolls away (before the person reaches it, after they pass it, or either: `side`), the same element glides to the dock at the bottom of the window, above the bars (`[data-ov-bottom-bar]`, the app bar), the keyboard and a footer that has come up, and back when its home returns. Never a copy and never hidden: its home keeps the space, the move is a transform (FLIP; from far away it rises from just past the edge), Calm shortens it and Off places it at once. `when()` keeps it home (e.g. only phones float it); `maxWidth`, `stretch`, `gap`, `above`, `avoid`; `ov:fab` and `data-ov-fab="floating|home"` say where it is; `check()` and `destroy()`; `OVFloat.actions()` lists them. Live's Go live adopts it next, replacing its copied dock. - **The composer fits its column (ov-composer.js).** - A box narrower than its words says their short form ("Message…", or the site's `data-ovc-short`) and the long one again when there is room; a site that changes its words later is followed. Words never wrap or clip. - Under 340 px the chat preset's tools tighten into quiet 36 px discs; under 240 px they go under the words. - **The close orb (search.js)** is a lit sphere: a highlight up and to the left, a shade under it, an accent rim, a soft glow, a white ×; a sheen sweeps across once as the menu opens; hover brightens the glow; a press sinks it. Nothing moves at rest. - Tests: `float-action-chrome` (one element floats and comes home, above the bar and the footer, `when()`, `ov:fab`, `destroy()`). ## 4.238.0 — 2026-11-13 **The menu's top is a composer, you lead it, no text arrows anywhere, a ringing bell, You gets the height** (the owner's phone, 11-13: "redesign the whole entire top to be our agentic search … uses our composer", "move the actor thing so that it's at the top", "merge … this little online thing … the colors and other settings … shouldn't be taking up any space", "the close button can't be white", "get rid of every single instance of this right or left arrow", "regenerate the bell icon like that's ringing", "hide the label of the inactive tabs", "add the badges back", "the icons are so small", "take up the full height properly"). - **The top (search.js).** - The pill is a composer: voice and attach inside it while it is empty, **Ask Vibe** (a send disc) once there are words; Ctrl/⌘+Enter asks Vibe whatever the list shows. A question becomes a Vibe run in the menu; an attached file goes into Vibe's box. - **You lead the pill:** your picture and the online dot. - **What runs for you is stacked behind your picture** ("when you have actors or tasks running … sessions, conversations, anything, there should be stacked … your agents … behind you, and … status indicator"): your Actor while it works or asks, and every run that is going or waits for you; what waits for you first; two faces on a phone and three on a computer, then a count. Each face has its picture, or its kind's glyph on its own hue, and its state on a ring (a comet while it works, amber while it waits for you). They fan out from behind you as the menu opens. Nothing is drawn on your own picture but the online dot (the arc on it read as a stray line). - A tap on your picture floats **your sheet** over the menu: your row with Display and your account's menu, your Actor's card, then **Running for you** (each run, its state, a tap opens it in Vibe); its parts rise in one after the other. A tap elsewhere, Escape or your picture again folds it. You's own row and Actor strip are gone, so You starts at its tabs. - On a phone the pill says "Search or ask Vibe" (the site's name is its tab). - **The close orb** sits beside the pill (not over it), 48 px, an accent disc with a 26 px x; it spins in and turns on hover and press. The white ring was the browser's own focus outline: focus is now an accent ring, for keys only. - The place tabs are shorter on a phone (54 px), their glyphs 30 px over the word (24 px beside it on a computer). - The list fills the menu's height. - **You (ov-home.js).** - Tabs: the chosen tab is lit and widens to show its name; the others are their glyphs (27 px); switching, the last one folds as the new one opens. The count sits on the bell's corner; the bell rings once when something is new. The row is shorter (42 px) and closer to the top. - All and Edit: 44 px with 26 px glyphs. Every app's name (yours too) is 13.5 px, 800; your apps' glyphs fill more of their tiles. - `OpenVibeHome.youCard(box, o)` draws your sheet; `actorCard(box, o)` your Actor's card. - **Notifications (notification-ui.js).** The ringing bell for the empty state (it swings once, its waves fade in; Calm shortens it, Off stills it), centred; search and Unread are 44 px circles with centred glyphs; the foot's buttons are 44 px with drawn glyphs; in the menu the foot sits at the bottom. - **The bell** is redrawn everywhere (kit, glyphs, Dock, notifications, You), sized and centred to the set (19 of 24 units), and **`bell-ring`** joins the registry; the glyph fonts and the ink fixture are rebuilt. - **No text arrows.** Every →, ↗, ‹, ›, ↑, ↓, ↩ shown to a person is a drawn glyph now (agent-session, agent-sheet, action-center, ov-float, ov-home, ov-look, ov-metrics, search, shipped, showcase, thread, user-card) or words (navbar, url-resolver, components, ov-composer, ov-capture). `test/no-text-arrows.test.js` reads every module's strings with a tokenizer and fails on one. - **Code is two ways** (dock-code.js): **Make or change** (something new or a project of yours, named in your words; Codes works out which: `mode: 'make'`, Codes #448) and **OpenVibe**. No repository field. - **Vibe's list** (ov-run.js): tighter rows. **Your Actor** (dock-actor.js): its recent steps are a clock button. - Tests: `menu-home-screen-chrome` (you lead the pill with your Actor's state; your sheet; the composer's tools; only the chosen tab is named; glyphs ≥ 24 px), `no-text-arrows`, `search-site-name-chrome`, `showcase`, `dock-code-chrome`, `dock-actor-chrome`; budgets: notification-ui 27.1 KB, action-center 8.2 KB (dated notes). ## 4.237.0 — 2026-11-13 **You is one slim row, your site's own are apps, and the menu's badges and the composer's row line up** (the owner's phone, 11-13: "completely redesign this card … the buttons are below", "it can be … an app … for admin, mod rank", "the red dot … next to the word feed", "improve … match" the badges, the composer's row "offset"). - **You (ov-home.js).** - Your card is one slim row: your picture with its online dot, your name and handle, Display, and your account's menu (a chevron). - The menu is anchored in the top layer (OVSurfaces.anchor) and holds Your profile, Account and settings, Add or switch account and Sign out. The button that opens it closes it; Escape and a press elsewhere do too. - What the site gives you (your channel, Admin, moderation: `me.own`) are apps at the start of the Apps tab, by rank, each with a tooltip; they are no longer buttons in the card. They are their own row (`.ovh-own-apps`), never part of the grid you arrange. - **The menu's tabs (search.js).** - Feed's live dot sits after the word and breathes. - Counts (Feed's new, You's unread) ride on the icon's corner instead of a third line under the label. - Every count in the menu (the tabs' and You's Notifications tab) is one badge: an 18 px pill, a ring of the ground, a soft shadow, and a pop-in. - **The composer's row.** - Every tool is the same quiet 40 px disc, so the first one lines up with the words above it. - An open + (or a pressed tool) is that disc tinted with a ring, not the only solid shape in the row. - Tests: `menu-home-screen-chrome` (the slim row, the account menu, own apps; `OV_CAPTURE_YOU` saves the open menu), `menu-places-chrome` and `navbar-ask-vibe` updated. ## 4.236.0 — 2026-11-13 **You is yours on every site, the wait is the logo, and the box says what a message answers** (the owner's phone, 11-13: "what happened to all the tabs … bring all that back", "what happened to the user avatar", "completely redesign this area", "in edit mode … you can't scroll up", "improve the O so it actually looks like the original", "improve the send button", "a replying to area or different content above"). - **You, on a site with its own session (Run's).** The menu knew the person but had no token for the network's reads, so You lost its tabs (Apps, Notifications, Recent) and the You tab its picture. Both follow the person now (`known(o)` in ov-home.js, `me` in search.js's tabs). Without a token, Notifications links to the person's account. - **Your card, redesigned.** - Your name and the gear on one line. - Under it, one row of actions across the whole card in equal columns: this site's own (Channel, Admin), Display, Switch, Sign out. Each is its glyph with its name under it and a tooltip; the row starts at the card's edge (it was indented 52 px). - Sign out's red only under a pointer; the gear turns under one. - **You's tabs look like tabs.** - Apps, Alerts (Notifications) and History are one segmented track, each with its glyph and name; the chosen one is lit. - All apps and Edit are two glyph buttons at the end: All with its count on its corner, and Edit a pencil that turns into the check, filled with the accent, while you arrange. That check is the one Done; the row is sticky, so it is always in reach. - **Editing your home on a phone.** A quick swipe up or down scrolls the menu. A hold of a fifth of a second, or a sideways move, takes the app (it lifts); only then does the page hold still. - **The menu's tabs nudge.** This site's tab rolls its glyph and name through the other places in its section, a beat each, and back to its own: a little after the menu opens, then every 40 s while it is open and idle. Calm rolls once per opening and Off never. Its accessible name stays its own; a press stops it. - **The wait (ov-mark busy).** The O stays the logo's ring at its full weight, a faint track, with a bright arc running round it that grows as it goes and draws in behind. The V lifts 2.5 units in time (it bobbed 6, off the O's line) and the glow breathes, one 1.25 s rhythm. It replaces eight thinner dots that sat inside the ring's line. - **The composer.** - `bar({ icon, title, detail, kind, onClose })` puts any context above the words, inside the box, as reply and edit do: a quote, or a file being answered. - Bars carry a rail of the accent (editing in its own colour) and come in with a short rise. - Send with nothing to send is a quiet outline round its arrow (it was a grey disc). With something to send it fills with the accent on a spring, and the arrow lifts under a pointer and on a press. - Tests: `composer-bar-send` (new), `ov-mark` (the arc), `menu-home-screen-chrome` (the card in one aligned row with names and tooltips; `OV_CAPTURE_YOU=` saves You and Edit at 390 px). ## 4.235.0 — 2026-11-13 **The layers: what floats folds into a small handle and grows to the window, and what opens from a button is anchored to it** (the owner's phone, watching a live stream, 11-13: "a small button that lets you pop it in and out", "doesn't allow it to be off screen", "I can't even resize it bigger", "the little three dots doesn't actually open a menu"). - **ov-float.js, tucked.** - Thrown past a side (or T, or a tuck button), a box folds into a small handle at that edge: 30 × 64 px, 34 × 72 to a finger, set with `--ov-float-tab-w/-h`. It used to leave a strip as tall as itself hanging off the screen. - The fold is a clip animated with the Web Animations API, so nothing inside is squeezed, while the landing's spring moves it to the side. - The handle is a button that moves: a tap opens it, a drag up or down slides it along its side, and a pull sideways brings it out under the finger. - Tucked by hand, it opens again where it was (`ux`, kept in this browser only). - **ov-float.js, size.** - It grows to the whole width of the window: `MAX_W` is 1 (was 0.60). - Past what a docked frame holds (its width, or 85% of its height), a pinch, the corner or + lifts it over the page where it is, and it keeps growing, up to 92% of the window's height. - A double tap on a phone makes it the screen's width. - New `f.sizeTo(px)`. - **ov-float.js, the place.** - This browser's place wins. The account's (`/api/me/layout`) fills a device that has none, so a phone and a desktop each keep their own. - The account and `onChange` get only the account's fields (`placeOf`), never the browser's extras. - A turn of the phone, the keyboard (the visual viewport), the address bar or a resize puts it back inside, once a frame. - While it moves, nothing in it is blurred: a backdrop blur repainted every frame made a phone's drag stutter. - **surfaces.js, `OVSurfaces.anchor(el, trigger, { place, gap, margin, sheet, animate })`.** - The element goes in the top layer (the Popover API; fixed without it). No `overflow: hidden`, mask or stacking context clips it. - It is placed beside its button: `place` is side-align. It flips to the side with room, shifts to stay inside the visual viewport, and is kept no taller than its side's room. - It is placed again on scroll, resize and size changes, and released when its button leaves the page. - `sheet: 'phone'` makes it a bottom sheet under 560 px. - `data-ov-side` says where it went, and the default entrance grows from the button. - `OVSurfaces.popover({ …, pop, place, sheet })` anchors its menu while it is open. - **kit-web.js.** Every `details.ovk-more` menu is anchored, not only those inside a rail: a phone's clipped layout, a sheet or a rail no longer hides it. - Tests: `ov-float-chrome` (the handle's size and place, a slide, a pull, growing past the frame, a phone's double tap, this device's place, the account's fields) and `surfaces-chrome` (a clipped menu at a phone's bottom opens above, on top, inside the screen, and is released; `placeBox`). ## 4.234.0 — 2026-11-13 **The bottom bar hides all the way, and the composer stops repeating itself** (the owner's phone screenshots, 11-13). - **The bottom bar (`appbar.js`).** It stepped aside for a keyboard or an open panel with `translateY(110%)` while its lift above the visible viewport still applied, so above a keyboard, or with Android's toolbar gap, it stopped half on the screen. A hidden bar now drops the lift, sits fully below the screen, and is invisible and not clickable until it comes back. - **The + sheet.** It no longer repeats a tool the row already shows; the emoji button and an "Emoji" tile side by side were the same thing twice. The sheet holds what a narrow row hides, and the extras (Timer, GitHub). - **The GitHub picker:** - each row's mark is its owner's initial on a colour of the name; GitHub's own pictures were blocked by most sites' image policy, so every row showed a broken picture, and each one asked GitHub; - the same words are answered from the page's cache for ten minutes; - a new search cancels the one still running; - it waits a third of a second after the last key; - the list scrolls inside its panel and no longer runs over the box. - Tests `composer-v2-chrome` (nothing repeated, the initial, the cache) and `navbar-appbar` (hidden is all the way). ## 4.233.0 — 2026-11-13 **`ov-metrics.js` on a phone, and prices under a dollar.** - **A narrow table is cards** (`OVMetrics.table`): - in a box under 520 px wide (a container query, so a side column counts too), each row is a card: its name on top and each value under its label; - the column heads become a row of sort buttons, and the one in use is outlined; - nothing scrolls sideways; - the table, its rows, cells and heads carry their roles, so a screen reader still reads a table whatever the display. - **`format.usd` keeps two significant digits under a dollar**: $0.0118 is `$0.012`, not `$0.01`; $0.25 stays `$0.25`. A per-call price no longer rounds away. - Test `ov-metrics-chrome`: the card form at 390 px, the labels, the roles, no sideways scroll, and the new prices. ## 4.232.0 — 2026-11-12 **`ov-metrics.js`: the network's one way to show numbers** (ai-metrics.md). Report, Exchange, Compare and the admin panel draw their AI and usage numbers with it, and nobody draws a chart of their own. The look is the theme's (tokens only). Every piece works at 390 px and in both themes, and stays still with motion off. - `OVMetrics.tiles()`: label, value, unit, a delta that knows whether up is good, a sub-line and a trend. - `.spark()`: a trend line with its last point. - `.bars()`: a ranked bar list. - `.percentiles()`: p50, p90 and p95 on one scale, with a spoken summary. - `.split()`: one bar in parts, with a legend. - `.table()`: sortable on a click, with `aria-sort`, numeric columns and an optional in-cell bar. - `OVMetrics.format`: the same words everywhere, and servers get them from `require('openvibe-shared/ov-metrics')`: - `ms` (540 ms · 1.3 s · 1 min 38 s), `usd` ($0.0042 · $61.20), `count` (18k · 9.1M), `tokens`, `rate` (99.4%); - `tps` (86.0 tok/s), `bytes`, `delta` (+12%); - unknown is a dash, never 0. - Test `ov-metrics-chrome`. ## 4.231.0 — 2026-11-12 **OpenVibe's own icons, and no Font Awesome drawing left** (the owner, 11-12: "make sure no remnants of font awesome or other libraries are still being used rather than our openvibe.design systems"). - **The ring icons' solids are the glyphs' own.** Nine product icons (Network, Live, Tools, Media, Games, Community, Chat, Domains, Bench) drew Font Awesome outlines as their solid twin. Each is now the solid drawing of the glyph that stands for it, on the same 24-unit grid as the line drawings. Exchange keeps its line drawing until `swap` has a solid. `scripts/build-navbar-icons.js` writes them from `glyphs.js` and refuses any drawing that is not a glyph. - **The generator that read Font Awesome's font is gone** (`scripts/build-nav-icons.py`; `npm run build:icons` is `build-navbar-icons.js`). The bar's dead 512-grid path in `navbar.js` went with it. - **OpenVibe's own markup:** - `` names any glyph and `` any logo, drawn by `ov-glyphs.js`; - classes `ovg-xs` … `ovg-3x`, `ovg-fw`, `ovg-rotate-*`, `ovg-flip-h`/`-v` and `ovg-fill` (what `fa-solid` did); - `OVGlyphs.icon()`, `.html()` and `.has()` in a page, and `glyphs.markup()` on a server; - the drop-in now carries every glyph (287), and the navbar loads it for this markup too. - **The bar draws glyph names:** a name the bar's set lacks is drawn as ``, never as Font Awesome. - **`scripts/fa-to-ov.js`** rewrites a repository's static Font Awesome markup into `data-ov-icon` / `data-ov-brand`. It keeps each attribute's own quote, and running it twice changes nothing. It lists what a person has to decide (names built at run time, JS class strings, CSS rules, animations, unknown names). `glyphs.fromFaClasses()` is its mapping. - **Names that drew nothing now draw their glyph:** `arrow-rotate-left`, `chart-pie`, `book-skull`, `crosshairs`, `location-crosshairs`, `satellite`, `globe-americas`, `street-view`, `magnifying-glass-location`, `apple-whole`, `backpack`, `shield-heart`, `openstreetmap`; and the logos `reddit-alien` and `kickstarter-k`. - Test `fa-to-ov`. ## 4.230.0 — 2026-11-12 - **OpenVibe's own controls on every site** (the owner, 11-12: "improve the selection boxes to use a more customized look integrated into openvibe.design and themed better with animations and effects for all inputs and buttons"). `ov-forms.css` now draws every checkbox and radio: a rounded box whose check pops in, and a ring whose dot grows. The mark is the box's own `::before` (a clip-path check, scaled), so no picture is fetched. Both lift their border on hover, squeeze on a press and glow with focus; the mixed state is a bar; disabled is faded. A switch (`role="switch"`) glows when on, its knob squeezes when pressed, and it has a focus ring. Buttons answer a press, and text fields, text areas and selects glow in the accent with focus. Everything is `:where()`, so a site's own rule wins; `data-ov-native` keeps the browser's control; motion follows the person (Calm slower, Off moves nothing). - The bar loads `ov-forms.css` on any page with a text field, a text area or a button. The select kit's script still waits for a select, a box or a file input. ## 4.229.0 — 2026-11-12 - **Back brings you back to the menu** (the owner, 11-12: "fix the history back button so it properly brings you back to this GUI rather than the page behind it"). Leaving through a link in the menu marks where it was on its history entry (its place, its door, its scroll); Back to that page opens the menu again there, whether the page comes back from the browser's cache, loads again, or a site swaps it in place (Boost). It reuses that entry, so Forward still works, and closing it then leaves the page as it was. Only for a Back or Forward within half an hour. - **Links are on their way before the click**: anywhere on the page (the bar, the menu, a footer, a card), a finger landing on or a pointer resting on a link to another OpenVibe site opens its connection at once; this site's pages were already prefetched by the bar's speculation rules. - **All apps has one search** (the owner, 11-12: "confusing"): no second box under the menu's pill. The pill reads "Find among 64 apps" and filters the apps in place; the view's head is its name, its count and a hint, coming in with the view. Back on Home, the pill searches OpenVibe again. - **The close x has no white ring**: the ring that leaves it as the menu opens is invisible at rest, so where animations are off (a phone's "Remove animations") it no longer stays as a white circle. - **The Feed never shows a card twice**: a card id already on the list is skipped (Network names a Deals burst once, as of its #887). - **Feed cards with no person wear their site's app icon** (design rule 142), 40 px beside 40 px faces, the glyph filling the square (the owner, 11-12: "icons to increase size"). - **Any button can open a place in the menu** (the owner, 11-12: "other tools and buttons can open specific areas of the menu"). A menu address is a place, or place/part: `you/notifications`, `you/apps` (All apps), `you/recent`, `feed`, `here/live`, or a door (`vibe`, `chats`, `agent`, `code`, `tasks`). Any element with `data-ov-menu="you/notifications"` opens it on a click, on any page with the bar; a link with an address still opens elsewhere with a modifier key. A page address ending `#ov-menu=you/notifications` opens it as the page loads (on any OpenVibe site), and a same-page link to it works too; the hash leaves the address. `OpenVibeNavbar.openMenu(address)` and `OpenVibeNavbar.menuAddress(address)` take the same addresses; OpenVibeHome's `show('drawer')` opens All apps. - **One search field for every site: `ov-searchbox.js`** (the owner, 11-12: "improve the search field … autocomplete, dropdown, animated effects … a shared, universal, reusable search input component"). `` in a form becomes a pill: the search mark, the field, a clear button and a "/" key hint on a computer; its edge glows with focus. The placeholder walks through the examples while idle (Calm slower, Off never). Suggestions come from the source in OVCombo's shape, with icons (search, recent, page, person, live, video, place) or a small picture; while empty, the person's recent searches here. The first suggestion that starts with the typed words shows the rest as a ghost: Tab or → takes it. Enter searches the typed words (the form's action) or the chosen row's page; "/" anywhere puts the cursor in it; Escape closes, then clears. `OVSearchBox.mount(input, { source, examples, scope, recent, onSearch })`; a cancelable `ov-search` event lets a page search in place. - **OVCombo grows hooks** for anything that is not a value picker: `pick`, `enter`, `onRows`, `selectFirst: false`, `none`, `limit`, `cacheMs`, `anchor`; rows take `icon` or `image`; the skeleton no longer flashes over rows already showing while a quick answer comes. - The navbar's budget is 52 KB brotli (51.6 KB with the menu addresses). ## 4.228.0 — 2026-11-12 - **A page's sections as tabs on a phone** (the owner, 11-11: "consolidate these into tabs, self-contained tabs, so the page isn't so freaking huge … at least on mobile"). `showcase.parts({ name, items: [{ id, label, count, html }], front })` shows one part at a time with a tab bar (its name and count) at 900 px and under, 600 for a front page; every part stays in the HTML (crawlers, AI readers); radios and `:has()`, no script; the arrow keys move between parts; wide screens and browsers without `:has()` stack them. `ov-parts.css` is the same look alone, for a page that does not load showcase.css (Live's home). - **`showcase.pick()`: the pick block, once.** Twenty-five sites kept a copy of a "pick block" (server/render/short.js) whose chips only jumped to a pane, so a phone still showed them all. `pick({ key, label, head, panes, checked })` is that block on `parts()`: a heading, then tabs on a phone, every pane in the HTML with its id, `ov-parts.css` linked by its hash. `parts()` takes `checked` too, and a link to something inside a part opens it (CSS `:target`, no script). - **Caption it with AI.** A picture in any composer has ✨: one tap sends it, made small (JPEG, 768 px), to the Frame's `/api/frame/caption` on the person's own allowance; the caption fills an empty box (theirs to change) and `ovc:caption` carries the alt text. `ctx.alt(file)` and `ctx.caption(file)` for a page; `data-ovc-caption="off"` leaves it out. - **`OpenVibeNavbar.token()`** reads the person's Network token the site gave `init()`. Caption it sends it as the Bearer on any site (the Network's session cookie is not sent cross-site), and the composer's settings sync, which asked for it all along, now finds it. - **A picture alone is a post.** The menu's Feed composer no longer asks for a description of every picture: one left empty is written by AI as it posts, and a post goes without one if that cannot be done. ## 4.227.0 — 2026-11-12 - **One app icon, drawn on the server too** (design rule 142). `OpenVibeIcons.appHtml(site, { size, label, hue })` returns the app icon as markup (no DOM needed): its hue and size inline and its glyph already drawn, so `ov-icons.js` finds nothing to fill and nothing moves when it arrives. `OpenVibeIcons.APP_CSS` is the app icon's own rules, sizes 20 · 26 · 32 · 44 · 56 · 64 included: a server-drawn page puts it in its stylesheet once and its icons are whole before any script runs. - **Every site's "More on OpenVibe", app launcher and next steps draw sites as their app icons** (showcase `network()`, `apps()`, the next-step list), whole on the server and the same as the menu's: 44 px in a row, 56 px as a launcher tile on a phone. A non-OpenVibe glyph (`fa-…`) keeps its tile. - **The square keeps its size before `ov-icons.js`**: the navbar's early rules hold every `.ov-appicon` at its `data-size`, so a page's app icons no longer pop in. - **The menu's "Across OpenVibe" sites and a quest's steps wear their app icons** instead of a small glyph in a ring. - **The Feed's chips name the one feed's new kinds**: Rundown, Jobs, Deals and Stats, beside the media kinds. - **A release reaches a returning visitor within minutes**: an unversioned asset (`cache-policy` `assetHeaders`) keeps five minutes of stale-while-revalidate, not a day. Sites load `navbar.js` without `?v=`, so the first visit to each site after a release ran the old menu. - **/updates passes its contrast check again**: a filter chip's count no longer fades to 70% (axe color-contrast, serious, on every site's /updates; the release browser check had paged as critical). ## 4.226.0 — 2026-11-12 - **The menu's feed draws the one feed's new kinds (feed.item@1)** (the one-feed job's finding: they fell through to a bare card): - **A report** is its number, large, with which way it moved and from what (▲ 12%, was 1,075). - **A folded run** (new jobs, new deals) lists its first three, each with its picture where there is one, rows lined up, then "and 11 more". - **What a count means** is said: "14 jobs", "41 voted"; `counts.watchers` reads "watched". - **The Rundown** is about its actor (feed.item@1's `subject` is a person's id, so the old reading found nothing). - A card without a person no longer says its text twice. - `menu-feed-v2-chrome` checks each. ## 4.225.0 — 2026-11-12 **The menu's Vibe is one place: All · Chats · Tasks · Code, no switch** (the owner, 11-12, crossing out the Chat · Code · Agents switch: "one new unified agent … a shared UI"). - **Vibe opens on All:** every run from the Frame (Vibe chats, tasks, coding runs) in one list (`ov-run.js`, 4.224.0). - The Action Center's waiting and running work from every product (Network `/api/v1/me/actions`) joins it, unless a run already shows it. What needs you comes first, approved or declined in place; the rest open their own pages. - Above the list: the Dock's Now and timeline, your Actor and your agent's live view (lent with `OpenVibeDock.mountInto(el, { tab: 'agent', part: 'top' })`). - Vibe's six starters sit above the box; a press starts that run. Enter in the menu's field starts a run too. - **Chats, Tasks and Code are the Dock's own panels, lent whole** (Vibe's conversations with voice, undo and the timer; Agents with its history, skills and filters; Code with its repos). They move into the one view when it does all they do, so nothing is lost on the way. - The Dock's places open their filter: `OpenVibeDock.open({ tab: 'vibe' })` opens Chats, `'agent'` Tasks, `'code'` Code. The status on the menu button still opens what needs you. `OpenVibeNavbar.openMenu()` also takes `'code'` and `'tasks'`. - **`ov-run.js` gains:** - `o.starters`; - `o.actions: { base }`, the Action Center's work in the list; - `o.top(el)`, the host's slot above the list on All; - `o.panes: { chat, task, code }`, filters the host draws itself; - `o.onPlace`; - `view.prefill(text)`, words in the box, unsent. - A system light theme darkens the agents' glyphs. - **The menu scrolls on a phone wherever the swipe begins** (the owner, 11-12: "scrolling is very buggy … on mobile … especially in notifications"). - Inside the menu, the notifications list was a scroll box of its own that held its overscroll. It never overflowed there, so a swipe that began on a notice moved nothing. - Inside the menu it is now part of the menu's one scroller (one scroller per layer). - Measured with real touches at 390 px, and checked on every tab: nothing else nests a scroll box like it. - New test `notifications-menu-scroll-chrome` (it fails without the fix). - `notification-ui.js`'s brotli budget grows from 25.9 to 26.1 KB for it. - **The composer's + has GitHub.** - It searches repositories through OpenVibe Exchange's code search (the Frame's `/api/frame/code/search`, Network #878) a quarter second after the last key. - Each row shows the owner's picture (GitHub's avatar host only), the name, the description, the language, stars and the licence, all as text. Enter or a press puts the repository's address in the box, where every site draws it as a card. - A box may point it at another Network with `data-ovc-frame`. `composer-v2-chrome` checks it. - **One app icon for every site: `.ov-appicon` and `OpenVibeIcons.app(site, { size, label })`** (design rule 142). - It is the menu's and Home's own icon: the app's steady hue on a rounded square, with its glyph drawn over it. - Use it from markup (``) or from script. Markup added later, or an app that changes, is drawn again. - With a label it is an image with a name; otherwise it is decoration. `OpenVibeIcons.hue(id)` is the shared hue. `ov-appicon-chrome` checks it. - **Home on a phone: a long press then a move keeps the app under the finger.** - Entering Edit repaints the grid, so the tile under the finger left the page, and the grid's touch guard no longer heard that touch: the first move scrolled the menu and cancelled the press. - The guard now rides on the pressed tile itself until the finger lifts. - `menu-home-screen-chrome` drags with a real touch (it fails without the fix). - The menu reads runs and the Action Center from the Dock's Network base (`runsBase`). - **Tests:** - `dock-chrome` gains the All view at 390 px: the four filters on All; a run and the Action Center's work in one order; the Dock's top lent without its list; the starters; Tasks as the Agents panel, remembered by the Network; approve in place from All. Every Dock check before it still passes unchanged. - `run-thread-chrome` gains the starters, the Action Center's rows (nothing twice), the host's slot, the place and prefill. - `menu-places-chrome` and `menu-home-screen-chrome` follow the filters in place of the switch. ## 4.224.0 — 2026-11-12 **One thread view for every run: chats, tasks and code** (the owner, 11-12, crossing out the menu's Chat · Code · Agents switch: "one new unified agent … a shared UI … a full conversation with rich embedding"). - **New module `ov-run.js` (`OpenVibeRun`)** draws any run from the Frame's Run API (Network `/api/frame/runs`; Contracts `agents.run@1`, `agents.step@1`), on every site: - `OpenVibeRun.mount(host, { base, token, me, sibling, examples, start, filter, open })` returns `{ list(filter), open(ref), start(text), destroy() }`. - `OpenVibeRun.card(type, render)` adds a rich card for a step's `ui.type`; built in: `results`, `table`, `link`, `code`. A card it does not know shows the step's words. - **The list:** - Filters: All · Chats · Tasks · Code. - Order: what needs you first, then newest. - Each run shows its agent's face (its picture, or its glyph on its own hue, with a badge saying what it is doing), its title in the brand face, its last line and when. - Pills say "Needs you", "Working" and "Did not finish". A product that did not answer is named under the list. - A run that asks before it acts is answered from the list: Approve or Not now, in place. - A filter reloads only the rows, so the words you are typing stay. - **The thread:** - Your words on the right. The agent's on the left: paragraphs, lists, bold, inline code, links, and numbered sources whose [n] marks link to them. - Thinking is folded. Each tool is one quiet row (it opens to its output). - An approval is a card with its answers. Child runs are rows that open them; files are chips or pictures. - It follows the run live: server-sent events read with fetch, so the bearer goes along, resuming after the last step it has. - The composer underneath says the next thing. A new run starts from the list's box, sent once with an idempotency key. - Page text is never markup, and only https links are drawn. - **The menu keeps the Dock's panels for now.** Its Vibe moves to this view (and the switch goes) once the view does everything those panels do: - the Action Center's items from every product, approved in place; - the live agent view (Pause, Curtain, Mute, End); - Vibe's starters and voice; - "Ask your agent" from a page; - the place the Network remembers. - **Arrange:** Stop is an ordinary optional part; it docks right like any other (#501). - `ov-run.js` and `ov-composer.js` have content hashes in `SIBLING_REV`, ready for the menu. Every site serves `ov-run.js` (`files.js`), and the package exports `openvibe-shared/ov-run`. - **Tests:** - New `run-thread-chrome` (390 and 1280 px): the list and filters; approve in place; every kind of step; the live stream and where it resumes; approvals, messages and a new run reaching the API with the person's token; no markup from page text; no overflow. ## 4.223.1 — 2026-11-12 The menu keeps its search field and tabs (the owner, 11-12, two phone screenshots: "the gui gets messed up and loses its tabs", "Missing top tabs"). - **What went wrong:** - 4.223.0's slow light behind the menu is drawn 20% past the panel's edges, and the panel was `overflow: hidden`. - A hidden-overflow box is still a scroll container, so a focus or a scroll into view inside the menu scrolled the whole panel up: the field and the tabs left the screen, with an empty band at the bottom. - **The fix:** the panel now clips (`overflow: clip` is never a scroll container), and any scroll an older engine gives it anyway is put back at once. - "Your own AI" keeps its name on one line; its sentence takes the wrap. - **New test** `menu-panel-still-chrome`: at 390 and 1280 px, a focus deep in the site list moves the list, never the panel. ## 4.223.0 — 2026-11-12 You redone as tabs, icons that fill their squares everywhere in the menu, names in the brand face, and one composer with a + for every tool (the owner, 11-12, a run of phone and desktop screenshots: "the notifications area is ultra buggy … move the notifications into a tab … put the apps more front facing"; "make the icons bigger so they actually take up more of the square … fix the alignment"; "waste of space … compact"; "fix the mic to the left … the timer should be in the plus thing … usable on all composers across all sites"). - **You:** - **One top:** your row, then your AI. Side by side when the menu is wide. Your row holds every round button, with this site's own (your channel, Admin, what a site adds) first as icons. The lone "Channel" row is gone. - **Three tabs:** Apps (first) · Notifications · Recent. One row, with All and Edit at its end; no "Your home" head. - An ink slides to the chosen tab and the tab's content slides in from its side. Calm fades; Off stills. - On a phone, only the chosen tab says its name. The arrow keys move between tabs. - **Notifications** is a tab: - the whole list, with its own search, filters and Mark all read; - it loads `notification-ui.js` itself when the tab opens first (it said "unavailable"); - its count follows the bell live. - **Recent** is the whole history: - newest first, in days (Today, Yesterday, This week, Earlier); - each place a card with its whole title, its site and when, and LIVE when it is live; - two columns when wide, Show more, and Full history to openvibe.my/history. - **Your AI:** - its face shows what it is doing (reading, writing, searching, coding, waiting for you…) as a glyph; - it breathes while working; - Open is a round arrow and Answer is a pill; - not yet set up, it is one slim row. - **All apps:** back is a round arrow, with the search beside it. Each group is marked with its glyph and its count. - **App icons, everywhere in the menu** (You, the site list, search rows, the feed): - the site's hue on a rounded square, with the glyph at 58% of it; - drawn absolutely, so no hover can move it off centre; - a folder's four apps sit in an even 2×2 (they were offset and cut off); - a + to add an app sits on the icon's corner; - a mouse lifts an icon and lights it in its hue, and a press sinks it. - **Names in the brand face:** - app, site, tab and section names are in OV Brand (Nunito 800, loaded by the navbar on every site); words you read stay in the UI face; - names wrap to two balanced lines and never end in "…"; - section heads are names, not small capitals. - **The site list** (a site's own tab) is a grid of app icons: four across on a phone, as many as fit beyond. Each section wears its glyph. - **The feed:** - a recording's length reads as a time (5203 → 1:26:43); - the Rundown is its own card: "The Rundown · about Maticus", its mark, a ribbon on its picture, and a grade, so it never reads as the stream's card; - the kind glyph beside the time is 18 px. - **One composer** (`ov-composer.js`, every box on every site): - **The row:** the mic first, then the + and the box's first tool on a phone; the + opens every tool of the box, big and named. It lists the row's own tools, the mods' tools and the extras. - **Timer:** a tool in every box's + (`OpenVibeComposer` TOOL `timer`, `extra: true`). Vibe's switch row no longer has a timer of its own. - **Examples:** an empty box shows what people do with it, in turn: `examples`, or a preset's own, or `data-ovc-examples`. Calm is slower; Off keeps the first. - **Send:** the round send is an arrow up, in the accent when there is something to send. - **Vibe:** - its box is the same composer, with its hold-to-talk mic first and then the +; - a link in your own message reads (it was blue on blue); - Chat · Code · Agents is one segmented control with a sliding ink, at 15 px with 20 px glyphs. - **The menu:** - Close is a round × on every screen; the phone's close orb is glass with a hairline edge, never a thick ring; - a slow light drifts behind the panel (Calm slows it; Off stops it). - `OpenVibeNavbar.openMenu(place)` opens the menu at a place: `notifications`, `recent`, `apps`, `you`, `feed`, `vibe`, `chats` or `agent`. A site's own links use it (openvibe.my's Notifications tile clicked a bell that is gone). - **Times:** a time without a zone is UTC. Network's history sends "YYYY-MM-DD HH:MM:SS", and browsers read it as local time; west of UTC every visit said "just now". - **The notification rows:** - one way to clear a notice (×); a tap reads it, and a swipe still offers Read or Clear; - the title and its ×N count are one run of text (the count overlapped the words). - **Tests updated:** menu-home-screen, menu-places, menu-close, dock-chrome (the timer through the +), composer-v2, composer-camera, inline-composer. ## 4.222.0 — 2026-11-12 The wallet sheet redesigned for phone and desktop, every phone page back to its true width, and whole site names in the menu (the owner, 11-12, a phone screenshot of the wallet marked "UGLY" twice; "make everything a little more user-friendly and elegant … perfect the layout … across all sites"). - **The wallet:** - **Balances first.** - **What changed reads as rows:** one per currency, with its mark, a counted summary ("Quests done ×10") and when, and the amount in its colour ("+161k"). Each change, with its own amount, sits in a fold ("See all 10"). Before, every quest was strung into one paragraph. - **Every section has a head with its glyph:** What changed, Recent activity, Store, Your items. - **Empty parts are a small card with their mark** saying what will appear (openvibe.design rule 141), never a grey line under a heading. - **Recent activity in the same hand:** the currency's mark, the reason as a 44 px link (no underline across the row), its first letter up, the amount in its colour. - **Store prices are pills with the currency's mark**, each named in full for a screen reader; "Owned" is a green badge; pictures and names sit closer. - **On a computer, What changed and Recent activity sit side by side.** - The head is the wallet's mark, "Wallet" and "Yours on every OpenVibe site". - The sheet's marks are the registry's glyphs (`test/wallet-glyphs.test.js`). - **The bar never widens a phone page.** Every OpenVibe page was 392 px wide on a 390 px phone (so phones zoomed out a little): Sign in's larger tap area reached 8 px past the bar's edge. `.openvibe-navbar { overflow-x: clip }`; dropdowns hang below, so only the sides clip. - **The menu keeps a site's whole name:** a long one takes a second line instead of "Downlo…". Tests: `wallet-chrome` and `purse-catchup-chrome` (the new rows), `wallet-glyphs` (new); the wallet fixture can give a rich history (`changes: 'many'`). ## 4.221.0 — 2026-11-12 The icon system, audited end to end (plan L32 I1/I2; the owner, 11-12: "Broken icon. Improve the icons that exist, add more icons, and improve the icon system in general"). - **No broken icon anywhere.** `scripts/icon-audit.js` reads every OpenVibers repository's main and lists every icon name that does not resolve: `fa-*` classes, `kit.icon('…')`, `glyphs.*('…')`, and the `icon:` fields in NAVs, menus and manifests. A site can run it from the package (`npx ov-icon-audit --root .`) and fail CI on a miss; the audit found and this release fixes `fa-shoe-prints`, `fa-calendar-check`, `fa-cloud-arrow-down`, `fa-magnifying-glass-chart`, `fa-magnifying-glass-dollar`, `fa-plug-circle-plus`, `fa-power-off` and `fa-receipt`. - **`kit.icon(name)` draws every glyph in `openvibe-shared/glyphs`**, not only the kit's own 86: the rest travel with kit.js as a generated block (`scripts/build-kit-glyphs.js`) and a test checks the block is current. `compass`, `chip`, `gauge`, `layers`, `route`, `scale` and `flask` no longer draw an empty `` through the kit. - **Nine new glyphs**, each with a solid twin: `binoculars`, `telescope`, `microscope`, `gpu`, `cpu`, `memory`, `joystick`, `wand` and `layers-plus`; `wand-magic-sparkles` now draws the wand, and `ram` maps to `memory`. All are centred and sized to the set (checked by test/glyph-metrics, test/icon-ink), reviewed at 16/20/24 px in light and dark, and rebuilt into the sprite, CSS, web/desktop fonts and code points. - **Keywords for every glyph.** `glyphs.META[name].tags` carries the Font Awesome names a glyph stands for plus its synonyms (for the icon pages and the suggest API), so every glyph has searchable words. ## 4.220.0 — 2026-11-12 **One UI: the floating Dock is gone; the menu holds Chat and Vibe on every screen** (the owner, 11-12, with a phone screenshot of the Dock crossed out: "there should only be the one unified UI … we're supposed to delete … that has the old tab system", and the menu marked "the one unified"). And the Vibe place redesigned (the owner: "sleek … nice on mobile … organized properly and sized well … without all these huge spaces … makes use of the full space … icons for everything using OpenVibe.design … modular … reusable for different sites"). - **Gone:** - the Dock's pill; - its floating card with the Vibe · Code · Agents · Chat · Activity tab bar, More, pin and Close; - corners, drag and resize; - the phone sheet that opened out of the menu button; - the window of its own (pop-out); - the You tab's "The Dock" row; - the Activity tab (the menu's You tab has the notifications; `OpenVibeNotifications.renderDock` is gone with it). `dock.js` is 703 lines, from 1,129. - **The menu's Chat and Vibe open inside the menu on every screen.** A computer opened the floating Dock. - Vibe's Chat · Code · Agents switch has the timer as an icon at its end; it was a full row under the box. - On a computer the menu grows tall while a place is open (`min(820px, 86vh)`). - `OpenVibeSearch.open({ door })` and `OpenVibeSearch.door(id)` open the menu on a place, or move an open menu there. - **`OpenVibeDock.open({ tab })`, `ask({ text })`, `share({ text, title })`, Alt+V and `OpenVibeNavbar.openDock(id)`** open the menu on that place (`opts.openMenu`, given by `navbar.js`); `close()` closes the menu. A place in Your places (Vibe, Agents) opens there too. - **What the pill said is a status on the bar's menu button** (`opts.status`, painted by `navbar.js`): - a breathing accent dot while agents work; - an amber one when one needs you (the button then opens the menu on Agents); - a timer's minutes in a small label under the button. The tooltip and the button's name say it in words. Calm slows the breathing; Off stops it. - **Vibe, redesigned:** - a header that says what it is: back, Vibe's mark, "Vibe" over "Your AI on every OpenVibe site", New chat and Open in Chat as icons; - a greeting at the top ("What can I do for you?"), and a new chat opens there; - six starters as full-width rows with their marks (two columns on a computer); - the composer's two-row box (the words over the whole width, then picture, Build it in Code, the mic and a round send); - result cards with their actions under the words; - long links wrap. - **Every Vibe mark is the network's glyph** (`openvibe-shared/glyphs`, shown on openvibe.design/icons); so is the Dock's send. `test/dock-vibe-glyphs.test.js` keeps them equal. - **Direct messages take the network's message actions** (openvibe.design rule 138, as Live's chat and `messages.js`): - Edit is a pencil beside your bubble on its empty side, on hover or focus, or a tap on a phone; it never covers words; - the box is the editor, under an "Editing your message" bar (Escape or × lets go); the browser's prompt is gone; - "edited" is one quiet word inside the bubble; - `dock-chat-edits.js` keeps only Chat's socket. - `bottom.js`: the pill's stacking entries and `--ovb-composer` (which only the pill read) are gone. - **One head, not two** (the owner, 11-12: "part of the one UI instead of having two different areas"): inside the menu a place has no header band of its own. An open conversation's + and ↗ move into the menu's search pill (as a list's already did); it keeps a slim way back and its name; Vibe's mark is the greeting's. Tests: - Rewritten for the menu: `dock-chrome` and `dock-vibe-timer-chrome` (no pill or floating Dock ever; the status on the menu button; Agents, Chats, Send to, the agent view, Vibe, voice, the timer and Ask your agent through the menu), `dock-mount-chrome`, `dock-signin-chrome`, `menu-places-chrome` (Chat and Vibe inside the menu at 390 and 1280), `menu-home-screen-chrome`, `bottom-chrome` (no pill). - New: `dock-vibe-glyphs`. - Gone: `pill-composer-chrome` (the pill it kept above a chat's box is gone). ## 4.219.0 — 2026-11-12 Every plain element styled by the theme (the owner, 11-12, with circled screenshots of openvibe.exchange: "make sure all basic elements are styled … custom with the theme system … update the little dots … reflect and improve all existing elements … the spacing could be improved"). - **Radios and checkboxes are drawn** under `.ov-base`: a ring in the theme's line colour, the site's fill when chosen, the radio's dot growing in and the checkbox's tick popping in (Calm keeps the change, Off removes the movement), a focus ring, and a label that holds its control is one tappable row. - **Text fields**: the placeholder in the muted colour, an accent ring on focus, room under each field. - **A plain details** (no class of its own) gets a chevron that turns when it opens, and no browser marker; a site's own details keeps its own. - **A site's own questions in a showcase section** (a plain `
` straight in `.sc-sec`, as 20 homes have them) look like `sc.faq`'s: a card each, no browser marker, a chevron that turns, the answer padded (unstyled-sweep found them on Blog, Chat, Compare, Coupons, Deals, Download, Food, Games, Host, News, OpenRestream, Reviews, Run, Space, Tips, Trade, VIP, Vision, Wiki and Zone). - **Words straight in a kit section** (`

`, ``, `

`, lists, quotes, code) keep the section's padding; they sat flush against the box's edge. Test: `kit-layout-chrome` (the drawn radio and its dot, the filled checkbox, the plain summary's chevron, a section's padding). ## 4.218.0 — 2026-11-12 One composer, three verbs: **Post · Ask · Do** (research-2026-11-12/composer-post-ask-do.md; the owner, 11-12: "make it so that the composer is able to … integrate directly to have the models list from OpenVibe.Exchange … the search the web feature, the search engine feature … more cohesive, interconnected", and "Actor should be more of an orchestrator … same features across all different sites"). - **`verbs: ['post', 'ask', 'do']`** (a site opts in; the first is where the box starts) draws one switch: on a post or a reply beside the name, in a chat or an agent's box at the start of the row; on a phone the chosen verb keeps its word and the others are icons. **Ask**: an AI answers you; **Do**: Actor does it for you (the orchestrator, handing parts to Codes, Bot, your computers); **Post** (Send, Reply) is unchanged. - **Ask and Do's chips**, a line of their own above the words: - **Model**: a sheet (the whole width on a phone) over the Frame's `/choices?task=`: Auto, then OpenVibe's models from Exchange's directory with their price per million and a link to each model's page on openvibe.exchange, your keys, your computers, your plans; a find field; the choice is remembered per task; - **Sources**: Web, OpenVibe, Mine, This page (when the site says what the page is), as switches; - **Depth**: Quick, Balanced, Deep research. - **The answer card** under the box: the answer streamed from the run's events (AG-UI over `/api/v1/runs/:id/events`), its sources as numbered chips, the model and the cost, and three ways on: **Post it** (the answer becomes the box's own post or message), **Continue in Vibe**, **Do this**. An Ask never reaches the box's onSubmit. - Without `onAsk` / `onDo` the box asks the Frame (`POST /ask`, `/do` at `frameBase`, default https://openvibe.network/api/frame); a site that answers itself gets the same card (`api.card`: append, set, cite, done, fail). The api adds `verb()`, `setVerb()`, `model()`, `sources()` and `answer()`. - **The inline Community thread is the comment preset** (#490): `thread.composer({ preset: 'comment' })` marks the server form, and `ov-thread.js` replaces it in place with `OpenVibeComposer.mount(..., { preset: 'comment' })` for every `[data-ovc-thread]`: the action, a reply's `parent_id`, files and the no-JS post stay. Video, Pics and a paste's comments are the same box, once. Tests: `composer-verbs-chrome` (the switch, the chips, the Model sheet from a fake Frame with prices and Exchange links, find and pick, Sources, an Ask streamed into the card with its sources, Post it, a site's own answer, 390 px), `inline-composer-chrome` (the inline thread mounts the comment preset, keeps its action and `parent_id`, posts at 390 px). ## 4.217.0 — 2026-11-12 The composer gets what the agents portal's own box had: a camera, Try again, and pictures made smaller before they go. - **A camera in the box** (`camera`, in the post and agent presets; any site can name it): a sheet over the page, the whole screen on a phone, with the picture, Photo or Video, the shutter, Switch camera and Close, as a phone's camera app has. A photo or a clip (up to a minute) goes into the box as a file, nothing kept or sent before the message is. It opens through the shared capture core (`ov-capture.js`, loaded from beside the composer the first time), so its help when a camera does not open is the same plain help Live's go-live page gives; the tool is not drawn where the browser has no camera. - **Try again on a failed upload**: the file's own picture (or icon) becomes the button, and a post's picture tile says "Try again" across it. - **Pictures made smaller before they upload**: `resize` (the long side in pixels; `data-ovc-resize` on a box made by hand): 2560 for a post, a chat or a reply, 1568 for an agent (the size a model reads, as the agents portal sent them). JPEG, PNG and WebP only; a smaller file is never swapped for a bigger one; GIFs and SVGs are left as they are. - **Fixed:** in the one-line chat box, the "Editing your message" and "Replying to …" bar is a line of its own above the words (4.216.0 drew it in the box's first column, over the words). ## 4.216.0 — 2026-11-12 One capture core for every camera, and a chat message's actions in one place on every site. - **`ov-capture.js`: `window.OVCapture`, one way to open a camera, a microphone or a screen, take a photo and record a clip**, shared by Live's go-live page, OpenVibe.Cam's recorder and ``, and the composer (the owner, 11-12: Live's capture must be "completely customize[able] … highly over engineered modular editable", then "OpenVibe.cam is actually fine … Harmony"). It began as Live's own system (OpenVibe.Live #847) and every site serves its own copy at `/shared/ov-capture.js`, so a camera never waits on another site, a content policy or a cache (from 11-09 to 11-12 nobody could go live because Live loaded Cam's kit from openvibe.cam and the browser refused it). - `open({ mode, facing, lens, mic, resolution })` runs the strategies in order (together, then each on its own, then anything), each with a time limit; a refusal stops at once; the failure that says most is the one reported. - `screen()`, `photo(stream, { mirror })`, `record(stream, { maxSeconds })` → `{ stop() → Blob, cancel() }` (the first format the browser supports), `devices()`, `meter()`, `network()`, `can()` (what this browser allows here). - `explain(error, mode, { instead })`: plain steps for each browser (Safari's "aA", Android's site settings, Firefox's blocked icon, an app's in-app browser, a Mac's Screen Recording switch), with a last step of the site's own. - Settings: this device first; `settings.sync({ load, save })` lets the choices that mean the same anywhere (facing, resolution, mirror, effects) follow the person, for example through OpenVibe.Cam's camera settings; camera and microphone ids never leave the device. - Every part (`use(name, impl)` returns the one it replaced), every strategy (`strategies.add/remove/replace/reset`) and every event (`on('opened' | 'failed' | 'settings' | 'synced' | 'recorded' …)`) can be changed; it fetches nothing. A newer copy replaces an older one, never the reverse. - **A message's actions are one cluster at its corner** (openvibe.design rule 138; the owner, 11-12, with phone screenshots of a stream's chat: "The edit button needs improvement … so it never happens again", "it also looks stupid as shit after you edit it"). `messages.js`: - `render(root, { …, actions, onAction })`: `actions` names what to offer (`reply`, `edit`, `react`, `translate`, `copy`, `delete`; edit and delete on your own messages only) as icon buttons in one cluster just above the message's right end, on hover or focus on a computer and a tap on a phone (thumb-sized there), never in the words; a press calls `onAction(id, message, row)` and bubbles `ovm:action`. - `actions(row, ids, { onAction, message, mine })` gives a site's own rows (Live's chat) the same cluster. - `edited(textNode, at)`: "edited" is one quiet word right after the words, the time as its title, never a line of its own. - **The composer edits and replies in the box**: `api.edit({ text, onSave, onCancel })` puts your message's words in the box under an "Editing your message" bar (Enter saves through `onSave`, never `onSubmit`; Esc or × puts back what was in the box; the send is a check); `api.reply({ name, text, data })` shows "Replying to …" and the send carries `reply: data`; `clearBar()`, `editing()`. ## 4.215.0 — 2026-11-12 Composer v2: one elegant composer that every site mounts (the owner, 11-12: "this composer is completely ugly and broken … doesn't have the file attachment … it needs to be super elegant, like some kind of social media platform … a shared composer … interconnected through all sites with all the features we might ever need … really modular"). - **`OpenVibeComposer.mount(host, options)`** draws a whole composer from a preset, and everything `enhance()` gives comes with it (files by the picker, a paste or a drop, uploads with progress, `/` commands, `@` mentions, voice, drafts, the keys, your settings): - **post**: one line with your picture, your name and who sees it (a chip), then the words over the full width, a box that grows with the words, pictures as tiles each with its description and files as chips under the words, photos, files, emoji and voice, the ring that fills toward the limit (amber near it, red past it) and Post; - **chat**: one line that grows, attach, emoji, voice and a round send; - **agent**: a roomy box, attach and voice, the mode chip and a round send (Actor, Codes); - **comment**: the small one, with your picture and Reply. - `onSubmit({ text, files, uploads, audience, mode }, api)`: the box clears after it; `false` (or an error, shown in the box) keeps it. `audience` and `mode` are chips over the browser's own list. - **For agents** (from the agents portal's own box): `chips: [{ name, label, icon, options, value }]` for any number of choices (Model and Reasoning beside the mode), all sent as `chips` by name; `setRunning(true, onStop)` turns the send into Stop while a run works (a click stops, nothing is sent), `setRunning(false)` brings it back. - **Tools are modules**: `OpenVibeComposer.tool(id, { label, path, accept | run(ctx, button, form) })` adds or replaces one for every box; a preset or a site names the ones it shows (`tools: ['photo', 'file', 'emoji', 'poll', 'voice']`). Built in: photo, file, attach, emoji (a panel of 90 at the caret), voice. `presets()` and `tools()` list them. - **The Feed's composer is the post preset.** Its own + drew an icon with no stroke, so it could not be seen; the Feed's posting (pictures with their descriptions through the frame, other files to Media) is unchanged. - `enhance()`: a box takes a file any of its pickers takes; a mounted box grows with its words; the file strip sits beside the box wherever the box is. Test: `test/composer-v2-chrome.test.js` (the four presets at 390 px, a post's chip above and pictures under, onSubmit and false, the ring, emoji, a site's tool); `menu-home-screen-chrome` reads the Feed's note inside the composer. ## 4.214.0 — 2026-11-11 A train of four pull requests: the Arrange editor (#481), one inline comment thread for every site (#479), the bar's first paint following the sign-in hint (#482) and four redrawn glyphs (#484). - **The Arrange editor: a person's own controls, on the real parts.** `ov-arrange.js` is loaded only when someone presses Arrange, and loads `ov-arrange-core.js` (openvibe-sdk/ui-layout for the browser, generated by `scripts/build-arrange-core.js`) from beside itself by content hash. A surface's `[data-ov-part]` elements are placed from a ui.layout@1: drag to move on the grid, the corner to resize, arrows to move and Shift with the arrows to resize (a docked overlay chooses an edge the same way). The part's sheet has visible, size, tint, shape, opacity, label and bindings; long press opens it on a phone. The SDK rules refuse a bad move with the reason in plain words (Stop has to stay visible; it is too small), every move and resize is announced, and Undo, Reset to default, Save and Share are in the bar. Ask OpenVibe's ui.layout.suggestion is previewed on the real parts and applied only with Keep; Motion Off shows no animation and Calm plays the short one. (#481) - **One inline comment thread for every site: `thread.renderThread` and `thread-inline.css` (new), beside the composer.** MediaHub's Video and Pics item pages and Community's paste and `/c` pages rendered two copies of the same thread; the renderer now lives in `openvibe-shared/thread`, with both sites' options: `attachmentsAllowed` (Pics and a paste page offer files; elsewhere the composer does not) and `draft` (the message kept after a failed post). It draws the quiet head, Top and Newest only when there is something to order, the composer or one sign-in line (the whole empty state when nobody has commented), the comments with their replies, targets, deletions and attachments, More, and the discussion link. The markup is byte-for-byte what the two sites render; each keeps its own post, delete and sign-in routes. The stylesheet is served like the package's other CSS (`/shared/thread-inline.css?v=`, `files.js` STYLES), so a site pins one look. Both sites' renderer tests are here; MediaHub and Community delete their copies and pin this release. (#479) - **The bar's first paint follows the sign-in hint (asks 327, 345).** When `ov_sso_hint` says `account`, navbar.js draws the signed-in shape at once: a neutral placeholder avatar, and the account's own name/initial only when the hint carries it (`account:`); the session check then replaces it or corrects the bar to guest. A failed check no longer leaves the optimistic bar behind, and an explicit `guest` hint keeps the guest bar and starts no silent round trip. The hint is never authorization: it holds no token and is not remembered as an account. sso-client.js stores the name after a FedCM sign-in when the response has one. (#482) - **Glyphs: care, fish, handshake and eye-off redrawn for 16 px** (the last four the 11-11 glyph review named weak): care keeps its heart clear of an open hand; fish has an open V tail and a dot eye; handshake drops the tiny finger strokes and gets its first solid twin; eye-off breaks the outline where the slash crosses (#484). ## 4.213.0 — 2026-11-11 - **The menu button's flight, polished** (the owner, 11-11: "the icon becomes whiter than it was when idle … needs general polish … effects when it lands … improve both the open and close transitions"). search.js's flight now copies the pressed button exactly as it looked before the press (every computed paint frozen onto the copy: the navbar's colour rules stop at its edge, and the press had already turned it bright and half into an x). It drops first and glides into its tab, swelling a little and tilting into the turn with a short trail and a soft glow; it lands with a squash and a ring; flying back it does the same on the bar button. The menu's circle now grows from the button around the flight (it was cut short), the close orb turns in once the button has left, and turns away when closing with a button flying back. Calm plays the same path short, with no trail, tilt or glow; Off skips it. - **The carried Live card, designed** (the player that keeps playing across sites, 4.212.0): at rest a live card keeps a small red dot in its corner; playing without sound (a browser that would not carry the sound over) it shows one "Tap for sound" chip, at rest too, that turns the sound on (only its icon on a card under 200 px); "Open the full page" draws a page with an arrow out of its corner, not fullscreen's two arrows. - **A menu in a rail opens in the top layer** (Community's paste cards, 11-11: the ⋯ menu was cut off). A rail's edge fade is a mask, which hides even a fixed menu outside the rail's box; kit-web.js now shows a rail's `details.ovk-more` menu with the Popover API, placed under its button, and keeps the fixed placement where the API is missing. ## 4.212.0 — 2026-11-11 A train of four pull requests (one line each): - **A carried Live player can play on any OpenVibe page that permits Network frames.** The portable card keeps the original Live embed and channel addresses in its state, while its iframe loads Network's narrow Live player bridge; sound controls and state events pass through that frame, so no destination's frame policy changes (#473, ask 360). - **The bar catches up on balance changes across sites (ask 273).** Once a signed-in wallet loads, its pill plays each currency's net gain or loss once and marks that currency's cursor read through Network's frame relay; Calm keeps one quiet effect, Motion Off updates the figures only. The Wallet sheet starts with the recent net amounts and the API's plain reason names (#474). - **The Dock's pill stands above a page's bottom composer.** bottom.js measures a composer docked at the bottom of the screen (`form[data-ovt-composer]` or `data-ov-bottom-dock`) and writes `--ovb-composer`; the pill keeps above it as it grows and comes back when it goes (on openvibe.chat it covered the send button) (#475). - **Glyphs: focus and bridge redrawn** after the all-glyph review: focus is a viewfinder round its centre, bridge two towers, the cable and the deck; both have solid twins, drawn to the set's size (the long side 0.79 of the box); the drop-in, sprite and fonts are rebuilt (#476). ## 4.211.0 — 2026-11-11 - **The menu's You tab leads with you (ask 158b, "the You tab still sucks").** Its notifications are a preview of the newest three, with no search, filters, foot or Load more until "Show all N" opens the whole list in place; the person's bar, their AI and the rest are a glance below instead of a thousand pixels down. The person's name and handle wrap instead of being cut (rule names-are-never-cut). - **An agent's sheet (agent-sheet.js, new; the Dock's Actor row opens it).** One window (ov-window.js: a panel beside the row on a computer, a sheet on a phone) with everything about one agent: its face, state and instructions, then Now, Asks (first when it waits for you, with the count), Work, Schedule, Memory and Computer as tabs (arrow keys move between them), each with its own words when empty; the mark's wait while it reads and Retry when a read fails. Data: Contracts actor.agent-sheet@1 / codes.agent-sheet@1 through Network's relay (/api/frame/agents/:id/sheet, /api/frame/codes-agents/:id/sheet) with the bearer, no cookies; all text, never markup. `OVAgentSheet.open({ kind, id, name, token, frameBase, base, from, openHref })`. The row used to leave for the Actor's page; that page is the sheet's Open now (a modified click still goes straight there). - **A composer's count shows only near its limit (ov-composer.js).** The last 15% of the box, at most 200 and at least 20 characters: a 120-character search box said "120 left" while it was empty (Exchange's /models). ## 4.210.0 — 2026-11-11 - **A page's title and its line wrap before they are cut (kit.css `.ovk-head`).** The title takes up to two lines and its line up to three, instead of one line each with an ellipsis (the Arena's "One prompt, two models, side b…" on a phone). openvibe.design rule names-are-never-cut. ## 4.209.0 — 2026-11-11 **The Quest guide on any page, and the current Live step in the Dock's agent view.** - **The Quest guide for browser pages (#464).** Pages can start the Quest guide from an opaque `qstep` link once the host resolves the step; it waits for late controls and checks the Events-backed completion read, and the shared navbar starts it from its own sign-in. - **The Dock's agent view shows the current Live step (#466)** when the stream supplies one; older streams keep showing the task without a step line. ## 4.208.0 — 2026-11-11 **One move engine for every floating thing: the picture-in-picture's drag, flick, tuck, pinch, corner and place, now shared and adopted by the window.** - **`ov-float.js`.** `OVFloat.attach(el, { frame, key, defaults, aspect, minPx, onChange })` gives any box Live's picture-in-picture behaviour: docked in its frame or fixed over the page, the lift on the first move, a transform each animation frame, the FLIP landing with the spring, a flick, edge snapping, the tuck into a side with its tab, pinch and corner sizing, a double tap, the keyboard (arrows, + −, T, F, Home), fullscreen, reduced motion, and its place as fractions of its frame. The place is kept in localStorage by `key` and in the account through `OVFloat.store` (`GET`/`PATCH /api/me/layout`, the `pip` map); `OVFloat.layout()` and the `ov:float` event say where every box is. Its behaviour CSS is injected once; a component keeps its own look. - **A panel window moves, tucks and keeps its place (`ov-window.js`).** A panel's head is an OVFloat handle: drag it anywhere, flick it, throw it past a side to tuck it with a tab, and it opens where it was left. The absolute place older releases wrote stays readable, and the size the corner grip keeps is unchanged. - **Live's picture-in-picture uses it (`stream-pip.js`, in the Live release).** The viewer sessions, waits and actions stay Live's; the move, tuck, size, keyboard and persistence are the shared engine's. ## 4.206.0 — 2026-11-11 **The menu keeps a stream playing, the Feed in the menu is searchable with the one composer at its top, and a Code task opens in the Dock's step card.** - **The menu no longer pauses what is playing (#461, ask 360).** Opening the menu on a phone left live video and audio paused under it; the sheet now leaves media alone and the page can read the player's state. - **The Feed in the menu (#463, ask 360).** Feed search uses Community's search and examples through Network, with loaded-card filtering when search is unavailable; the example searches are chips that fill the field. The Feed's post form is the one composer (OpenVibeComposer: files, paste, drop, commands, drafts, settings); each picture needs a description and other files upload to Media. Its + and the example chips carry their own styles in the menu (they drew as bare browser buttons in the PR's screenshots). - **Chat and Vibe (#463).** The Chat summary's Vibe row is an accessible Open Vibe button that selects the menu's Vibe tab; on a desktop Chat and Vibe open the Dock after the menu closes, and the Dock opens from its pill only when that pill is visible. - **A Code task in the Dock (#465, ask 354).** The Dock's Code card shows the task's live steps with the AG-UI step view (agent-session.js card mode) and opens the whole run. ## 4.205.0 — 2026-11-11 **Agents show their work everywhere: the one step view reads AG-UI, compact like the portal, with the one composer to talk to the run; and every site's first HTML is crawlable.** - **The step view reads AG-UI 1.0 (`agent-session.js`, protocol 1.2, ask 354).** Run, step, text, tool call, reasoning, state, activity and custom events, with OpenVibe's words in `metadata.ov` (title, kind, sources): phases with a plan row ("1 of 3"), steps under the agent's own titles (rows under one title show their own target), thinking folded to one line, sources gathered in one strip (site tiles, https links), text streamed in place. - **Compact runs.** A group is one line (its state, its words, the step it is on in mono, the chevron), the head says what it is doing now, three dots while it works; `mount(el, { mode: 'card', href })` for a chat message, the Dock or a feed card. - **Talk to the run with the one composer.** `mount(el, { onSend(text, { files, uploads }) })`: the shared composer's markup ("+" for files, paste and drop, "/" commands, voice, drafts, settings), loaded from beside the view. - **The composer on any page (`ov-composer.js`).** `clear()` and `uploads()` for boxes sent by script, a form reset clears it, and it styles its own tool buttons and row, so it looks the same without thread.css. - **`openvibe-shared/crawlable` (was #457).** Static navigation, the network's sites by group, JSON-LD and llms.txt for the HTML a site sends before its scripts run. ## 4.204.0 — 2026-11-11 **Buttons that show their state, windows that resize, the one composer everywhere, players that start sooner, and one place for the network's CSP.** - **Buttons that show what they do and what is happening (`kit.css`, `kit.js`, `kit-web.js`).** Kinds by importance (hero, soft, live beside primary, quiet, ghost, danger); a count badge, a status dot, a toggle's fill, a progress fill; attention (the one next step glows now and then); busy → a check, or a shake and red (`OpenVibeKitWeb.busy()`); hold-to-confirm for destructive buttons; icons that move by meaning. Every motion follows the motion setting. docs/kit.md#buttons. - **A panel window can be resized (`ov-window.js`).** `resizable: true` adds a corner grip that a mouse, a finger or a pen drags and the arrow keys move; the size is kept with the place per id. - **The composer carries its own look, and Vibe's Dock box is the same composer (`ov-composer.js`, `dock-vibe.js`).** Its styles moved out of `thread.css` into the script; Vibe's box gets drafts, "/" commands, the marks and settings, with `data-ovc-no-files` keeping its picture upload its own. (Was #458, never released.) - **Players start sooner (`player.js`, #454).** The poster stays until a frame is presented; preload follows the connection; battery-aware HLS attachment with a low first rung. docs/player-startup.md. - **No more macOS flakes from fixed sleeps (tests).** A browser test now checks the page with `eventually()` from browser-harness (it retries until the page is there, 5 s at most) instead of after a guessed sleep: 382 checks in 26 files, including menu-places-chrome, whose 180 ms sleep against a 140 ms debounce failed on the slow macOS runners and held back 4.202.0 and 4.203.0. `test/fixed-waits.test.js` keeps the count of sleep-then-check places at zero. - **`openvibe-shared/csp` (#455).** One place for the network's Content-Security-Policy pieces; `connectSources()` names Media, the composer's upload origin. ## 4.203.0 — 2026-11-11 - Dock conversations update edited messages and link cards live; authors can edit their own messages. ## 4.202.0 — 2026-11-11 **One field dropdown, one window for small interfaces, one user card, a measured page end, eight site groups, and the reveal remade.** - **An empty footer column is never drawn (`footer.js`).** A group with no heading or no links is left out instead of showing as an untitled "0 links" fold. - **One field dropdown (#447).** `ov-combo.js` adds async, grouped suggestions and optional creation; the composer handoff to Code and whole site names in the phone menu are included. - **One window (#451).** `ov-window.js` supplies dialog, sheet and panel modes, and the composer's settings use it. - **One user card (#452).** Shared mention hooks, the profile card, wallet window and display style settings. - **Page end (#442).** A shared bottom measurement keeps the end of a page at 32 px on computer and 24 px on phone. - **Eight site groups (#445).** The footer, rooms, You folders and home pages use the same groups. - **Reveal (#448).** Headings emerge from blur, rules draw, and up to six cards stagger as they enter view. - **Jump back in (#412).** The full history link and private history support are present from the 4.201.0 base. ## 4.201.0 — 2026-11-10 **Notifications move into the one menu; the mark and the name are one button; one composer and Code on every site.** From the owner's notes of 2026-11-10 (asks 334 to 350). - **The one menu's look (`search.js`).** Vibe's three parts (Chat, Code, Agents) sit in one row on a phone. Notifications in You have a head: their name, the red "n new", and Show all in the head instead of a dashed box under the list. The Timer under Vibe and the Dock's actions in You are rows with a glyph, not dashed folds. - **Notifications in You, no bell in the bar (`navbar.js`, `search.js`, `notification-ui.js`).** The bar's bell is gone: the signed-in picture wears the red unread count, and pressing it opens the menu's You at Notifications, on phones and computers alike (the menu's You tab wears the red count too). The notification read/unread BroadcastChannel keeps open tabs in sync. Feed keeps its calm new count and live dot, now synced across same-origin tabs by BroadcastChannel and the storage event; the menu button shows the Feed indicator too. Messages and Vibe stay inside the menu on phones and open the floating Dock on computers. The pressed bar button still flies into its tab (`OpenVibeSearch.open({ from })`, 4.200.0's flight kept whole). The menu's feed counts are the server half's (Network #790). - **A picture that cannot show becomes its initial (`footer.js`, ask 345).** Any `img[data-ov-initial]` that fails is replaced by its initial (a capture listener plus a sweep for early failures; CSP-safe). Footer faces and the account picture carry it: openvibe.locker's footer showed a broken avatar where five sites' `img-src` omit openvibe.media. - **The player on a phone (`player.js`, `player.css`, ask 288).** The phone rules lost to the bar's sizing block later in the file, so at 390 px the row ran ~50 px off screen. A last-in-file phone block: speed and PiP out, a 64 px slider, mute alone under 380 px, position alone under 360 px (the length is now its own span). 1280 px unchanged. - **The quest card module (`quest.js`, `quest.css`, `guide.js`).** The daily quest card from OpenVibe.Live's finished design, as a component any site can mount: `OpenVibeQuest.mount(host, { load })` returns `{ refresh, el }`, with the site fetching the quest shape its own way under the person's Network token. Signed out, `1 OF 3` with the streak chip, `DONE`; the next step marked, done steps checked. Scoped to `ovq-`, on the kit's tokens. - **Soft pages (`soft.js`).** Prefetch on intent (pointer down, or 80 ms of hover on a computer; never on Save-Data or 2G/3G, at most four in flight, never auth, posts, downloads, queries, anchors or `data-ov-no-prefetch`), a conservative prefetch-only speculation rule in Chrome/Edge, `OVMark.navStart('page')` on the press finished by the arriving page at first paint, and cross-document view transitions where they exist (the shared bar held still, the rest cross-fading 180 ms; Calm 120 ms; Off none). One opt-in line after `theme-loader.js`; not loaded by `navbar.js`, so a site that does not opt in is unchanged. `window.OpenVibeSoft = { on(), off(), exclude() }`. - **Updates (`shipped.js`, ask 341).** The filter chips ask the feed with `kind=` and carry their totals; Improved has no tag; empty kinds say so; commit hashes open on git.openvibe.codes. - **Icon ink normalised (`glyphs.js`, `nav-icons.js`, `kit.js`, `ov-glyphs.*`).** 666 drawings normalised to a 0.79 ink-size target; app tiles use a 0.58 painted-ink fraction and the old oversized tile rule is gone. Measured in headless Chrome at 96 px (painted ink bounds in `test/fixtures/icon-ink.json`), within 3% centre and 4% size. - **The Dock's browser test runs in two halves (`test/dock-chrome.test.js`, `test/dock-vibe-timer-chrome.test.js`).** The whole file took about 65 s and the runner stops a file at 60 s, so it timed out on the slower macOS machines. Its sections each open a fresh page: the first file runs the first half (`DOCK_CHROME_PART` 1, the default), the new second file sets it to 2; 0 runs both. - **The mark and the name are one button (`navbar.js`, `ov-drop.js`, `nav-slots.js`, ask 347).** The mark and the site's name are one 40 px button (46 px to tap) with a chevron: the accent tint on hover, a stronger tint with a ring while open. It opens the site's pages (Home first, the present page marked); "All OpenVibe sites" at the end opens the full menu on every site. The lead button a site draws (`nav-slots.js`) matches the menu button's size and corner. A site that turns the switcher off keeps the old links. - **One composer on every site (`ov-composer.js`, `ov-thread.js`, `thread.js`, `thread.css`, ask 349).** Every `thread.composer()` box — and any site's own form through `OpenVibeComposer.enhance(form)` — gets files (the + menu, paste and drop become chips: a thumbnail, the name and size, ×), `/` (the site's, its mods', the person's own, and settings) and `@` (the mods' mention sources), voice where the browser can listen, drafts per box for 7 days, and the person's settings under `/settings` (kept in this browser, and on their account once Network's composer route lands). `OpenVibeComposer.mod({ id, match, tools, commands, mentions, upload, beforeSend })` for mods. - **Vibe is Chat · Code · Agents (`search.js`, `dock.js`, `dock-code.js`, ask 350).** The menu's Vibe place holds three parts (your chats with Vibe, your coding tasks, your agents), and the Dock grows the same Code tab. `dock-code.js` gives one box to start a coding task the way openvibe.codes does (Create, OpenVibe, My code) with your latest tasks under it — state, repository, how long ago, and Stop — read through the Network's same-origin relay. - Budget: `dock.js` 20.51 KB brotli (budget 20.55 KB, was 20.45 KB) for the Code tab's mount branch; the tab itself ships in `dock-code.js`, loaded the first time it opens. `notification-ui.js` 25.72 KB (budget 25.75 KB, was 25.7 KB) for the one menu's notifications. The bar holds its 49.9 KB budget. ## 4.200.0 — 2026-11-10 **The button becomes its tab; Vibe holds Chat and Agents; every site from the site's name.** From the owner's notes of 2026-11-10 (asks 334 to 338). - **The button becomes its tab (`search.js`, `navbar.js`).** "When you click this button, I want it to animate into the tab it becomes. Same with the other buttons." The bar's button that was pressed (the menu button, the picture; the bell once it opens You) flies to its tab's icon in the menu and turns into it on the way: its own picture fades out as the tab's fades in, along one short arc, and the tab settles with a small give. The bell's count rides along to the tab's count. Closing flies it back into the bar. When a button flies, the sheet's close X is simply there (the menu button no longer travels to it). Motion Off skips it; Reduced plays it short and straight. A flying button is hidden by opacity, so a quick second press still lands on it. `OpenVibeSearch.open({ from })` takes the pressed element. - **Vibe, with Chat and Agents (`search.js`, `dock-vibe.js`).** The menu's "AI" place is called Vibe; its two-part switch is Chat · Agents (your chats with Vibe, and your agents). The list loses its "Vibe conversations" heading and the large "New conversation" button: a + icon (new chat) and an ↗ icon (open in OpenVibe.Chat) stand in for them. - **Chat, where it was Messages (`search.js`, `dock.js`).** The menu's Messages place is called Chat (on openvibe.chat itself, whose own tab is already "Chat", it keeps "Messages" so the row never shows one word twice). An ↗ icon opens OpenVibe.Chat over your conversations and in a thread; the footer that said the same in words is gone. The "AI chats" row among your conversations is "Vibe". The Dock's own tab is "Chat" too. - **A place's icons in the search pill (`search.js`).** Inside the menu, a place's icons (+ and ↗) sit in the search pill, left of the close button, so they cost no row; the floating Dock keeps them in a slim row of their own. The menu mirrors the panel's buttons and each mirror presses the panel's own. - **Every site from the site's name (`ov-drop.js`, `navbar.js`, `search.js`).** The dropdown under a site's name ends with "All OpenVibe sites", which opens the menu scrolled past the site's own pages to every site. The scroll had never run: the menu read the tab after "sites" had become "here". - **The site's name, highlighted (`navbar.js`, ask 342).** The name that opens its pages gets its highlight as a spread shadow with room around it (no added width, so the name still reads whole at 360 px): a faint tint on hover; open, a deeper tint with a hairline ring that comes up on a small spring. Motion Off keeps it still (the theme loader's rule). - **A quick close and reopen keeps the menu open (`search.js`).** Closing the menu steps back in history; that step's event arrives later and used to close a menu opened again in between. The menu now ignores the one step it took itself. - Budget: `dock.js` 20.43 KB brotli (budget 20.45 KB, was 20.30 KB) for the "Open in Chat" icon in the always-loaded Dock; the Vibe-only button rules stay in `dock-vibe.js`. ## 4.199.0 — 2026-11-10 **Every page downloads about 56 KB less: the shared files are served minified.** From the owner's notes of 2026-11-10: "Make sure everything loads … non-blocking asynchronously … minified". - **Served minified, cached by content hash (`serve.js`, new `minify.js`; OpenVibe.Shared #429).** Sites have no build step by choice, so the shared browser files are minified where they are served: terser for JavaScript, clean-css for stylesheets. It runs once per release per file, and the immutable `?v=` address does the rest. On 4.197.0's eager set (the bar, the theme, the footer, the kit and the rest) that is 806 KB → 523 KB raw and 189 KB → 133 KB after brotli, about 56 KB less per page view; `navbar.js` alone is 49.8 KB → 34.4 KB as delivered. A file the minifier cannot handle, or one that would not come out smaller, is served as it is; a minifier error never fails a request. ETag and `?v=` immutability are unchanged. Stylesheets are minified at clean-css level 1 only (inside each rule), never level 2, which moves and merges rules and could change which rule wins. New dependencies: `terser`, `clean-css`. - **Avatars reserve their box (OpenVibe.Shared #430).** The bar's, the footer's, the account switcher's and the user card's pictures carry their width and height and decode asynchronously (the footer's also load lazily, below the fold), so a signed-in page no longer shifts when the picture arrives. - Checked on production openvibe.chat with every shared file served minified, on a phone and a computer: the bar, the menu, Messages and AI inside it, the Dock; no page errors. ## 4.198.0 — 2026-11-10 **On a phone the menu is one sheet: Messages and AI open inside it.** From the owner's notes of 2026-11-10, with the menu and the Dock side by side: "combine and consolidate these two menus into one unified menu … easier to search between", and a phone picture of the Dock's own head over the menu ("Menu", "…", close, then four tabs: two rows of chrome). - **The menu (`search.js`).** On a phone, Messages and AI in the row of places no longer close the menu to open the Dock's second sheet. They open inside the menu, under its own head, and become the chosen place like Feed or You. AI carries a small two-part switch at its top: Vibe · Agents (your Actor is the top of Agents). Feed, Here or You, typing in the field, or closing the menu hand the Dock's panel back with its state. On a computer the two places still open the floating Dock, which stays beside the work. - **The Dock (`dock.js`, new `dock-mount.js`).** `OpenVibeDock.mountInto(host, { tab })` → `{ show(tab), destroy() }` shows one of the Dock's panels (chats, vibe, agents, activity) inside another sheet, with no head of its own: the same panel body, state, counts, token and loaders as the floating Dock, which closes while a panel is lent. The layout loads on first use (`dock-mount.js`), so `dock.js` stays inside its budget. Six mount and destroy laps leave no nodes or listeners behind (`test/dock-mount-chrome.test.js`). - **The agent view (`dock-agent.js`).** An ended session is two lines of words with its one button beside them (it sat alone on a third row), and the agent view's buttons are 44 px under a finger. - The bar's touch-feedback comment, which ships inside its styles, is one line now: the bar is back under its size budget with room for the next hashes. ## 4.197.0 — 2026-11-10 **The footer says "3 online", and the tooltip part works anywhere.** From the owner's notes of 2026-11-10: "Make it like shorthand '3 online'. If you put your mouse over it, it says 'last 30 minutes'". - **The footer's online strip (`footer.js`)** read "13 online in the last 30 min", then the faces, then "1 member · 12 guests". It now says **"13 online"** and the faces. Hovering the count (or reaching it with the keyboard) shows the one tooltip: "In the last 30 minutes", and under it how many are members and guests. A press opens the same words above the list of names, because a finger never sees a tooltip; with guests only, the count still opens that one line (before, a guests-only strip opened nothing). - **The tooltip part (`ov-tip.js`) loads at the first hover over anything that carries `data-ov-tip`**, not only over the bar: the footer's count, and whatever a site labels the same way. The waiting listener lives at module level, so it holds no bar that a soft navigation has replaced. - A test (`menu-places-chrome`) measured the menu's origin after a fixed wait and could read it mid-motion on a busy machine; it now waits for the motion to end. ## 4.196.0 — 2026-11-10 **Your Actor in the Dock, redrawn: one row and one line to type in. And a tone is a lean and a glow, never a bar.** From the owner's notes of 2026-11-10. - **The Dock's Actor block (`dock-actor.js`).** The owner, on the Agents tab on a phone: "improve the design and layout so it's more intuitive, minimalist, elegant". It was a row with two outlined pills ("Resume", "Open"), a grey box that said "Paused" a second time beside a green dot, the model and the cap in a sentence, a field with a "Send" pill and a "Read recent history" pill. Now: - **Who, in one row.** The face wears a ring in the colour of its state (green and breathing while it works, amber while it waits for you, dimmed when paused), then the name and one quiet line: the state, and today's spend against the cap ("Paused · $0.00 of $1.00 today"; the model is that figure's tooltip). The row is the link to the Actor's page, so "Open" is gone. - **One action, the one that fits.** "Resume" in the accent when the Actor is paused; a quiet pause button when it runs. What happened is said in one line under the field ("Resumed.", "Sent. Your Actor reads it at its next step.", or why it did not go through), in place of notes piling up at the bottom. - **What it does, only when there is something to say.** The step it is on (a soft pulse), what it is looking at, the steps before it and what comes next ("Next: … , in 40 min"), as a short line of dots. A paused Actor shows none of it, and the state words Actor sends as a step ("Paused", "Resting until the next goal is due.") are no longer drawn as one. - **What it asks you** sits in the warning tone (a lean and a glow), with its own buttons: the first in the accent, "Not now" as plain words, and "1 more on your Actor's page" as a link. - **One field to tell it something**, with send inside the field; it lights up when there are words in it. - **Built once.** A refresh (every 15 seconds) used to rebuild the whole block and wiped the line being typed; now it repaints the row, the steps and the ask only when the answer changed, and never touches the field. - "Recent history" is a quiet text button; the button that opens the list closes it, one line per entry. - **The agent view (`dock-agent.js`): no black box for a session that left no picture.** A session that ended with no still drew a 16:9 black stage saying "Nothing to show", which pushed the runs off a phone's screen. The stage is left out; the line under it still says what it was and how long it worked. - **The kit's tone (`kit.css`).** The owner, on a notice with a red bar down its side: "instead of just like this red and crappy border … blur maybe effect or shadow, glow". Notices and `.ovk-tone[data-tone=good|alert|warning]` take a tinted hairline, a gradient that leans from the corner, a soft glow under them and a round icon chip; no side stripe anywhere. ## 4.195.0 — 2026-11-10 **The You tab gets a row of its own, and the menu grows out of the button that was pressed.** From the owner's notes of 2026-11-10. - **The You tab: one slim row, and the old account block is gone from the menu.** The owner, with the block crossed out: "When I said integrate the user drop down into this menu, I didn't mean like this … get rid of this thing … We didn't really need the actual [block] here, other than like adding your account … making a new design for that." The row: your face and name, add or switch account, Display, Settings, Sign out (each a full touch target, with a tooltip). Under it, small, only what has no other home in the menu: this site's own items, your status, and Admin for an admin. History, Ask Vibe, Work, the Dock and the wallet are not repeated: they are tiles, the search box, the row of places and the balances pill. `navbar.js` hands the menu three small things (`me: { add, out, own }`) in place of its dropdown; `ov-home.js` draws the row. - **The menu grows out of the pressed button** ("go … to the proper element … what you clicked on, and be more aware … of positioning"). On a computer it unfolded from its left corner, though its button has been at the right since 4.193.0: its origin is now the pressed button's centre, wherever the sheet was clamped to, on the dropdown's own curve. - Tests: `menu-home-screen-chrome` and `navbar-ask-vibe` read the row (the old block and its grid are not in the menu); `menu-places-chrome` checks the sheet's origin against the pressed button. `navbar.js` is under its budget. ## 4.194.0 — 2026-11-10 **One row of places in the menu, a wallet that is there at once, and a Sign in that says so.** From the owner's notes of 2026-11-10. - **The menu's head is one row of five places** ("combine and consolidate these two menus into one unified menu … It just seems a little much with all the buttons on the first one … the agents and AI tools versus the feed and kind of community stuff"). This site · Feed · Messages · AI · You, in place of three tabs with a second row of four under them: on a phone each is its icon over its word, on a computer side by side. Messages and AI (Vibe and your agents) open the Dock on those places for now; their panels move into this sheet next. A visitor has this site, Feed and You, as before. The Dock draws Vibe as the spark and Agents as a robot, as the row does (the spark meant two things). - **The wallet sheet is there at once and nothing jumps** ("load faster and dynamically sync smarter … isn't so jumpy as it loads in, the different elements and balances"). It opens holding what it last showed in this tab, or room held for its three cards; the store and your items stand as placeholders of their size; the store, the kinds and the items are asked side by side with the balances (they waited for them before); each part arrives where it stands, once. What it keeps is the wallet's own answer in the person's tab, forgotten when the account changes. - **Sign in says "sign in"** ("should represent … that they need to sign in"). In the filled circle the figure and an arrow coming in through a door take turns (the arrow for a moment every six seconds); under the pointer it is the arrow, what a press does. Off shows the figure and does not move. - **The tooltip's file is fetched by the first pointer over the bar**, not with the page (it was fetched at once on any device that can hover); what that pointer rests on gets its tooltip when the file arrives. - Tests: `menu-places-chrome` (five places in one row signed in, the doors open the Dock, three for a visitor), the wallet's and the bar's. `dock.js` is 20.30 KB brotli (budget raised by 0.05 KB for the robot glyph, dated). ## 4.193.0 — 2026-11-10 **The bar's right end, one tooltip, and one frame for mail.** From the owner's notes of 2026-11-10. - **The menu button is at the right on a computer too** ("The menu button should be on the right, even on desktop … there's like a duplicated icon"). The orb at the bar's right is drawn on every width, and the one beside the name is not drawn where it is: the left end is the logo (the network's sites) and the name (this site's pages), the right end the menu and then the person. A second press closes the menu. - **Sign in is an icon** ("This can be majorly improved with a custom icon. Doesn't need the label really, and could have a tooltip"). A filled circle with a figure in it, the size of the picture it stands in for, in the readable accent pair; the figure arrives on load, lifts under the pointer, and the ring runs while the sign-in page opens. Its name is its own (`aria-label="Sign in"`) and its tooltip. A finger's area is 44 px and stays off the menu button's. - **New `ov-tip.js` (`OVTip`): the network's one small tooltip.** Anything with `data-ov-tip` (and an optional quiet second line, `data-ov-tip-sub`) gets a small card that grows out of what it names, under it or above, kept on the screen. A mouse sees it after a short rest (the next one at once), the keyboard's focus at once; a press, a scroll, Escape or leaving hides it; a finger never sees it, so nothing is said only there. The bar loads it where a pointer can hover; the menu button carries one too (its native `title` made a second, plain one). - **New `email.js`: one frame for every mail** ("Improve the entire email system so it uses openvibe.design … uses the theme applied by the user … explain more details … what they can do, what they can click"). `frame({ theme, site, tone, kicker, title, lead, body, facts, code, actions, next, why, manage, preheader })` returns `{ html, text }`: the person's theme written on the elements (all fifty read at 4.5:1 or better), a title that says what happened, the facts as a list, one button and quieter links, what happens next, and why it came. Text only and safe links only. A tone is never a hard coloured border ("instead of just like this red … border … shadow, glow"): the card leans toward the tone at its top and glows in it, the kicker is a pill with a round mark, the facts stand in a box with a tinted hairline. `palette(theme)` and `mix(a, b, t)` are exported for a site's own blocks. - **`mini.js` plays what the page plays.** Found on openvibe.video the hour it shipped: the page's script gives the video its streaming playlist, and one recording's plain file stopped with a decode error three seconds in. The small player now takes the playlist (`data-ov-mini-hls`) where the browser plays one by itself, in the page's cross-origin mode, and the plain file (`data-ov-mini-src`) otherwise; a playlist that fails gives way to the file at the same second. A video that cannot be played either says so ("Open its page to keep watching"), keeps the way back, and does not follow to the next page; it used to close without a word. - **The wallet says what a line was for** (OpenVibe.Shared #416, from the money-reasons work): the reason is a made sentence, linked to the thing it paid for. - The 4.192.0 entry's date is corrected (it said the 11th). - Tests: `ov-tip-chrome`, `email` (every theme, every tone), `mini-chrome` (the cannot-play state), `navbar-fit-chrome` (the menu button at the right at every width, no second one by the name), the tap-area tests with the round Sign in. ## 4.192.0 — 2026-11-10 **The video that comes with you.** The owner, 2026-11-10, with the browser's floating picture-in-picture window over a watch page: "should … actually [be] like YouTube where it moves that video. Now you go to the search again or the index … the homepage … it's just kind of confusing". - **New `mini.js` (`OpenVibeMini`): a small player of our own.** A watch page says its video may come along (`