| 2026-09-18 |
GIF fallback raised to the same 768px crop as the video
...
Frame cap lowered 240 -> 150 so the heavier 768px GIF stays under the
server's 25MB upload limit.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
14 hours ago
|
Cursor marker in recordings + higher encode quality
...
- CDP screencast frames don't include the OS pointer, so the GIF and
WebM encoders now paint a classic white arrow (dark outline) at the
interpolated cursor position — the crop centers on it, so it stays
in frame
- screencast JPEG quality 55 -> 70
- VP8 bitrate ~0.3 bits/px/frame (cap 8 Mbps) for sharper output
- verified with the real built offscreen encoder: synthetic green
frames + known track land the arrow within 3px of the true cursor
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
14 hours ago
|
Video in report details + 768px cursor crop quality
...
- web panel: screen recording now plays in the Details tab (large
video card), removed from the Attachments thumbnails to avoid
showing it twice
- screencast cap raised 1280 -> 2560 so wide viewports keep the
cursor crop at native resolution (user viewport 2552 was scaled
down to 1280, halving the video size)
- crop raised 512 -> 768 CSS px; GIF fallback stays at 512
- VP8 bitrate now scales with output size (~0.18 bits/px/frame,
capped at 4 Mbps) instead of a fixed 1 Mbps
- e2e ffprobe assertion updated to the 768px cap
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
15 hours ago
|
Recording submits at stop; composer edits the report by token
...
An MV3 service worker is killed after ~30 s of idle time, so parking the
recording buffer in background memory (pending + 10-min auto-save timer)
was unreliable: the timer never fired and Save could hit a restarted
worker with an empty buffer. Now recorderStop uploads the media, submits
the report with the auto-title right away, and only then opens the
composer. Save patches title/description (PATCH /api/reports/{token}),
Discard deletes the report — both are token-based and survive worker
restarts. recorder_submit is replaced by recorder_edit/recorder_discard
{token}.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
15 hours ago
|

Project switcher in popup, pending-recording composer, cursor-crop video
...
- Popup: project dropdown (list_projects + settings_save defaultProjectId);
switching refreshes the last-report card and panel link immediately.
- Recording stop no longer submits blindly: the buffer goes pending and a
composer opens in the tab with title (prefilled) + description, Save
(Ctrl+Enter, copies the share link) or two-step Discard; unanswered
pending recordings auto-save after 10 minutes, and starting a new
recording auto-saves a pending one. Composer survives navigation.
- WebM is now a square cursor-following crop (shared cursorCropRect helper
with the GIF path), source dimension raised to 1280 so the 512px crop is
native-resolution at DPR 1; full-frame 800px stays as fallback.
- e2e: second project + popup switcher asserts, composer save (typed
title/description verified on server), keyboard-driven discard flow,
ffprobe square-video assertions (512x512 VP8).
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
16 hours ago
|
| 2026-09-17 |

Record silent WebM screen video instead of GIF during recordings
...
The recorder now captures continuous screencast frames via the CDP
screencast API and encodes them into a silent WebM (VP8, ~15 fps, capped
at 800px wide) uploaded as recording.webm. WebCodecs VideoEncoder is not
exposed to service workers, so encoding runs in an offscreen document
(chrome.offscreen) fed by base64 frame batches over a runtime port; the
result is verified with a local <video> playback probe and falls back to
the cursor-following GIF when encoding or verification fails (Firefox,
old Chrome, broken output).
Root cause of the earlier corrupt output: webm-muxer silently produces a
broken file when the first chunk's timestamp is non-zero — media
timestamps now start at the first frame and the muxer uses
firstTimestampBehavior: "offset".
The e2e now validates the uploaded recording with ffprobe (vp8 codec,
positive duration) and still covers the GIF fallback path, console-step
dump, navigation survival and replay.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

Record screen video around the cursor + console dump per recording
...
The recorder now captures continuous screen video instead of single frames
per event. captureVisibleTab is quota-limited to ~2 shots/sec, so the video
rides a CDP screencast (Page.startScreencast) over the chrome.debugger
connection: frames arrive throttled to ~15 fps, decimated past 600 to bound
memory. At submit, the GIF is cropped to a 512×512 square centered on the
cursor position from the mouse track at each frame's time, paced by real
frame gaps — a "video" of exactly the area the tester was looking at.
Firefox and a busy debugger degrade to the old per-event screenshots; the
video path is a videoCapture setting (default on, like hoverReplay).
Console errors now ride along with recordings: a MAIN-world document_start
tap wraps console.error/warn and the uncaught error/rejection handlers,
posts through the relay content script, and lands as "console" timeline
steps (capped at 200, text truncated at 2000 chars). New consoleCapture
setting; the server schema, shared types and the panel timeline (warning
icon) accept the new step type; replay counts such no-effect steps as
played so the played/total summary stays honest.
E2E generates a console error + warning mid-recording, asserts the console
steps, and validates the GIF header: 512px wide with 3+ frames.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

