Ruri.GhostCursorSharp.Core
0.2.0
See the version list below for details.
dotnet add package Ruri.GhostCursorSharp.Core --version 0.2.0
NuGet\Install-Package Ruri.GhostCursorSharp.Core -Version 0.2.0
<PackageReference Include="Ruri.GhostCursorSharp.Core" Version="0.2.0" />
<PackageVersion Include="Ruri.GhostCursorSharp.Core" Version="0.2.0" />
<PackageReference Include="Ruri.GhostCursorSharp.Core" />
paket add Ruri.GhostCursorSharp.Core --version 0.2.0
#r "nuget: Ruri.GhostCursorSharp.Core, 0.2.0"
#:package Ruri.GhostCursorSharp.Core@0.2.0
#addin nuget:?package=Ruri.GhostCursorSharp.Core&version=0.2.0
#tool nuget:?package=Ruri.GhostCursorSharp.Core&version=0.2.0
GhostCursorSharp
GhostCursorSharp is a .NET 10 port of the upstream ghost-cursor package, built around PuppeteerSharp and Microsoft.Playwright.
It generates human-like mouse paths between coordinates and provides browser-facing cursor APIs for moving, clicking, scrolling, and debugging cursor movement across Puppeteer and Playwright pages.
Installation
Choose the package that matches your target:
Ruri.GhostCursorSharp.CorePath generation, shared options,ElementBox, and target-agnostic cursor infrastructure.Ruri.GhostCursorSharp.PuppeteerGhostCursorforPuppeteerSharp. Depends onCore.Ruri.GhostCursorSharp.PlaywrightPlaywrightGhostCursorforMicrosoft.Playwright. Depends onCore.
Install the package you need:
dotnet add package Ruri.GhostCursorSharp.Puppeteer
dotnet add package Ruri.GhostCursorSharp.Playwright
dotnet add package Ruri.GhostCursorSharp.Core
If you are developing this repo itself:
dotnet restore GhostCursorSharp.slnx
Status
Implemented today:
- Path generation with
CursorPath.Generate(...)andCursorPath.GenerateTimed(...) - Shared
ElementBox,MouseButton, and option models inCore GhostCursorandPlaywrightGhostCursormovement and click APIs- Selector lookup with CSS and XPath
scroll,scrollTo, andscrollIntoView- Random movement with
PerformRandomMovesandToggleRandomMove(...) - Public element-box geometry helper with inline-element and iframe-aware fallbacks
- Visual mouse helper installation
- Default action options and
CreateCursor(...)compatibility shim
Usage
Generate movement data between two coordinates:
using GhostCursorSharp;
var from = new Vector(100, 100);
var to = new Vector(600, 700);
var route = CursorPath.Generate(from, to);
Generate movement data with timestamps:
using GhostCursorSharp;
var route = CursorPath.GenerateTimed(
new Vector(100, 100),
new Vector(600, 700),
new PathOptions
{
MoveSpeed = 10
});
Use it with PuppeteerSharp:
using GhostCursorSharp;
using PuppeteerSharp;
var browserFetcher = new BrowserFetcher();
var installedBrowser = browserFetcher.GetInstalledBrowsers().FirstOrDefault()
?? await browserFetcher.DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = false,
ExecutablePath = installedBrowser.GetExecutablePath()
});
await using var page = await browser.NewPageAsync();
await page.GoToAsync("https://example.com");
var cursor = new GhostCursor(page);
await cursor.ClickAsync("a");
Use it with Microsoft.Playwright:
using GhostCursorSharp;
using Microsoft.Playwright;
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
{
Headless = false
});
var page = await browser.NewPageAsync();
await page.GotoAsync("https://example.com");
var cursor = new PlaywrightGhostCursor(page);
await cursor.ClickAsync("a");
Using default action options:
using GhostCursorSharp;
var cursor = GhostCursor.CreateCursor(
page,
defaultOptions: new DefaultOptions
{
Click = new ClickOptions
{
WaitForSelector = 1000,
MoveSpeed = 24,
PaddingPercentage = 100
},
Scroll = new ScrollIntoViewOptions
{
ScrollSpeed = 100,
ScrollDelay = 100
}
});
await cursor.ClickAsync("#submit");
await cursor.ScrollToAsync("bottom");
Puppeteer Behavior
Current behavior mirrors the upstream package in the following areas:
MoveAsync(...)targets a random point inside the element unlessDestinationis specified.PaddingPercentagecontrols how center-biased or edge-biased element targeting is.- Long moves can overshoot and then correct back toward the destination.
ClickAsync(selector)is shorthand for moving to the target and then clicking.ScrollIntoViewAsync(...)will bring offscreen elements into view before movement.- Selector-based move and click retries can reacquire a rerendered target across attempts.
API
new GhostCursor(page, start?)
var cursor = new GhostCursor(page);
var cursorWithStart = new GhostCursor(page, new Vector(100, 100));
Creates a cursor bound to a PuppeteerSharp.IPage.
page: Puppeteer page instance.start: optional initial cursor position. Defaults to(0, 0).
new GhostCursor(page, options)
var cursor = new GhostCursor(page, new GhostCursorOptions
{
Start = new Vector(100, 100),
Visible = true,
DefaultOptions = new DefaultOptions()
});
Start: optional initial cursor position.Visible: installs the mouse helper immediately.DefaultOptions: default options applied to actions likeclick,move,scroll, andgetElement.
new PlaywrightGhostCursor(page, start?)
var cursor = new PlaywrightGhostCursor(page);
var cursorWithStart = new PlaywrightGhostCursor(page, new Vector(100, 100));
Creates a cursor bound to a Microsoft.Playwright.IPage.
new PlaywrightGhostCursor(page, options)
var cursor = new PlaywrightGhostCursor(page, new GhostCursorOptions
{
Start = new Vector(100, 100),
Visible = true,
DefaultOptions = new DefaultOptions()
});
Supports the same option model as the Puppeteer facade.
GhostCursor.CreateCursor(page, start?, defaultOptions?, visible?)
Compatibility-oriented factory:
var cursor = GhostCursor.CreateCursor(page, visible: true);
PlaywrightGhostCursor.CreateCursor(page, start?, defaultOptions?, visible?)
Compatibility-oriented factory for Playwright:
var cursor = PlaywrightGhostCursor.CreateCursor(page, visible: true);
GetLocation(): Vector
Returns the current tracked cursor position.
InstallMouseHelperAsync(): Task<MouseHelperInstallation>
Installs a visible cursor overlay into the page for debugging.
RemoveMouseHelperAsync(): Task
Removes the visible cursor overlay if installed.
GetElementAsync(selector, options?): Task<IElementHandle>
Resolves an element by CSS selector or XPath.
selector: CSS selector or XPath.options.WaitForSelector: optional timeout in milliseconds before failing.
GetElementAsync(element, options?): Task<IElementHandle>
Returns an existing handle unchanged.
element: existingIElementHandle.options: accepted for parity, but ignored when a handle is already provided.
GetElementBoxAsync(element, relativeToMainFrame?): Task<BoundingBox>
Resolves an element box using the same geometry fallbacks as cursor movement.
- Uses
DOM.getContentQuadswhen available. - Falls back to
boundingBox()and thengetBoundingClientRect(). - Handles inline elements more reliably than a plain bounding box.
For PlaywrightGhostCursor, the equivalent return type is ElementHandleBoundingBoxResult.
MoveAsync(selector | element | boundingBox, options?): Task
Moves the cursor to a target element or bounding box.
PaddingPercentage: target more toward center or more toward edges.Destination: explicit point relative to the target's top-left corner.MoveSpeed: path density/speed hint.MoveDelay: delay after movement.RandomizeMoveDelay: randomize the final delay between0andMoveDelay.WaitForSelector: optional selector wait timeout.ScrollSpeed: scroll speed used if the element must be brought into view.ScrollDelay: delay after scrolling.InViewportMargin: extra margin when checking viewport visibility.SpreadOverride: override the path spread.DelayPerStep: extra C#-specific delay between generated mouse points.MaxTries: maximum number of reacquire/retry attempts if the element shifts or rerenders during movement.OvershootThreshold: distance threshold for overshoot correction.
Examples:
await cursor.MoveAsync("#button");
await cursor.MoveAsync("#card", new MoveOptions
{
PaddingPercentage = 0,
MoveSpeed = 28
});
await cursor.MoveAsync("#card", new MoveOptions
{
Destination = new Vector(20, 14)
});
MoveToAsync(destination, pathOptions?, delayPerStep?): Task
Moves the cursor to an absolute page coordinate.
MoveByAsync(delta, pathOptions?, delayPerStep?): Task
Moves the cursor by a relative offset.
ClickAsync(options?): Task
Clicks at the current cursor location.
Hesitate: delay before pressing the mouse button.WaitForClick: delay between mouse down and mouse up.Button:MouseButton.Left,MouseButton.Middle, orMouseButton.Right. Defaults to left.ClickCount: number of clicks. Defaults to1.- Inherits the move-related options from
MoveOptions.
ClickAsync(selector | element, options?): Task
Moves to the target, then clicks it.
await cursor.ClickAsync("#submit");
await cursor.ClickAsync("#submit", new ClickOptions
{
WaitForSelector = 1000,
PaddingPercentage = 100,
MoveSpeed = 26
});
MouseDownAsync(options?): Task
Presses a mouse button at the current cursor position.
MouseUpAsync(options?): Task
Releases a mouse button at the current cursor position.
ScrollIntoViewAsync(selector | element, options?): Task
Brings an element into view if needed.
ScrollSpeed:0-100, where100is effectively instant.ScrollDelay: delay after scrolling.InViewportMargin: extra margin around the target element.WaitForSelector: optional selector wait timeout for string selectors.
ScrollAsync(delta, options?): Task
Scrolls the page by a relative delta.
await cursor.ScrollAsync(new Vector(0, 500));
ScrollToAsync(destination, options?): Task
Scrolls to an absolute destination.
Supported overloads:
ScrollToAsync("top" | "bottom" | "left" | "right", options?)ScrollToAsync(new ScrollToDestination { X = ..., Y = ... }, options?)
Path API
CursorPath.Generate(start, end, options?): IReadOnlyList<Vector>
Generates a human-like route between two coordinates or from a coordinate to an ElementBox.
CursorPath.GenerateTimed(start, end, options?): IReadOnlyList<TimedVector>
Same as Generate(...), but includes timestamps.
PathOptions
SpreadOverride: override the Bezier spread.MoveSpeed: speed hint used during path generation.
Debugging
Run the included demo:
dotnet run --project .\src\GhostCursorSharp.Demo\GhostCursorSharp.Demo.csproj
That demo lets you choose Puppeteer - Chromium, Playwright - Chromium, or Playwright - Firefox, then runs scenario-driven tours for movement, clicking, press/release, scrolling, and random motion with the visual mouse helper enabled.
Attribution
This project is a C# port of the original ghost-cursor work by Xetera and contributors.
The upstream project is MIT licensed.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Ruri.GhostCursorSharp.Core:
| Package | Downloads |
|---|---|
|
Ruri.GhostCursorSharp.Playwright
Microsoft.Playwright integration for GhostCursorSharp human-like cursor automation. |
|
|
Ruri.GhostCursorSharp.Puppeteer
PuppeteerSharp integration for GhostCursorSharp human-like cursor automation. |
|
|
Ruri.GhostCursorSharp.Selenium
Selenium WebDriver integration for GhostCursorSharp human-like cursor automation. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Split the library into Core, Puppeteer, and Playwright packages.