release: Mark VIII 1.0

This commit is contained in:
c4ch3c4d3
2026-08-11 20:24:24 -07:00
commit 3e1805dab8
86 changed files with 20678 additions and 0 deletions
@@ -0,0 +1,185 @@
# Virtual Pager Dock — Design Spec
- **Date:** 2026-08-11
- **Status:** Approved
- **Owner:** WiFi Pineapple Pager expansion project
- **Applies to:** `payload/user/general/pager-webui/www/` (front-end only) and
`scripts/dev_proxy.py` (dev config)
## 1. Goal
Add a **Virtual Pager** button in the topbar next to the existing **Terminal**
button in the Pager WebUI (`http://172.16.52.1:8080/`). Clicking it opens a
bottom-docked panel that shows a live, interactive replica of the Pager device:
the physical-device graphic with the real-time screen in the middle and
clickable directional/A/B buttons — matching the virtual pager view of the
Pager's stock UI at `http://172.16.52.1:1471/`.
Behavior mirrors the existing Terminal dock: open/close toggling, docked panel,
connect/disconnect of WebSockets on open/close.
## 2. Stock UI Reference (verified 2026-08-11)
Source: `http://172.16.52.1:1471/` (captured to
`%TEMP%\opencode\pager-virtual-pager.html`, 141,707 bytes).
### 2.1 Connections
- Screen: `ws://<host>:1471/api/pager/display/screen.ws` — streams binary RGBA
framebuffer frames. Requires the daemon `AUTH_<serverid>` cookie; returns
`401 Unauthorized` without it.
- Keys: `ws://<host>:1471/api/pager/input/keys.ws` — text frames; same cookie.
- Both handshakes verified returning `101 Switching Protocols` with a valid
`AUTH_<serverid>=<token>` cookie.
- Cookies are host-scoped (not port-scoped), so a browser that has logged into
`172.16.52.1:8080` already sends the cookie to `172.16.52.1:1471`. This is the
same mechanism the existing Terminal WS uses (direct `:1471` connection, no
backend relay), and requires **no backend changes**.
### 2.2 Screen framebuffer
- Resolution `480 × 222`, stride `480 * 4 = 1920`, expected
`1920 * 222 = 426,240` bytes per frame (4 bytes/pixel RGBA).
- Client renders each frame: copy RGBA into a hidden 480×222 canvas
(`createImageData`/`putImageData`), `canvas.toDataURL('image/png')` into the
`<img id="pager">` screen element.
### 2.3 Buttons / keys
Button image click sends these strings over the keys WS:
| Control | Sent key |
|-----------|------------------|
| LEFT | `ArrowLeft` |
| UP | `ArrowUp` |
| RIGHT | `ArrowRight` |
| DOWN | `ArrowDown` |
| A | `Enter` |
| B | `Escape` |
Physical keyboard: when the pager screen is focused (or body, with no other
control focused) the stock UI sends `e.key` on keydown (no repeats). Buttons
show a brief `.pressed` feedback (brightness filter).
### 2.4 Device graphic
`<table id="pager_ui">` (745 × 531) built from 24 image slices +
`spacer.gif`, button images `LEFT.png`, `UP.png`, `RIGHT.png`, `DOWN.png`,
`A_Button.png`, `B_Button.png`, and a 480×222 screen surface with hidden canvas
and a `#pager_error` overlay. Images are static and fetchable without auth from
`http://172.16.52.1:1471/images/`. Identical files already exist in
`wifipineapplepager/payloads/library/user/remote_access/nautilus/www/images/`
(sizes match byte-for-byte); they will be copied from there and hash-verified
against the stock UI.
Scaling: the stock UI scales the graphic with CSS `zoom` (`scale =
min(1, availableWidth / 745)`), `transform-origin: top center`.
## 3. Design
### 3.1 index.html
- Add `#pager-btn` ("Virtual Pager", `btn ghost`) next to `#terminal-btn`.
- Add `#pager-panel` dock after `#terminal-panel`, mirroring its structure:
- `#pager-bar` — title "Virtual Pager" + `#pager-close` button.
- `#pager` content area containing the pager graphic table with the live
screen, hidden canvas, and error/retry overlay.
- Load `js/pager.js` after `js/terminal.js`.
### 3.2 app.css
- `#pager-btn`: same style as `#terminal-btn`; `.active` state for both.
- `#pager-panel`: fixed bottom dock like `#terminal-panel` but `height: 540px`;
reuses the `term-up` slide-in animation and a shared `.dock` utility where
practical. Content centered; overflow hidden.
- Pager graphic scale-to-fit: a wrapper whose `zoom`/transform scales the
745×531 graphic to the available panel width, never upscaling
(`scale = min(1, availableWidth / 745)`), per §2.4.
- `.pager-btn` cursor/`user-select`/pressed feedback (stock rules).
- `#pager_error` overlay styles (centered, dark overlay, Reconnect button).
### 3.3 js/pager.js (new, mirrors js/terminal.js)
Module `Pager` with:
- `SCREEN_WIDTH = 480`, `SCREEN_HEIGHT = 222`, `FB_STRIDE = 1920`.
- `ensure()` — lazily grab `#pager-panel`, canvas, `<img id="pager">`, build the
graphic table (static innerHTML from bundled images), wire button clicks.
- `toggle()` — show/hide `#pager-panel`, toggle `#pager-btn.active`,
connect/disconnect.
- Screen WS: binary `event.data``new Uint8Array(buffer)`
`renderRGBAFrame(bytes)` (reject frames `< FB_STRIDE * SCREEN_HEIGHT`).
On error/close: hide screen, show error overlay with Reconnect.
- Keys WS: `sendKey(name)` helper; button clicks send the §2.3 strings.
- Keyboard: a `keydown` listener active only while the dock is open; skips when
focus is in an INPUT/TEXTAREA/SELECT or the terminal; captures
ArrowLeft/ArrowUp/ArrowRight/ArrowDown/Enter/Escape (preventDefault on the
arrows to stop page scroll) and sends them via keys WS. Letter shortcuts
(D/C/P/R/L/M) and backtick (terminal toggle) keep working — backtick closes
the pager dock via the replace-on-open behavior.
- `disconnect()` closes both WS.
- `window.addEventListener('resize')` re-applies scale-to-fit while open.
### 3.4 app.js
- Wire `#pager-btn` and `#pager-close` to `Pager.toggle()` (guarded with
`typeof Pager === 'undefined'` like the terminal).
- **Replace-on-open:** a small helper `showDock(name)` that, when opening
`pager`, calls `Term.close()` if `Term` is defined and its panel is open, and
vice versa. Refactor the terminal wiring to go through `showDock('terminal')`
so both directions use the same rule. (`Term` gains a `close()`/`isOpen()`
helper in `terminal.js`.)
- Keyboard shortcut `g` (or none) is not required; the button is the entry
point. Backtick toggles the terminal and closes the pager dock (per
replace-on-open).
### 3.5 config.js / dev_proxy.py
- `config.js`: add `pagerScreenWs: ''`, `pagerKeysWs: ''`.
- `app.js`: read `cfg.pagerScreenWs || ('ws://' + location.hostname +
':1471/api/pager/display/screen.ws')` and the keys equivalent; expose as
`App.pagerScreenWs` / `App.pagerKeysWs`.
- `dev_proxy.py` `_serve_dev_config`: emit both fields pointing at the pager
host (same shape as `terminalWs`).
### 3.6 Assets
- Copy from the nautilus payload into `www/assets/pager/`:
`virtual_pager_01..24.png`, `LEFT.png`, `UP.png`, `RIGHT.png`, `DOWN.png`,
`A_Button.png`, `B_Button.png`, `spacer.gif`.
- Hash-verify each against the stock UI (`http://172.16.52.1:1471/images/…`)
during implementation; if any differ, use the stock bytes instead.
### 3.7 Error handling
- Screen WS error/close: show `#pager_error` ("Lost connection to virtual
pager") with a Reconnect button that calls `connect()`.
- Keys WS is best-effort: if not OPEN, button presses are ignored (stock
behavior).
- If WS construction throws (unreachable daemon), write a message into the
error overlay rather than throwing in app.js.
## 4. Testing
- **Unit (Python):** none required — no backend changes.
- **Static review:** `pager.js` frame renderer bounds check; button→key mapping
table; keyboard guard conditions; replace-on-open logic.
- **On-device smoke (per §8 of the main webui spec):**
1. Log in at `http://172.16.52.1:8080/`; Virtual Pager button present next to
Terminal.
2. Open Virtual Pager: dock slides up, screen streams live, graphic scales to
fit width.
3. Click LEFT/UP/RIGHT/DOWN/A/B — screen responds; physical arrow/Enter/Escape
also drive it; typing in an input/terminal does not.
4. Open Terminal while Pager open → Pager dock closes (replace-on-open) and
vice versa.
5. Kill/reconnect network to the daemon → error overlay + Reconnect recovers.
6. Backtick still toggles the terminal and closes the Pager dock.
## 5. Out of scope
- The stock page's embedded shell terminal and terminal-shortcut grid (the
WebUI already has a Terminal dock).
- The Pager Skinner / virtual-pager theme features.
- Any backend relay for the pager WS (direct `:1471` connection, same as the
Terminal).