>_EXECUTIVE SUMMARY
stryke-gui is one of the opt-in connector packages in the stryke ecosystem. Mouse motion / buttons / wheel, keyboard press / type / hotkey, screen size + bounds, pixel reads, screenshots, and clipboard — a PyAutoGUI-equivalent surface for stryke. Opt-in package, kept out of the stryke core binary so the daily-driver install stays slim and free of X11/Wayland system libraries. It ships as a Rust cdylib that stryke dlopens in-process on first use GUI; the native input/display code (enigo + xcap + arboard) lives in libstryke_gui.{dylib,so}.
Core stays small on purpose — most one-liner / awk-replacement work doesn't need a virtual-pointer driver or a screen-capture pipeline. enigo + xcap drag in the platform input/display stack (Wayland + xkb + dbus + PipeWire on Linux; CGEvent + ScreenCaptureKit on macOS), so they ship as an opt-in package.
~ARCHITECTURE
In-process cdylib design: the stryke side is a thin .stk wrapper that calls FFI symbols on the dlopen'd library. No subprocess, no pipe — calls return on the same thread that made them.
| Layer | Implementation |
|---|---|
stryke wrappers (lib/GUI.stk) | Thin wrapper exposing typed functions in the GUI:: namespace (use GUI); each JSON-encodes args, calls the FFI symbol, and parses the JSON return |
cdylib (libstryke_gui.{dylib,so}) | Single Rust cdylib crate; every export is an extern "C" fn gui__<verb>(*const c_char) -> *const c_char wrapping the mouse / keyboard / capture modules |
| Process model | Library is dlopen'd once per stryke session on first use GUI; the Enigo input handle persists in a process-global OnceCell<Mutex<Enigo>> (src/common.rs::enigo_lock) and is reused across calls; macOS reuses the parent terminal's Accessibility / Screen-Recording grant |
| Input synthesis | enigo 0.6 — macOS CGEvent, X11 XTest, Wayland virtual-pointer, Win32 SendInput |
| Display capture | xcap 0.9 — macOS ScreenCaptureKit, X11 XGetImage, Wayland portal, Win32 GDI |
| Build | Cargo with [lib] crate-type = ["cdylib"]; publish = false; the package itself ships via s pkg install -g . (or make install) |
| Install path | ~/.stryke/store/stryke-gui@<version>/ after make install; use GUI from any stryke script resolves it |
| Tests | Cargo unit tests under src/ (FFI plumbing, error-on-panic, free-cstring contract, region parsing — headless CI-safe) plus zunit-style t/test_gui.stk for the end-to-end stryke → FFI → cdylib call path |
| CI | GitHub Actions .github/workflows/ci.yml — cargo fmt + clippy + test, plus stryke pkg install verification |
$WHY OPT-IN (NOT BUILTIN)
The enigo (input) and xcap (capture) crates link against the platform input/display stack. On Linux that means the X11 and Wayland client libraries plus xkb, dbus, and PipeWire — a stack of -dev packages that would otherwise have to be installed before cargo install strykelang could even build. Baking them into core forces that cost on every user, GUI or not.
The trade-off is intentional. The core stryke binary stays slim precisely because each connector ships separately. Daily-driver work (one-liners, awk replacement, data scripting) doesn't need a virtual-pointer driver or a screen-capture pipeline linked in.
&FFI ENVELOPE
JSON in / JSON out across the FFI boundary. Each GUI::* wrapper serializes its args to a JSON string and calls the matching gui__* symbol resolved out of the dlopen'd cdylib; the cdylib returns a JSON CString the wrapper parses. Action calls (gui__mouse_move, gui__mouse_click, gui__key_type, gui__key_hotkey, …) return a success JSON; query calls return a structured payload. catch_unwind on every call converts panics to JSON errors; the returned CString is freed via the cdylib-exported free-cstring symbol, wired automatically by stryke's FFI loader.
| Query export | Response shape |
|---|---|
gui__mouse_pos | {"x":i64,"y":i64} |
gui__screen_size | {"width":i64,"height":i64} |
gui__on_screen | {"on_screen":bool} |
gui__pixel | {"r":u8,"g":u8,"b":u8} |
gui__pixel_matches_color | {"match":bool} |
gui__screenshot (no path) | {"width":u32,"height":u32,"rgba":[u8,…]} |
gui__screenshot (with path) | {"path":"PATH"} (PNG written to disk) |
gui__keyboard_keys | JSON array of recognized key names |
Failures come back as a {"error": "<msg>"} JSON payload and the .stk wrapper dies with the message.
# request shape (built by the .stk wrapper)
{"...": ...}
# response shape
{"result": ...} # success — per-fn shape
{"error": "<msg>"} # failure — wrapper die()s with the message
/SCOPE
The surface is a PyAutoGUI-equivalent — mouse motion / buttons / wheel, keyboard press / type / hotkey, screen size + bounds, pixel reads, and full or region screenshots. Coordinates use a top-left origin; the primary display only. Tweened motion runs at 60 fps via linear interpolation; duration ≤ 0 is a single-step warp.
The package exposes 69 public GUI:: functions (counted from lib/GUI.stk), backed by 60 gui__* cdylib exports in src/lib.rs — the difference is convenience wrappers (mouse_size, the right/middle/double/triple click and relative-drag/hscroll variants) that reuse a shared export. The surface divides into a device half (31 functions) and a pure half (38 functions) that runs headless with no display or permission gate.
| Category | Functions |
|---|---|
| Position & size | mouse_pos, screen_size, mouse_size, on_screen |
| Mouse motion | mouse_move, mouse_move_rel, mouse_drag, mouse_drag_rel |
| Mouse buttons | mouse_click, mouse_right_click, mouse_middle_click, mouse_double_click, mouse_triple_click, mouse_down, mouse_up |
| Mouse wheel | mouse_scroll, mouse_hscroll |
| Keyboard | key_press, key_down, key_up, key_type, key_hotkey, keyboard_keys |
| Pixel & screenshot | pixel, pixel_matches_color, screenshot, screenshot_region |
| Clipboard & displays | clipboard_get, clipboard_set, displays, display_screenshot |
| Pure hotkey helpers | parse_hotkey, format_hotkey |
| Pure color parse / compare | parse_color, format_color, color_distance, delta_e, contrast_ratio, relative_luminance, is_dark, name_color |
| Pure color transforms | mix, blend_lab, blend_oklab, gradient, rotate_hue, adjust_lightness, adjust_saturation, invert, grayscale, sepia, posterize, temperature, alpha_over, scheme |
| Pure color-space conversions | to_hsl/from_hsl, to_hsv/from_hsv, to_hwb/from_hwb, to_cmyk/from_cmyk, to_lab/from_lab, to_xyz/from_xyz, to_oklab/from_oklab |
See the README's API reference for the authoritative function list with per-field notes. The device half mirrors PyAutoGUI's shape so existing automation scripts port directly with GUI:: in place of pyautogui.; the pure color half has no PyAutoGUI counterpart.
+DEPENDENCIES
The cdylib pulls in the native input/display stack plus the JSON envelope crates. The release profile (Cargo.toml) builds with opt-level = 3, thin LTO, a single codegen unit, symbols stripped, and panic = "abort".
| Crate | Version | Role |
|---|---|---|
enigo | 0.6 | mouse + keyboard synthesis (CGEvent / XTest / Wayland virtual-pointer / SendInput) |
xcap | 0.9 | screen capture + pixel reads (ScreenCaptureKit / XGetImage / portal / GDI) |
arboard | 3 | cross-platform clipboard (NSPasteboard / X11+Wayland / Win32) |
image | 0.25 | PNG encode for screenshots (png feature only) |
serde / serde_json | 1 | JSON-over-FFI envelope (preserve_order on the JSON side) |
anyhow | 1 | error handling inside the cdylib |
once_cell | 1 | process-global persistent Enigo handle |
!PERMISSIONS
| Platform | Permission gate |
|---|---|
| macOS | First mouse/keyboard call prompts for Accessibility; first pixel/screenshot call prompts for Screen Recording. One-time grants for the terminal app running s, persisted in System Settings → Privacy & Security. |
| Wayland (Linux) | Requires the wlroots-virtual-pointer protocol (mouse/keyboard) and the org.freedesktop.portal.Screenshot portal (pixel/screen). The portal prompts on first capture. |
| X11 (Linux) | No permission gates. enigo uses XTest; xcap uses XGetImage. |
| Windows | No permission gates. enigo uses SendInput; xcap uses GDI. |
#PROJECT METADATA
| Item | Value |
|---|---|
| License | MIT |
| Author | MenkeTechnologies |
| Repository | github.com/MenkeTechnologies/stryke-gui |
| Parent language | strykelang |
| Meta umbrella | MenkeTechnologiesMeta |
| Issues | github.com/MenkeTechnologies/stryke-gui/issues |