Ruri.GhostCursorSharp.Selenium
0.3.0
dotnet add package Ruri.GhostCursorSharp.Selenium --version 0.3.0
NuGet\Install-Package Ruri.GhostCursorSharp.Selenium -Version 0.3.0
<PackageReference Include="Ruri.GhostCursorSharp.Selenium" Version="0.3.0" />
<PackageVersion Include="Ruri.GhostCursorSharp.Selenium" Version="0.3.0" />
<PackageReference Include="Ruri.GhostCursorSharp.Selenium" />
paket add Ruri.GhostCursorSharp.Selenium --version 0.3.0
#r "nuget: Ruri.GhostCursorSharp.Selenium, 0.3.0"
#:package Ruri.GhostCursorSharp.Selenium@0.3.0
#addin nuget:?package=Ruri.GhostCursorSharp.Selenium&version=0.3.0
#tool nuget:?package=Ruri.GhostCursorSharp.Selenium&version=0.3.0
GhostCursorSharp
GhostCursorSharp is a .NET 10 port of the upstream ghost-cursor package, with browser integrations for PuppeteerSharp, Microsoft.Playwright, and Selenium WebDriver.
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.Ruri.GhostCursorSharp.SeleniumSeleniumGhostCursorfor Selenium WebDriver. Depends onCore.
Install the package you need:
dotnet add package Ruri.GhostCursorSharp.Puppeteer
dotnet add package Ruri.GhostCursorSharp.Playwright
dotnet add package Ruri.GhostCursorSharp.Selenium
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 APIsSeleniumGhostCursormovement, click, scroll, and mouse-helper 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");
Use it with Selenium WebDriver:
using GhostCursorSharp;
using OpenQA.Selenium.Chrome;
using var driver = new ChromeDriver();
driver.Navigate().GoToUrl("https://example.com");
var cursor = new SeleniumGhostCursor(driver);
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.
new SeleniumGhostCursor(driver, start?)
var cursor = new SeleniumGhostCursor(driver);
var cursorWithStart = new SeleniumGhostCursor(driver, new Vector(100, 100));
Creates a cursor bound to an OpenQA.Selenium.IWebDriver.
new SeleniumGhostCursor(driver, options)
var cursor = new SeleniumGhostCursor(driver, new GhostCursorOptions
{
Start = new Vector(100, 100),
Visible = true,
DefaultOptions = new DefaultOptions()
});
Supports the same option model as the Puppeteer and Playwright facades.
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);
SeleniumGhostCursor.CreateCursor(driver, start?, defaultOptions?, visible?)
Compatibility-oriented factory for Selenium:
var cursor = SeleniumGhostCursor.CreateCursor(driver, 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.
For SeleniumGhostCursor, the equivalent return type is ElementBox.
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, Playwright - Firefox, Selenium - Chromium, or Selenium - 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
- Ruri.GhostCursorSharp.Core (>= 0.3.0)
- Selenium.Support (>= 4.40.0)
- Selenium.WebDriver (>= 4.40.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Added Selenium support, Firefox coverage, and expanded demo/browser test parity across all targets.