- Stop the live OS click watcher during the selftest so the user's real
clicks (toast dismissal, terminal focus) can't add extra steps and
shift the marker comparisons.
- Inject clicks in physical pixels via dipToScreenPoint so the test
measures correctly on scaled Windows displays.
- Guard the marker report against step-count mismatches instead of
crashing on out-of-range indexing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Implements the architecture change from ai_prompts/prompt3.md:
- New app/click-frames.js: shared timestamped frame ring + strict
click-to-frame pairing (never a frame whose grab started after the
click); legacy slack behavior kept behind capture.strictClickFrames=false.
- New stream capture backend (app/stream-backend.js + hidden worker
window): per-display desktop media streams sampled into ring buffers
and PNG-encoded entirely off the main process, so click delivery is
never starved by capture work. Auto-degrades to the legacy in-process
frame loop when streams cannot start or the worker stops answering.
- Clicks are paired with their frame at event time (eager pairing in
enqueueClickCapture); only the storing is serialized, so slow encodes
cannot skew later clicks in a fast burst.
- Linux watcher: restored event-time root coordinates from
xinput test-xi2 and merge raw/regular twin events structurally.
- Replaced the 40ms time debounce with source-aware duplicate
suppression: fast legitimate clicks are never dropped.
- New app/coords.js: physical-to-DIP conversion with multi-monitor and
scale-factor handling; Windows keeps screenToDipPoint.
- STEPFORGE_CLICK_SELFTEST end-to-end hook: 3/3 clicks become steps via
the stream backend with 0.00% marker offset on this host.
- Tests rewritten/added: strict selection, coords, stream backend,
Linux coordinate parsing, twin merge, burst clicking (126 passing).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- New Capture sessions now start paused; the window only tucks away once
the user clicks "Start recording" in the capture bar instead of hiding
~1.2s after starting.
- The capture status bar is shown only in the editor view, not over the
library.
- Fix openModal/confirmDialog resolving as cancelled when an action button
is clicked, which made the step "Delete" button (and other modal actions)
silently no-op.
- Click-triggered captures now use the click-time cursor position for the
marker and arm the capture cache as soon as recording starts, so the
first click is captured instantly and accurately placed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Users couldn't click into the app mid-session: every automatic capture
hid the window for the shot, so it vanished under the cursor. Under
WSLg minimize() is a no-op and isFocused() sticks true, so neither can
be used for control.
- Sessions now hide the window once at start and show a red tray icon
with Capture now / Pause-Resume / Open StepForge (auto-pauses) /
Finish; finishing or quitting restores/cleans up properly
- Opening the app from the tray pauses capture; resuming tucks the
window away again
- Automatic captures skip while the cursor is over a visible StepForge
window (cursor-based, not focus-based, due to WSLg sticky focus)
- Per-shot latency reduced: with the window already hidden the 350 ms
hide-repaint wait is skipped entirely
- OS notification announces the session; self-tests updated and green
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The session previously only listened for the global hotkey, which is
unreliable under WSLg/Wayland — users got one screenshot and nothing
more. Sessions now layer three triggers:
- click-capture via OS adapters (xinput test-xi2 on X11, PowerShell
GetAsyncKeyState polling on Windows), debounced, ignoring clicks on
StepForge itself
- interval auto-capture (3/5/10 s) as the always-works fallback,
enabled by default when click detection is unavailable
- the existing global hotkey, plus a manual Shoot button
The REC bar now shows live count + active trigger with Shoot / Auto /
Pause / Finish. New captures and added steps are selected in the
editor (explicit reload(stepId) wins over a surviving selection).
Capture self-test hook (STEPFORGE_CAPTURE_SELFTEST) verifies 3x
hotkey-path captures and interval capture end-to-end.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bug fixes from code review:
- Wrap renderer modules (canvas/dialogs/editor/app) in IIFEs: duplicate
top-level 'const api' across plain scripts threw a SyntaxError that
prevented app.js from ever running (blank window), and dialogs.js/
editor.js silently overrode each other's labeledRow/makeSelect
- Focused-view toggle now writes step.focusedView.enabled instead of a
nonexistent flat field that the schema dropped on save
- Annotation property edits no longer rebuild the panel on every
keystroke (focus was stolen mid-typing); debounced save instead
- flushStep/undo/redo keep this.steps in sync with stepMap so the step
list stops going stale after the first save
- Escape now deselects the annotation; Delete remains the delete key
Welcome screen (per spec): app opens to a title at top and three
buttons at the bottom — New Capture (creates a guide, opens the editor,
starts a capture session), Existing Workspace (library), Settings.
Brand click returns to the welcome screen.
Adds an env-gated dev screenshot hook (STEPFORGE_SCREENSHOT[_JS]) used
to visually verify welcome/library/editor views under WSLg.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>