H-M-H/Weylus
Use your tablet as graphic tablet/touch screen on your computer.
Mixed signals — read the receipts
weakest axisnon-standard license (Other)
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 2w ago
- ✓12 active contributors
- ✓Other licensed
Show all 7 evidence items →Show less
- ✓CI configured
- ✓Tests present
- ⚠Concentrated ownership — top contributor handles 74% of recent commits
- ⚠Non-standard license (Other) — review terms
What would change the summary?
- →Use as dependency Concerns → Mixed if: clarify license terms
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/h-m-h/weylus)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/h-m-h/weylus on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: H-M-H/Weylus
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/H-M-H/Weylus shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Mixed signals — read the receipts
- Last commit 2w ago
- 12 active contributors
- Other licensed
- CI configured
- Tests present
- ⚠ Concentrated ownership — top contributor handles 74% of recent commits
- ⚠ Non-standard license (Other) — review terms
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live H-M-H/Weylus
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/H-M-H/Weylus.
What it runs against: a local clone of H-M-H/Weylus — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in H-M-H/Weylus | Confirms the artifact applies here, not a fork |
| 2 | License is still Other | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 45 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of H-M-H/Weylus. If you don't
# have one yet, run these first:
#
# git clone https://github.com/H-M-H/Weylus.git
# cd Weylus
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of H-M-H/Weylus and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "H-M-H/Weylus(\\.git)?\\b" \\
&& ok "origin remote is H-M-H/Weylus" \\
|| miss "origin remote is not H-M-H/Weylus (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
&& ok "license is Other" \\
|| miss "license drift — was Other at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "src/main.rs" \\
&& ok "src/main.rs" \\
|| miss "missing critical file: src/main.rs"
test -f "src/weylus.rs" \\
&& ok "src/weylus.rs" \\
|| miss "missing critical file: src/weylus.rs"
test -f "src/websocket.rs" \\
&& ok "src/websocket.rs" \\
|| miss "missing critical file: src/websocket.rs"
test -f "src/capturable/mod.rs" \\
&& ok "src/capturable/mod.rs" \\
|| miss "missing critical file: src/capturable/mod.rs"
test -f "src/input/mod.rs" \\
&& ok "src/input/mod.rs" \\
|| miss "missing critical file: src/input/mod.rs"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 45 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~15d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/H-M-H/Weylus"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Weylus is a cross-platform (Linux/macOS/Windows) application that turns tablets and smartphones into graphic tablets and touch screens for computers via WebSocket-based screen mirroring and input redirection. It captures the host screen in real-time using hardware-accelerated video encoding (FFmpeg with libva/NVENC support) and streams it to a browser on the remote device, while accepting stylus pressure, tilt, multi-touch, and keyboard input back through a web interface. Hybrid architecture: core application in Rust (src/) with C libraries for system capture and input (lib/linux/xcapture.c, lib/linux/uinput.c for Linux, platform-specific paths), managed through build.rs and cc crate. Frontend is a TypeScript/HTML/CSS web UI served by Hyper HTTP server, with WebSocket upgrade via fastwebsockets for real-time input/screen streaming. src/capturable/ abstracts multiple backends (X11, Wayland/PipeWire, Windows DXGI, macOS Core Graphics, remote_desktop_dbus) behind a unified interface.
👥Who it's for
Artists and designers using drawing applications (Krita, Xournal++) who want pen pressure sensitivity and multi-touch input from their tablet, plus casual users wanting a second wireless display—primarily Linux users who benefit from stylus and multi-touch support, but also macOS and Windows users seeking a free hardware tablet alternative.
🌱Maturity & risk
Actively maintained and production-ready: v0.11.4 released, has CI/CD via GitHub Actions (build.yml), Docker support for reproducible builds, and a clear release history on the releases page. Linux support is most mature with stylus/pressure/multi-touch; Windows and macOS are functional but with fewer features. The codebase shows consistent updates (recent Cargo.lock and Cargo.toml pins suggest active dependency management).
Single-maintainer risk (repo under H-M-H GitHub account). Moderate dependency surface: pulls in Tokio, Hyper, GStreamer, and FFmpeg (via deps/ scripts), plus platform-specific deps (winapi on Windows, dbus/gstreamer on Linux). The deps/ folder with manual patch management (command_limit.patch, awk.patch) and hash validation (update_hashes.sh) suggests FFmpeg and codec library build complexity could break on new system versions. No visible unit tests in the file structure (no tests/ directory or test markers in src/).
Active areas of work
No specific recent changes visible in the file list alone, but the repo structure shows active maintenance of multi-platform support and hardware encoding. The Cargo.toml pins recent stable versions (tokio ^1, hyper ^1.4, clap 4.5.18, image ^0.25), indicating ongoing dependency updates. Docker support (Dockerfile, Dockerfile_alpine) suggests containerized CI/build infrastructure is being used.
🚀Get running
git clone https://github.com/H-M-H/Weylus.git
cd Weylus
cargo build --release
# On Linux, ensure uinput is enabled: see README for details
./target/release/weylus
Daily commands:
cargo run --release
The app starts a native GUI (FLTK-based) and an embedded HTTP server on port 1701 by default. Open browser to http://localhost:1701 to access the web interface.
🗺️Map of the codebase
src/main.rs— Entry point for the application; initializes CLI parsing, server startup, and GUI setup — essential for understanding application bootstrap flow.src/weylus.rs— Core application logic orchestrating capture, encoding, WebSocket communication, and input handling — the heart of the tablet-to-computer bridge.src/websocket.rs— WebSocket server implementation handling real-time communication between tablet client and desktop; critical for input/output streaming.src/capturable/mod.rs— Abstract interface for screen capture across platforms (X11, Wayland, macOS, Windows); pluggable platform abstraction layer.src/input/mod.rs— Input device abstraction (mouse, keyboard, stylus) with platform-specific implementations; required for understanding how tablet input reaches the OS.src/video.rs— Video encoding pipeline interfacing with FFmpeg via C bindings (lib/encode_video.c); handles screen-to-stream transformation.Cargo.toml— Rust dependency manifest defining external crates (hyper, fastwebsockets, fltk, autopilot); tracks all build-time requirements.
🛠️How to make changes
Add a New Screen Capture Backend for a New Platform
- Create a new module in src/capturable/my_platform.rs implementing the Capturable trait (frame capture, resolution query, error handling) (
src/capturable/mod.rs) - Add a conditional pub mod my_platform; block and match clause in the impl Capturable factory function in src/capturable/mod.rs (
src/capturable/mod.rs) - Add platform detection logic to src/main.rs or src/weylus.rs to select your backend at runtime (
src/main.rs) - If using native APIs, create lib/my_platform/capture.c and add C binding declarations in build.rs under cc::Build (
build.rs)
Add Hardware Acceleration for a New Encoder (GPU, CPU-specific)
- Extend the encoder enum and codec selection logic in src/video.rs to detect and initialize your encoder (e.g., HEVC on Apple, NVENC variants) (
src/video.rs) - Update lib/encode_video.c to add your hardware encoder initialization function (e.g., av_hwdevice_ctx_create for a new device type) (
lib/encode_video.c) - Modify deps/ffmpeg.sh to include build flags for your encoder library (e.g., --enable-nvenc, --enable-hevc-videotoolbox) (
deps/ffmpeg.sh) - Test with cargo build and verify encoder fallback logic gracefully degrades if hardware is unavailable (
src/video.rs)
Add a New Input Gesture or Input Device Type (Tablet Buttons, Pressure Levels)
- Extend the protocol message types in src/protocol.rs to represent the new gesture or input event (e.g., tablet button bitmask, pressure normalization) (
src/protocol.rs) - Update ts/lib.ts to capture and serialize the new input event from the tablet's native touch/pointer APIs and send it via WebSocket (
ts/lib.ts) - Extend src/weylus.rs to unpack the new message type and dispatch to src/input/mod.rs (
src/weylus.rs) - Implement handling in src/input/uinput_device.rs (Linux) or src/input/autopilot_device.rs (macOS/Windows) to translate to OS input events (e.g., uinput_abs_event for pressure) (
src/input/uinput_device.rs)
Add a New Configuration Option (Server Port, Encoding Quality, Capture Resolution)
- Define the new field in src/config.rs struct Config and add a clap CLI argument in src/main.rs (
src/config.rs) - Pass the config value through src/weylus.rs to the module that needs it (e.g., src/video.rs for quality, src/web.rs for port) (
src/weylus.rs) - Optionally expose the setting in src/gui.rs as an FLTK UI input field if it should be user-adjustable at runtime (
src/gui.rs) - Update README.md with documentation on the new flag or config file parameter (
Readme.md)
🪤Traps & gotchas
- Linux uinput requirement: running on Linux without uinput device permissions or CONFIG_UINPUT in kernel breaks stylus/pressure/multi-touch—README mentions this but easy to miss
- FFmpeg build complexity: deps/build.sh downloads FFmpeg, libva, x264, NV codec headers with custom patches; failures here are environment-specific and not caught until compile time
- Hardware encoding fallback: if GPU encoding (VA-API/NVENC/VideoToolbox) unavailable, defaults to CPU encoding—no warning, just slow performance
- WebSocket port binding: Hyper server binds to 1701 by default; firewall rules or port conflicts silently prevent remote connections
- Platform-specific GStreamer/dbus: Linux builds need GStreamer 1.16+ and dbus; Windows/macOS don't require these but tests won't catch missing Linux deps
- Tokio runtime requirement: uses tokio multi-threaded runtime; any blocking code in capture loops can starve other async tasks
- No test suite visible: no tests/ directory or #[cfg(test)] markers found—changes risk regressions, especially on non-primary platforms (Windows, macOS)
🏗️Architecture
💡Concepts to learn
- Video Encoding Hardware Acceleration (VA-API, NVENC, VideoToolbox) — Weylus's core performance depends on GPU encoding; understanding VA-API (Linux Intel/AMD), NVENC (NVIDIA), and VideoToolbox (macOS) is essential for debugging encoding failures and optimizing for different hardware
- WebSocket Upgrade via HTTP — Weylus uses fastwebsockets to upgrade HTTP connections to persistent bidirectional WebSocket channels for real-time input and screen streaming; this is the core protocol between browser client and server
- Linux uinput and Event Input Device Abstraction — Stylus pressure, tilt, and multi-touch on Linux require creating virtual input devices via /dev/uinput; understanding input_event struct and device capabilities (EV_ABS, ABS_PRESSURE) is critical for Linux-specific input features
- Platform-Specific Screen Capture (X11, Wayland, DXGI, Core Graphics) — Weylus abstracts four fundamentally different screen capture APIs in src/capturable/; understanding X11 MIT-SHM, PipeWire (Wayland), Windows DXGI desktop duplication, and macOS Core Graphics is needed to debug capture failures or add new backends
- Async/Await with Tokio Runtime and Task Spawning — Entire server architecture is async Tokio-based; screen capture, WebSocket message handling, and HTTP requests run on the same multi-threaded runtime; blocking operations or improper task scoping will degrade performance
- FFmpeg C API for Hardware Encoding and Remuxing — lib/encode_video.c wraps FFmpeg libavcodec/libavformat C API for encoding captured frames and streaming; tweaking codec params, hardware encoder selection, and bitrate requires FFmpeg C API knowledge
- Build Scripts and Conditional Compilation with cc Crate and Cargo Features — build.rs compiles C code conditionally per platform; Cargo.toml uses cfg(target_os) to gate dependencies (winapi on Windows, gstreamer on Linux); understanding this is essential for adding new platform support or dependencies
🔗Related repos
mirrorlink/mirrorlink— Android-to-PC screen mirroring alternative, though less focus on stylus input and pen pressure than Weylusscrcpy/scrcpy— Android device screen mirroring and control tool; shares WebSocket streaming and hardware encoding patterns but targets mobile devices onlyGenymobile/gnirehtet— Reverse tethering tool from same ecosystem (Genymobile); demonstrates Android-to-Linux input injection patterns relevant to Weylus input handlingH-M-H/autopilot-rs— Weylus's own fork of autopilot crate for cross-platform mouse/keyboard control; direct dependency of Weylus, maintained in lockstepinput-rs/input-rs— Generic input device abstraction library; potential alternative or complement to autopilot for input handling if Weylus refactored input layer
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add integration tests for WebSocket protocol message handling (src/protocol.rs and src/websocket.rs)
The protocol.rs and websocket.rs modules handle critical communication between tablet and computer, but there are no visible integration tests. Given this is a real-time input application, testing message serialization, deserialization, and state transitions would catch regressions early. This is especially important since the repo supports multiple platforms (Windows, Linux, macOS) with different input backends.
- [ ] Create tests/websocket_protocol_tests.rs with test cases for protocol message encoding/decoding
- [ ] Add tests for input event serialization from src/input/device.rs structures
- [ ] Test edge cases like malformed messages, missing fields, and version mismatches
- [ ] Integrate into build.yml CI workflow to run on all platforms
- [ ] Document test patterns in a new TESTING.md file referencing src/protocol.rs and src/websocket.rs
Add CI workflow for clippy linting and code quality checks (expand .github/workflows/build.yml)
The repo has a build.yml workflow but no linting enforcement. Given the codebase spans multiple modules (src/capturable/, src/input/, src/video.rs) across different platforms with conditional compilation, clippy checks would catch unused code, unnecessary allocations, and common Rust anti-patterns before merge. This is especially valuable for a multimedia app handling tablet input.
- [ ] Extend .github/workflows/build.yml to run 'cargo clippy --all-targets' for each platform target
- [ ] Add clippy lints configuration to Cargo.toml with strict settings appropriate for I/O code
- [ ] Test against src/video.rs (FFmpeg FFI bindings) and lib/encode_video.c integration
- [ ] Configure to fail CI on clippy warnings for new contributions
- [ ] Document clippy expectations in CONTRIBUTING.md (create if missing)
Add platform-specific documentation and troubleshooting guides for input backends (create docs/PLATFORM_SETUP.md)
The repo has platform-specific code in src/input/ (autopilot_device.rs, uinput_device.rs, autopilot_device_win.rs) and src/capturable/ but the README only partially covers setup. Users debugging input issues on Linux (uinput permissions), macOS (accessibility), or Windows (DirectInput) have no centralized reference. This would reduce support burden and help contributors understand platform constraints.
- [ ] Create docs/PLATFORM_SETUP.md with sections for Linux (referencing src/input/uinput_device.rs), macOS, and Windows
- [ ] Document uinput permissions, device node access, and systemd-logind quirks for Linux
- [ ] Add troubleshooting for each src/input/ backend with permission/capability requirements
- [ ] Link from README.md and reference the existing lib/linux/uinput_info.md
- [ ] Include platform-specific build requirements (cc build dependencies) from Cargo.toml
🌿Good first issues
- Add unit tests for
src/config.rsTOML parsing and default values—file has clear interface but no test coverage, and config loading is critical for runtime behavior - Document the Linux uinput permission setup in a dedicated guide (currently scattered in README)—create
docs/LINUX_UINPUT_SETUP.mdwith step-by-step instructions, common errors, and syslog debugging tips - Add hardware encoding fallback warnings: emit a tracing::warn!() in
lib/encode_video.cor wrapper when GPU encoding fails, so users see why performance is poor instead of silent CPU fallback
⭐Top contributors
Click to expand
Top contributors
- @H-M-H — 74 commits
- @schctl — 12 commits
- @qdlmcfresh — 4 commits
- @bbb651 — 2 commits
- @normalUserKarn — 1 commits
📝Recent commits
Click to expand
Recent commits
38a01a8— Try another image for macos intel builds. (H-M-H)ec0e53a— Hash only shell and patch files for action cache. (H-M-H)f5693b4— Update GitHub actions. (H-M-H)eeb2019— Update external deps and improve download script. (H-M-H)0983c86— Update cargo deps. (H-M-H)9b386b3— Update macos-13 runner to macos-14-large. (H-M-H)69b4941— Remove unused movement_x/y from protocol. (H-M-H)ad90986— Merge pull request #487 from normalUserKarn/patch-1 (H-M-H)22c1c65— Fix ios video rendering (normalUserKarn)56e29ec— Explicitly enable d3d11va on windows. (H-M-H)
🔒Security observations
- High · Git Dependency with Pinned Revision —
Cargo.toml - autopilot dependency. The autopilot dependency is sourced directly from a GitHub repository with a pinned revision rather than using a published crate version. This bypasses the crate registry's security review process and makes the dependency vulnerable to potential compromises of the repository if the revision is ever rewritten or if the repository is compromised. Git dependencies also make reproducible builds more fragile. Fix: Migrate to a published crate version if available, or if a git dependency is necessary, ensure the repository is owned/controlled by the project maintainers and use branch pinning with signed commits. Consider vendoring the dependency for supply chain security. - High · Potential XSS in Web Templates —
www/templates/index.html, www/static/access_code.html, ts/lib.ts. The codebase uses Handlebars templating (www/templates/index.html, www/static/access_code.html) to render web content. If user input or unsanitized data is passed to templates without proper escaping, this could lead to XSS vulnerabilities. The TypeScript/JavaScript client (ts/lib.ts) may also be vulnerable to DOM-based XSS if it handles user input unsafely. Fix: Ensure all dynamic content in Handlebars templates uses triple-braces {{{value}}} only when absolutely necessary and content is trusted. Validate and sanitize all user inputs in TypeScript/JavaScript. Use Content Security Policy (CSP) headers to mitigate XSS impact. Review all dynamic HTML generation in src/web.rs. - High · WebSocket Input Validation —
src/websocket.rs, src/protocol.rs. The WebSocket implementation (src/websocket.rs) handles protocol messages from remote clients. Without robust input validation and sanitization, this could be vulnerable to injection attacks, buffer overflows, or DoS attacks. Remote clients can send arbitrary protocol messages that need to be validated. Fix: Implement strict input validation for all WebSocket messages. Define and validate protocol schema rigorously. Implement rate limiting and message size limits. Add comprehensive error handling that doesn't expose sensitive information. Fuzz test the protocol parser. - High · Remote Code Execution via Input Devices —
src/input/ module. The input handling subsystem (src/input/device.rs, src/input/uinput_device.rs, src/input/autopilot_device.rs) processes remote input commands from WebSocket clients. If these commands are not properly validated, an attacker could potentially inject malicious input that exploits vulnerabilities in the underlying input systems or the application logic. Fix: Implement whitelist-based validation for all input commands. Sanitize input parameters before passing to system APIs. Use safe abstractions and avoid passing untrusted data directly to system calls. Implement input rate limiting and throttling to prevent abuse. - Medium · Unencrypted WebSocket Communication Default —
src/websocket.rs, src/web.rs, README.md (Encryption section). The application appears to support WebSocket connections (src/websocket.rs). Unless TLS is properly configured by default, communication between the tablet client and computer could be transmitted in plaintext, exposing touch coordinates, keyboard input, and potentially screen content. Fix: Implement TLS/WSS as the default transport. Provide clear documentation on enabling encryption. Consider requiring a minimum security baseline. The weylus_tls.sh script suggests TLS is available but not enforced by default. Make HTTPS/WSS mandatory rather than optional. - Medium · Access Control via Simple Access Code —
src/web.rs, www/static/access_code.html, src/protocol.rs. Authentication appears to rely on an access code (www/static/access_code.html suggests HTML-based input). Simple access codes are weak authentication mechanisms and vulnerable to brute force attacks if not properly rate-limited. The security of this mechanism depends on entropy and rate limiting which are not evident. Fix: Implement rate limiting on failed authentication attempts. Use cryptographically secure random code generation with sufficient entropy (minimum 128 bits). Consider implementing TOTP or stronger authentication mechanisms. Store authentication tokens securely (hash with salt). Implement automatic token expiration. - Medium · Unsafe FFI with C Code —
undefined. The codebase includes C/C++ code for platform-specific features (lib/encode_video.c Fix: undefined
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.