Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
61a04fe
WIP: media lane (previous agent's uncommitted work, as found)
siyabendoezdemir Oct 9, 2026
b58ffe2
Merge origin/main (Spaces, PR #3) into lane/media
siyabendoezdemir Oct 9, 2026
09f7493
WIP: Orbit floating player in main (borrowed tab view, geometry, cont…
siyabendoezdemir Oct 9, 2026
6f263cc
WIP: floating player view and controls, long video fixture, player e2…
siyabendoezdemir Oct 9, 2026
4556b43
WIP: player lifts the video only at its own size, black view backgrou…
siyabendoezdemir Oct 9, 2026
495ce43
Merge remote-tracking branch 'origin/main' into lane/media
siyabendoezdemir Oct 9, 2026
ac9333d
feat(media): Back to tab flies the video home; Back to PiP grows from…
siyabendoezdemir Oct 9, 2026
6fee8da
Merge remote-tracking branch 'origin/main' into lane/media
siyabendoezdemir Oct 9, 2026
a5e0089
fix(media): a late resize from the tab's window no longer cancels the…
siyabendoezdemir Oct 9, 2026
676cd1a
docs(media): status notes describe Orbit's own player; SB-10 and KS-1…
siyabendoezdemir Oct 9, 2026
3cbe082
test(media): zoom the player with the platform modifier (Cmd on macOS)
siyabendoezdemir Oct 9, 2026
1e1234d
test(commandbar): CB-04 measures the bar at rest
siyabendoezdemir Oct 9, 2026
9b51615
split: a full split row is no drop target; SV-26 test can't race or hang
siyabendoezdemir Oct 9, 2026
3d7bca9
fix(media): PR #9 review fixes (reduced motion, media in frames, page…
siyabendoezdemir Oct 9, 2026
88c081a
Merge origin/main (PRs #6 and #7) into lane/media
siyabendoezdemir Oct 9, 2026
8edc3e5
fix(split): a Favorite split never comes apart past 12 Favorites (FV-…
siyabendoezdemir Oct 9, 2026
f755593
test(e2e): start each main-process evaluate in a task of its own
siyabendoezdemir Oct 9, 2026
6d73442
test(tabs): the favicon tests' servers listen on port 0
siyabendoezdemir Oct 9, 2026
5335293
Merge origin/main (PR #8, Peek and Mini Window) into lead/polish2
siyabendoezdemir Oct 9, 2026
1c14d54
docs(architecture): why e2e evaluates start in a task of their own (D25)
siyabendoezdemir Oct 9, 2026
0a63ed6
test(e2e): keep tests offline behind a dead proxy
siyabendoezdemir Oct 9, 2026
f8a1988
test(e2e): every test server listens within ports 3300-3399
siyabendoezdemir Oct 9, 2026
369a98f
test(media): MD-04 compares the elapsed time with the video; MD-07 le…
siyabendoezdemir Oct 9, 2026
2fbe461
Merge origin/main (PR #8, Peek and Mini Windows) into lane/media
siyabendoezdemir Oct 9, 2026
4fe445a
fix(main): log exceptions nothing caught; Electron's modal error box …
siyabendoezdemir Oct 10, 2026
5efc435
test(mini-window): a command that closes the Mini Window may close it…
siyabendoezdemir Oct 10, 2026
721fdc8
test(split): the views-over-panes poll waits for a pane that is still…
siyabendoezdemir Oct 9, 2026
13a2494
fix(split): the pane strip's timers stop when its window closes; a fa…
siyabendoezdemir Oct 10, 2026
3942167
fix(favorites): Duplicate, Open in Split View, reopen and undo never …
siyabendoezdemir Oct 10, 2026
d2e4b8d
test(spaces): SP-21 waits until the new row takes presses (PR #10 rev…
siyabendoezdemir Oct 10, 2026
7eaec40
Merge remote-tracking branch 'origin/lead/polish2' into lead/quit
siyabendoezdemir Oct 10, 2026
504872a
fix(e2e): the quit check finds an uncaught exception in a long log (P…
siyabendoezdemir Oct 10, 2026
d19b9da
ci: pin the Linux jobs to ubuntu-24.04 before ubuntu-latest moves to …
siyabendoezdemir Oct 10, 2026
45a85b1
Merge remote-tracking branch 'origin/lane/media' into HEAD
siyabendoezdemir Oct 10, 2026
da6a207
test(e2e): media's fake-device launch goes through launchOrbit, so it…
siyabendoezdemir Oct 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ env:
jobs:
checks:
name: Typecheck, lint, unit tests
runs-on: ubuntu-latest
# Pinned: `ubuntu-latest` moves to Ubuntu 26 from 2026-10-19. The e2e job's apt packages
# (xvfb, libasound2t64) are only known to work on 24.04.
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
Expand All @@ -42,7 +44,7 @@ jobs:

e2e-linux:
name: E2E (Linux, Xvfb)
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
timeout-minutes: 25
steps:
- uses: actions/checkout@v4
Expand Down
50 changes: 25 additions & 25 deletions FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@

Every row is one behaviour from the clean-room spec. Status per ID: **spec’d** (every row) → **built** → **tested** (a unit or e2e test names the ID) → **feels right** (lead sign-off after a hands-on review against `feel.md`).

**Totals:** 485 spec’d · 140 built (45 partial) · 189 tested · 0 feel right.
**Totals:** 485 spec’d · 146 built (57 partial) · 208 tested · 0 feel right.

| Priority | Spec’d | Built | Tested |
|---|---|---|---|
| ? | 7 | 0 | 0 |
| P0 | 174 | 97 | 118 |
| P1 | 221 | 39 | 66 |
| P2 | 83 | 4 | 5 |
| P0 | 174 | 101 | 127 |
| P1 | 221 | 40 | 75 |
| P2 | 83 | 5 | 6 |

P0 = milestone-1 core experience, P1 = parity, P2 = later.

Expand All @@ -30,7 +30,7 @@ Spec: `spec/sidebar.md`
| SB-07 | "+ New Tab" row | P0 | ✅ | ✅ e2e | – | + New Tab row with press animation opens the command bar |
| SB-08 | Empty sidebar area: double-click, drag, right-click | P1 | – | – | – | |
| SB-09 | Bottom bar: Library, Space switcher, "+" menu | P0 | 🟡 partial | ✅ e2e | – | switcher and + menu done; Library button arrives with the archive lane |
| SB-10 | Transient trays above the bottom bar | P1 | – | – | – | |
| SB-10 | Transient trays above the bottom bar | P1 | 🟡 partial | ✅ e2e | – | media tray and call controls (media lane), above the bottom bar, pushing the list up; download progress and the update banner belong to other lanes |
| SB-11 | Show / hide the sidebar | P0 | 🟡 partial | – | – | scaffold |
| SB-12 | Hover to reveal the hidden sidebar | P0 | – | – | – | |
| SB-13 | Feedback when things happen while the sidebar is hidden | P1 | – | – | – | |
Expand Down Expand Up @@ -70,8 +70,8 @@ Spec: `spec/tabs.md`
| TB-12 | Rename a tab and set a custom icon | P1 | ✅ | ✅ e2e | – | double-click/menu rename, empty reverts; emoji icon picker |
| TB-13 | Multi-select tabs | P1 | 🟡 partial | ✅ e2e | – | Cmd-click, Shift-click ranges, Escape/plain click clears; Cmd+W, Copy URL, menu pin/unpin/move/new folder and group drag act on the selection; open-as-split is the split lane's |
| TB-14 | Tab context menu | P0 | 🟡 partial | ✅ e2e | – | native menus with every tab, pinned, Favorite, folder and multi-selection item; not theme-coloured; split/share items belong to other lanes |
| TB-15 | Audio, mute, microphone/camera and screen-share indicators | P1 | 🟡 partial | ✅ e2e | – | audio icon toggles mute; no mic/camera/screen-share indicators |
| TB-16 | Tab sleeping and background resource limits | P1 | 🟡 partial | ✅ e2e+unit | – | sleep timer (settings.sleepAfterMs), Favorites warm 4x, audible/selected never sleep |
| TB-15 | Audio, mute, microphone/camera and screen-share indicators | P1 | 🟡 partial | ✅ e2e | – | audio icon toggles mute; camera/microphone indicator (media lane); no screen-share indicator or Favorites notes |
| TB-16 | Tab sleeping and background resource limits | P1 | 🟡 partial | ✅ e2e+unit | – | sleep timer (settings.sleepAfterMs), Favorites warm 4x; selected, audible, playing (muted too), PiP and camera/mic tabs never sleep |
| TB-17 | Tabs across multiple windows | P1 | 🟡 partial | ✅ e2e+unit | – | tab handoff; no two windows ever show the same tab (close, Clear, archive, moves, undo, drag-out); no blank window yet |
| TB-18 | Undo sidebar actions | P1 | ✅ | ✅ e2e+unit | – | Cmd+Z undoes moves, close, Clear, archive below, renames, icons and folder changes (page text fields keep their own undo); Cmd+Shift+Z redoes moves, closes and renames |
| TB-19 | Back on a fresh child tab returns to its opener | P2 | 🟡 partial | ✅ e2e | – | Back with no history closes a link-opened Today tab and selects its opener (shortcut/command) |
Expand Down Expand Up @@ -306,22 +306,22 @@ Spec: `spec/media.md`

| ID | Feature | P | Built | Tested | Feels right | Notes |
|---|---|---|---|---|---|---|
| MD-01 | Automatic picture-in-picture when leaving a video tab | P0 | – | – | – | |
| MD-02 | Open picture-in-picture manually | P1 | – | – | – | |
| MD-03 | The floating player's look and placement | P0 | – | – | – | |
| MD-04 | Floating player controls | P0 | – | – | – | |
| MD-05 | Keyboard and media keys for the floating player | P1 | – | – | – | |
| MD-06 | Move, resize and zoom the floating player | P1 | – | – | – | |
| MD-07 | Ending picture-in-picture | P0 | – | – | – | |
| MD-08 | Turning automatic picture-in-picture off | P0 | – | – | – | |
| MD-09 | Sidebar media controls for background audio | P0 | – | – | – | |
| MD-10 | Several players: the media tray | P1 | – | – | – | |
| MD-11 | Audio and recording indicators, mute | P0 | – | – | – | |
| MD-12 | Media and the tab lifecycle | P0 | – | – | – | |
| MD-13 | Video calls: automatic call picture-in-picture | P1 | – | – | – | |
| MD-14 | Call controls in the sidebar | P1 | – | – | – | |
| MD-01 | Automatic picture-in-picture when leaving a video tab | P0 | 🟡 partial | ✅ e2e+unit | – | Orbit's own floating player: leaving a tab whose main video plays (tab, Space or split change; the largest playing video) moves it there within ~300 ms, still playing; not when paused, muted or turned off (MD-08); selecting the tab again puts it back in the page with no blank frame; moving between a split's panes doesn't float it; media inside frames (embedded players) isn't seen yet: no automatic PiP, and its controller has only Go to tab and Close, which leaves it playing |
| MD-02 | Open picture-in-picture manually | P1 | 🟡 partial | ✅ e2e | – | Picture in Picture in a video's page right-click menu, the Picture in Picture action and the tray's PiP button; while the tab stays selected the engine's own PiP window shows the video (Orbit's player needs the tab's view), so its controls are the engine's until the tab is left and Orbit's player takes over |
| MD-03 | The floating player's look and placement | P0 | ✅ | ✅ e2e+unit | – | frameless, always-on-top window, 320x180 for 16:9 (keeps the video's shape), bottom-right 16 px inside the work area; rounded corners (a window shape where the system has none) and shadow; video only until hovered, then controls over a dark gradient; the same player on every platform |
| MD-04 | Floating player controls | P0 | ✅ | ✅ e2e+unit | – | on hover: play/pause, +/-15 s, progress with elapsed and total time (seekable; LIVE badge for streams), Back to tab (selects it in its window and Space), x (keeps playing in the sidebar), ... menu (playback speed, turn off today / always for the site), previous/next for Media Session pages; double-click goes back to the tab |
| MD-05 | Keyboard and media keys for the floating player | P1 | 🟡 partial | ✅ e2e | – | with the player focused (clicked) Space plays/pauses and arrows seek 5 s (tested); hardware media keys go through Chromium's media key handling to the playing page, not verifiable under Xvfb |
| MD-06 | Move, resize and zoom the floating player | P1 | 🟡 partial | ✅ e2e+unit | – | drag or two-finger hover-scroll moves it and it glides to the corner the release or fling heads for; corner drag resizes keeping the shape, at least 200 px wide (tall videos too) and at most half the screen width and the screen's height, with rubber-band resistance; Cmd/Ctrl+scroll or pinch zooms (crops) inside the window; corner and size remembered; doesn't yet move aside for Orbit's alerts and dialogs |
| MD-07 | Ending picture-in-picture | P0 | ✅ | ✅ e2e | – | returning (select, double-click, Back to tab) ends it with the video playing in the page; x closes it and the media keeps playing in the sidebar controls; closing or unloading the tab stops media and player; navigating the tab or the video ending closes it, without replay |
| MD-08 | Turning automatic picture-in-picture off | P0 | 🟡 partial | ✅ e2e+unit | – | player ... menu Turn Off for Today / Always Turn Off for This Site (also in the tray controller menu); global switch (settings.autoPip, Picture in Picture action); turning off keeps playback (sidebar controls); muted tabs never trigger; the site controls checkbox (SB-04) and Settings > Advanced (ST-10) belong to other lanes (media.setSitePip and the setting are ready) |
| MD-09 | Sidebar media controls for background audio | P0 | 🟡 partial | ✅ e2e+unit | – | controller above the bottom bar: favicon, Media Session title/artist or tab title (marquee), play/pause, next, previous where supported, x pauses and hides; click jumps to the tab (switching Space); quiet audio counts; hidden while its tab is selected; no artwork yet; media inside frames (embedded players) isn't seen yet: no automatic PiP, and its controller has only Go to tab and Close, which leaves it playing |
| MD-10 | Several players: the media tray | P1 | ✅ | ✅ e2e+unit | – | one controller per background tab, newest first, appears and disappears by itself, works across windows; a video's controller has Picture in Picture (Back to PiP): the player grows out of the controller while the controller gives way |
| MD-11 | Audio and recording indicators, mute | P0 | 🟡 partial | ✅ e2e | – | pulsing camera/microphone indicator on tab rows (tracks the page shows); per-pane Mute/Unmute in the split row's menu (split lane's menu, tested here: only that pane goes silent); no screen-share indicator; no switcher indicators (TB-05 has no overlay yet) |
| MD-12 | Media and the tab lifecycle | P0 | ✅ | ✅ e2e+unit | – | playing (muted too), PiP and camera/mic tabs never sleep, auto-archive, Clear or Archive Below; closing stops media, PiP and controller; isAnyMediaPlaying() is ready for the updates lane |
| MD-13 | Video calls: automatic call picture-in-picture | P1 | 🟡 partial | ✅ e2e | – | leaving a call tab floats the largest participant video (never the self view) in Orbit's player with microphone/camera toggles and Back to call tab; moves and resizes like any video; no document picture-in-picture, leave-call or chat toggle |
| MD-14 | Call controls in the sidebar | P1 | 🟡 partial | ✅ e2e+unit | – | a background call tab (or a closed call window) gets a sidebar call controller: microphone and camera toggles (track.enabled on the tracks the page shows) and jump back; detection needs the page to show its own camera (a self view) |
| MD-15 | Switch which tab is being screen-shared | P2 | – | – | – | |
| MD-16 | Feel: entering and leaving picture-in-picture | P1 | – | – | – | |
| MD-16 | Feel: entering and leaving picture-in-picture | P1 | 🟡 partial | ✅ e2e+unit | – | enter: the video shrinks from its place in the page to the corner (~300 ms, standard curve); Back to tab/double-click: the tab is selected at once and a still of the last frame flies back into the page; release glides to the corner; Back to PiP grows from the controller; tray slides with the snappy spring; with reduced motion (FL-28) the player appears and goes without motion and a release settles with a 120 ms ease-out; no haptic tick on macOS |

## Archive, recently closed, history and sidebar backups (prefix AR)

Expand Down Expand Up @@ -357,7 +357,7 @@ Spec: `spec/shortcuts.md`
| KS-08 | Page navigation and page tools | P0 | – | – | – | |
| KS-09 | Split view | P0 | – | – | – | |
| KS-10 | Peek and Mini Window | P1 | – | – | – | |
| KS-11 | Media | P1 | – | – | – | |
| KS-11 | Media | P1 | 🟡 partial | ✅ e2e | – | Space and arrows in the focused player, Cmd/Ctrl+scroll and pinch zoom (tested), hardware media keys via Chromium (untested), Mute Tab action assignable; the calendar meeting shortcut (P2) belongs to TB-21/FV-09 |
| KS-12 | Library, history, downloads, settings, extensions, help | P1 | – | – | – | |
| KS-13 | Developer tools | P1 | – | – | – | |
| KS-14 | Canvases, notes, capture and Tweaks | P2 | – | – | – | |
Expand Down Expand Up @@ -401,11 +401,11 @@ Spec: `spec/feel.md`
| FL-25 | Menus, popovers and tooltips | P1 | – | – | – | |
| FL-26 | Recent-tab switcher (Ctrl+Tab) | P1 | – | – | – | |
| FL-27 | Window-level motion | P1 | – | – | – | |
| FL-28 | Reduced motion | P0 | – | – | – | |
| FL-28 | Reduced motion | P0 | – | ✅ e2e+unit | – | |
| FL-29 | Responsiveness budgets (input to visual) | P0 | – | – | – | |
| FL-30 | What makes it feel native and smooth | P0 | – | – | – | |
| FL-31 | Haptics (macOS trackpads) | P2 | – | – | – | |
| FL-32 | Picture-in-picture and media tray motion | P2 | – | – | – | |
| FL-32 | Picture-in-picture and media tray motion | P2 | ✅ | ✅ e2e+unit | – | corner resize follows the pointer, resists past its limits (rubber band) and springs back on release; a fling heads for the corner in its direction and settles with the spring; tray slides up with the snappy timing; Back to tab flies to the video's place; pinch zooms (MD-06) rather than resizes |

## Appearance (global)

Expand Down
2 changes: 1 addition & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ Rules: no synchronous disk I/O on hot paths after boot, no full-state broadcasts
## 9. Testing and CI

- **Unit** (`vitest`): shared logic (tree moves, URL parsing, accelerators, theme math, persistence normalization), main-process models with fakes. Fast; run on every commit.
- **E2E** (`@playwright/test` `_electron`): `tests/e2e/helpers.ts` launches the built app with an isolated `userData` and `ORBIT_E2E=1`. That exposes `globalThis.__orbit` test hooks in main (state, view bounds, run command) and serves local fixture pages from a loopback HTTP server, so there's no network dependence. **Every test title starts with the feature IDs it covers**, e.g. `test('[TB-06][TB-07] close and reopen a tab', …)`. `scripts/features.mjs` reads those IDs to mark rows tested in `FEATURES.md`.
- **E2E** (`@playwright/test` `_electron`): `tests/e2e/helpers.ts` launches the built app with an isolated `userData` and `ORBIT_E2E=1`. That exposes `globalThis.__orbit` test hooks in main (state, view bounds, run command) and serves local fixture pages from a loopback HTTP server. The app runs behind a dead local proxy that loopback bypasses, and `launchOrbit` waits until every profile's session uses it, so a test that searches or follows a link to a real site gets the URL but loads nothing. Playwright reaches main through the inspector, which can interrupt main-process code part-way, even inside a store update. So `launchOrbit` makes each `app.evaluate` start in a task of its own, and the hooks' `run` and `action` defer the same way (D25). Main logs an exception nothing caught as `[orbit] uncaught exception:` rather than letting Electron show its modal box, which blocks quitting. `app.close()` fails a test whose main process logged one (`takeUncaught()` claims one thrown on purpose), and kills an app that hasn't quit 15 s after being asked (D28). **Every test title starts with the feature IDs it covers**, e.g. `test('[TB-06][TB-07] close and reopen a tab', …)`. `scripts/features.mjs` reads those IDs to mark rows tested in `FEATURES.md`.
- **CI** (`.github/workflows/ci.yml`): typecheck + lint + unit (Linux), e2e under Xvfb (Linux), and build + unit + e2e + unsigned `.dmg`/`.zip` packaging (macOS). Green CI is required before merge.
- **Feel checks and clips**: `scripts/capture/record.mjs <scenario>` drives the built app through `scripts/capture/scenarios/<scenario>.mjs` while ffmpeg (`ORBIT_FFMPEG`, needs x11grab) records the X display, so native tab views are captured exactly as composited. Clips are named by feature ID and stored in `clips/` in the Orca context directory, screenshots in `screenshots/`. "Feels right" in `FEATURES.md` is a lead sign-off against `feel.md`.

Expand Down
Loading