Replay hover events: synthetic mouse family + CSS :hover via debugger API
...
The virtual cursor now dispatches the full mouse event family as it walks
the recorded path — mouseover/mouseenter on the new target, mouseout/
mouseleave (non-bubbling) on the previous one, relatedTarget wired up, and
throttled mousemove — so JS hover handlers stay live during replay.
CSS :hover can't be triggered by synthetic events, so when the hoverReplay
setting is on (default) the background attaches chrome.debugger to the
replay tab and mirrors cursor positions as trusted Input.dispatchMouseEvent
mouseMoved commands (~20 Hz), which light up real :hover styles. Firefox has
no debugger API and another debugger may hold the tab — both degrade
gracefully to JS-level hover only. New "debugger" permission; toggle in the
options page.
E2E now latches both hover kinds on the test page (sticky mouseover flag +
rAF-sampled :hover poll) and asserts the synthetic family; the CSS check is
reported but stays non-fatal since the debugger can be legitimately absent.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
Recorder survives page navigation, cursor clock sync, initial page_url
...
- Background reinstalls the capture listeners (and recorder bar) in
every new document while a recording is active, so a full page
navigation no longer resets the track; pending input debounces and
the mouse-track tail are flushed on pagehide so "type, then
navigate" keeps the input step
- The report's page_url now stays the URL where recording started
(replay opens that page; the rest of the path lives in url_change
steps)
- Replay: after a url_change step the new document gets its content
script and cursor back, resuming the mouse path from the current
step (replay_start now takes a from_t offset); after every executed
step the background nudges the cursor clock toward the gap-capped
step clock (max 400 ms per nudge) so the virtual mouse no longer
drifts behind the actions
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

Record the mouse path and play it back with a virtual cursor
...
- Recording: content script samples mousemove at ~25 Hz (2 px / 40 ms
thresholds), batches it to the background every second and before
submit; stored as reports.mouse_track (viewport + points, capped and
decimated server-side) via a new alembic migration
- Replay: a virtual cursor (overlay arrow) walks the recorded path,
scaled to the current viewport, dispatching synthetic mousemoves so
JS hover handlers stay live; clicks snap the cursor to the target
- Replay errors: page-load timeout aborts with a clear message, a
closed tab aborts, per-step failures (missing elements) are
collected, reported in the flash and in the replay result
- Panel: "Start replay" button on recording reports talks to the
extension through a new tiny relay content script (window messages,
no extension-id config), with presence check and toasts for
missing extension / no response / partial replay (en + ru)
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
Extension: popup UI, panel URL, icon fix, GIF tracks and track replay
...
- Popup replaces the auto-start picker: mode choice (element note /
record steps), latest report card with open / replay / delete, web
panel link; share links open at panelUrl (default :5173)
- Register the Phosphor font via the FontFace API — constructable
stylesheets ignore @font-face, which left overlay icons empty
- Recorder tracks upload as one animated GIF (gifenc) instead of per-
step screenshots; frames follow event pacing, UI hidden on capture
- Replay a recorded track from the popup: background opens the start
page, re-executes click/input/url_change steps with original pacing
and flashes the result in the overlay
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
Extension popup: mode choice, latest report, panel link; auto-copied share links
...
- Toolbar click now opens a popup instead of jumping straight into the
picker: two mode buttons (element note / record steps with live step
count), the latest report of the default project with open and
two-step delete, and an "Open web panel" shortcut to the project page.
- New background messages (start_picker, toggle_recorder, latest_report,
delete_report, open_panel) resolve the active tab themselves; the
action.onClicked path stays for keyboard-driven flows.
- Settings gain panelUrl (falls back to serverUrl); options page gets a
"Web panel URL" input.
- After a note is submitted its share link is copied to the clipboard
automatically (with an execCommand fallback) and a brief toast
confirms it; e2e asserts the clipboard content.
- Build: new popup entry (own CSS chunk), manifest default_popup.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
Bigger editor canvas, larger annotation text, plugin UI hidden in captures
...
- Fullscreen editor: toolbar and Save/Cancel now float above the canvas,
which takes the entire window (1344x896 vs 1147x765 at 1440x900).
- Extension composer widened to 1100px, drawing area raised to 62vh.
- Text tool renders ~2.4x larger (strokeWidth * 12, min 24px); size
slider now goes up to 20.
- Screenshots never contain the plugin's own UI: the background hides the
overlay host around every captureVisibleTab (covers region capture,
full-page tiles and recorder step screenshots); the region selector
keeps it hidden for the whole stitch via a refcounted module.
- e2e saves a step screenshot for inspection; fixed its file download to
resolve attachment id -> file id.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
Extension onboarding: warn when signed out, first-run click opens settings
...
- NoteComposer shows a warning banner with an "Open settings" button when
there is no session or no default project (background: open_options)
- Toolbar click opens the options page instead of the picker until the
user is signed in with a default project
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

Extension: picker, note composer, recorder + infra (Makefile, prod compose, README)
...
- MV3 extension for Chrome and Firefox: single codebase, per-entry IIFE
builds (background / content / options), manifests generated per target
- Background service worker owns all networking (Bearer token from
storage.local), captureVisibleTab (windowId!), recorder event buffer
with offset_ms and auto-screenshots on clicks
- Content overlay in a closed shadow root (constructable stylesheets,
kit CSS fetched from assets/style.css with /assets URL rewrite);
PickerLayer, NoteComposer (autofocus, Ctrl+Enter submit),
RecorderBar (step counter, note, stop)
- Options page: server URL, login, default project
- Recorder steps link screenshots by uploaded file id (server accepts
attachment id or file id); environment/element JSONB serialized with
mode="json" (datetime captured_at broke inserts)
- e2e harness: headless Chromium + extension, note + recording flows
- Makefile, docker-compose.prod.yml (caddy :8081 + static panel),
deploy/Caddyfile, README (ru) with extension install and /assets notes
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|