// STRYKE-GUI — ENGINEERING REPORT

Opt-in stryke connector package · cdylib libstryke_gui.{dylib,so} (crate-type = cdylib) · dlopen'd in-process on use GUI · JSON-over-FFI envelope

>_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.

cdylib
Crate type
opt-in
Tier
dlopen
Load model
JSON-over-FFI
Envelope
enigo + xcap + arboard
Native deps
3
Platforms (macOS / Linux / Windows)
69
Public GUI:: functions
31 / 38
Device fns / pure helpers

~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.

LayerImplementation
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 modelLibrary 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 synthesisenigo 0.6 — macOS CGEvent, X11 XTest, Wayland virtual-pointer, Win32 SendInput
Display capturexcap 0.9 — macOS ScreenCaptureKit, X11 XGetImage, Wayland portal, Win32 GDI
BuildCargo 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
TestsCargo 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
CIGitHub 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 exportResponse 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_keysJSON 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.

CategoryFunctions
Position & sizemouse_pos, screen_size, mouse_size, on_screen
Mouse motionmouse_move, mouse_move_rel, mouse_drag, mouse_drag_rel
Mouse buttonsmouse_click, mouse_right_click, mouse_middle_click, mouse_double_click, mouse_triple_click, mouse_down, mouse_up
Mouse wheelmouse_scroll, mouse_hscroll
Keyboardkey_press, key_down, key_up, key_type, key_hotkey, keyboard_keys
Pixel & screenshotpixel, pixel_matches_color, screenshot, screenshot_region
Clipboard & displaysclipboard_get, clipboard_set, displays, display_screenshot
Pure hotkey helpersparse_hotkey, format_hotkey
Pure color parse / compareparse_color, format_color, color_distance, delta_e, contrast_ratio, relative_luminance, is_dark, name_color
Pure color transformsmix, blend_lab, blend_oklab, gradient, rotate_hue, adjust_lightness, adjust_saturation, invert, grayscale, sepia, posterize, temperature, alpha_over, scheme
Pure color-space conversionsto_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".

CrateVersionRole
enigo0.6mouse + keyboard synthesis (CGEvent / XTest / Wayland virtual-pointer / SendInput)
xcap0.9screen capture + pixel reads (ScreenCaptureKit / XGetImage / portal / GDI)
arboard3cross-platform clipboard (NSPasteboard / X11+Wayland / Win32)
image0.25PNG encode for screenshots (png feature only)
serde / serde_json1JSON-over-FFI envelope (preserve_order on the JSON side)
anyhow1error handling inside the cdylib
once_cell1process-global persistent Enigo handle

!PERMISSIONS

PlatformPermission gate
macOSFirst 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.
WindowsNo permission gates. enigo uses SendInput; xcap uses GDI.

#PROJECT METADATA

ItemValue
LicenseMIT
AuthorMenkeTechnologies
Repositorygithub.com/MenkeTechnologies/stryke-gui
Parent languagestrykelang
Meta umbrellaMenkeTechnologiesMeta
Issuesgithub.com/MenkeTechnologies/stryke-gui/issues