hoijunkim.github.io/flip · Releases
Pick a region of your screen. flip captures it, sends the page-turn key to the window you chose, waits for the redraw to settle, and repeats - then hands you a folder of images or an assembled PDF.
Windows only. Single executable, no runtime dependencies, no cgo.
flip is one .exe. There is no installer.
- Download
flip-v<version>-windows-amd64.zipfrom the releases page. - Right-click the zip > Properties > Unblock, then extract
flip.exe. - Run it.
The build is not code-signed, so Windows SmartScreen warns on first run:
More info > Run anyway. That is expected for an unsigned exe from a small
project; verify the download against the published .sha256 if you want
certainty.
Home > Target (pick the window to capture) > Region (drag a box over
the page; a live heatmap shows what is changing so you can keep a blinking
toolbar or caret outside it) > Settings (speed, format, spread splitting) >
Preflight (one test capture, checked for capture protection and integrity) >
Run (a five-second countdown to click the target, then flip shrinks to a
small always-on-top widget and works through the pages) > Results (reorder,
delete, and export to images or a PDF). Ctrl+Shift+F9 aborts a run at any
time.
flip does not work around capture protection. A DRM reader (some ebook viewers) tells Windows not to let its window be captured, so it reads as solid black - flip detects that at preflight and stops. Use it on content that is yours to reproduce.
In development. Plans 1 through 6 of 8 are merged, plus a design pass and this
brand/distribution work in progress. The capture foundation
(internal/capture), internal/detect's tile fingerprint and page-advance,
settle and blank decision rules, internal/session's capture-loop state
machine, Win32 input and window targeting (internal/input, internal/winfo,
internal/hotkey), and post-processing and export (internal/postproc,
internal/export, internal/exportpipe) - spread splitting, margin trim,
aspect crop, resize, and JPEG/PNG/BMP/PDF output, driven end to end by
flipdbg run and flipdbg export.
Plan 6 adds a Wails GUI over the same internal/exportpipe pipeline: seven
screens (Home, Target, Region, Settings, Preflight, Run, Results) covering
target/region selection, a live difference heatmap while dragging a region,
the run itself, and a results screen with reorder, delete and export. Settings
includes spread splitting - split mode, reading order and a cut offset - the
same internal/postproc.Split flipdbg export -split already used, now
reachable from the GUI rather than the CLI alone. internal/app/e2e_test.go
drives the whole flow - region, config, a scripted document through the run
goroutine, results, a reorder, a delete, and an export - in Go, with no screen
and no Win32 target, and asserts the exported files and their order.
A later design pass reworked the frontend into flip's own instrument look (a
calibration-teal-on-graphite token system, the platform's Segoe UI for chrome
and a mono face for every measured number, a centred responsive layout, both OS
themes) and added a compact capture widget: while actively capturing, flip
shrinks to a small always-on-top readout parked off the region's monitor, so its
own window is not read into the pages, and restores the moment interaction is
needed. The logo is a dog-eared page, rendered onto the app icon by a pure-Go
supersampling renderer in internal/brand.
go test ./... and the frontend's Vitest suite are green, including the
end-to-end test above, and cover every stage's own logic plus that one
composed flow. What they do not cover:
- No frame from a real document viewer has been through the detector or the capture loop. Plan 4 named four manual gates - the physical-pixel coordinate identity through a real region drag, a real capture-target selection, a full document run against a real viewer, and the settle detector's behaviour against a real redraw - and they are still open. Plan 6 makes them easier to run (a GUI to click through, instead of the CLI alone); it does not close them.
- The heatmap countermeasure - the region selector's live difference overlay - is unverified. It responds to a measured problem (a small toolbar repaint reads as statistically indistinguishable from a real content change of the same size), but whether showing a user what blinks actually lets them avoid it is something only real use will say.
maxTilemay be doing nothing. One real-pixel reading (Plan 4) found it far above its own idle threshold whilechangedsat far below its threshold; if that holds against a real document viewer,Advanced's two-clause rule may be effectively one clause with a decoration. Not changed in this plan - measure first.- Nothing about the frontend's look and feel is verified beyond
type-checking (
svelte-check) and its own unit tests (vitest, pure logic only - no component-level or visual testing). Whether a drag feels right, whether Settings' split controls read clearly, whether the status panel dodges the capture region - all of that needs a person looking at it. - CI (
.github/workflows/ci.yml) has not yet executed on this project's account - its Actions budget is exhausted. Every step (format, the dependency cap, vet, the Go build/test matrix, the frontend's Vitest suite and build, and the production-tagged GUI build) has instead been run locally, against a clean checkout equivalent, as each plan lands.
flip reads pixels that are already rendered and visible on your screen. It does
not work around windows that have opted out of screen capture via
SetWindowDisplayAffinity, and it does not try to hide that its keystrokes are
synthetic. When it detects either, it stops and tells you which one it hit.
A viewer with a large blinking text-cursor caret can defeat the settle
detector: the caret toggling reads as continuous change, the page never
measures as settled, and every page trips the no-change budget - the
symptom is zero pages captured, then "end of document?" after about 7.5
seconds, on a document that plainly has more pages. Use flipdbg detect
against the viewer to measure whether your caret falls in the affected range
before reporting this as a bug.
Requires Go 1.26.4 on Windows.
go test ./...
go build -o flipdbg.exe ./cmd/flipdbg
flipdbg is a debug harness for the capture layer, and also flip's own CLI
front end for driving a capture end to end:
flipdbg monitors # list displays, bounds, DPI
flipdbg dpi # DPI awareness and refresh rate
flipdbg grab -r 0,0,800,600 -o out.png # capture a region
flipdbg detect -r 0,0,800,600 # poll a region, print the detector's verdict
flipdbg windows [-all] # list windows a capture could target
flipdbg sendkey [-vk 0x22] [-w 5s] # send an advance keystroke to a window you pick
flipdbg run -hwnd 0x... -r 0,0,800,600 [-out DIR] [-format jpg] [-pdf FILE]
# capture a document end to end: turn pages,
# poll for settle, stop at -max or end of document
flipdbg export -in DIR [-out DIR2] [-pdf FILE] [-split half] [-trim] [-long 2000]
# post-process and assemble a directory of
# spooled PNGs, with no capture involved
Run any subcommand with -h for its full flag list.
Coordinates are physical pixels on the virtual screen. Monitors left of or above the primary monitor have negative coordinates.
Building or testing the frontend needs Node (the frontend's own package.json
and package-lock.json are under frontend/) and the
Wails CLI - frontend/wailsjs/ (the generated JS/TS
bridge every screen imports from) is gitignored and regenerated, not tracked,
so it has to exist before npm run build or npm run check will resolve:
go install github.com/wailsapp/wails/v2/cmd/wails@v2.12.0 # matches go.mod's wails/v2 version
wails generate module # writes frontend/wailsjs/
cd frontend
npm install
npm run test -- --run # Vitest - pure logic only (frontend/src/lib), no component/visual tests
npm run check # svelte-check
npm run build
wails build -tags production # or: go build -tags production -o flip.exe . after npm run build
A plain go build ./... (no build tag) compiles internal/app/app_default_windows.go,
a stub that shows a Win32 error dialog and exits - useful for confirming the
cgo-free build stays green without a Node/npm setup, not for running the real
GUI.
- Spec:
docs/superpowers/specs/2026-07-28-flip-design.md - Plans:
docs/superpowers/plans/
