Team Ai
Datasetpublic

Fraser/cursors

Cursors A dataset of labelled OS cursor images for compositing onto cursor-free screenshots as synthetic training data for GUI grounding models. 366 rows across 7 OS/theme sources, covering 31 cursor types. Intended use Given a screenshot with a cursor composited into it, a model is asked: "What cursor type is shown in the red box?" The cursor_type labels are chosen to be visually distinguishable — if two themes render a cursor name differently (e.g. one theme… See the full description on the dataset page: https://huggingface.co/datasets/Fraser/cursors.

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes58downloads
Dataset Card

Cursors

A dataset of labelled OS cursor images for compositing onto cursor-free screenshots as synthetic training data for GUI grounding models.

366 rows across 7 OS/theme sources, covering 31 cursor types.

Intended use

Given a screenshot with a cursor composited into it, a model is asked: "What cursor type is shown in the red box?"

The cursor_type labels are chosen to be visually distinguishable — if two themes render a cursor name differently (e.g. one theme draws move as a four-way arrow and another as a closed fist), the label reflects what the cursor actually looks like, not what the X11 name says.

Cursor type taxonomy

Pointers

cursor_typeDescriptionTypical appearance
arrowDefault pointerAngled arrow pointing upper-left
pointerClickable / linkHand with index finger pointing
textText selectionVertical I-beam
text_verticalVertical text selectionHorizontal I-beam
crosshairPrecision selectThin cross / plus

Drag & drop

cursor_typeDescriptionTypical appearance
grabElement is grabbableOpen hand, palm facing out
grabbingActively draggingClosed / clenched hand
moveMovable elementFour-way arrow cross
copyDrag-copyArrow with small + badge
aliasCreate shortcut / linkArrow with curved-arrow badge

Resize

cursor_typeDescriptionTypical appearance
resize_nNorth (up)Upward arrow
resize_sSouth (down)Downward arrow
resize_eEast (right)Rightward arrow
resize_wWest (left)Leftward arrow
resize_neNortheastArrow pointing upper-right
resize_nwNorthwestArrow pointing upper-left
resize_seSoutheastArrow pointing lower-right
resize_swSouthwestArrow pointing lower-left
resize_ewHorizontalLeft-right double arrow
resize_nsVerticalUp-down double arrow
resize_neswDiagonal (/ axis)Double arrow on NE-SW axis
resize_nwseDiagonal (\\ axis)Double arrow on NW-SE axis

Status

cursor_typeDescriptionTypical appearance
waitBusy / loadingSpinning circle or hourglass
progressBusy but interactiveArrow with spinner

Other

cursor_typeDescriptionTypical appearance
not_allowedForbidden / no-dropCircle with diagonal line
helpHelp availableArrow with ? badge
context_menuRight-click menuArrow with menu icon
cellCell / spreadsheet selectHollow plus / crosshair
zoom_inZoom inMagnifying glass with +
zoom_outZoom outMagnifying glass with −
all_scrollOmnidirectional scrollFour-way arrow cluster

Schema

FieldTypeDescription
cursor_typestringOne of the 31 types above
osstringSource OS/theme identifier
frameslist\[image\]Cursor image(s). Static cursors have 1 frame; animated cursors (wait, progress) have multiple
frame_delay_msint32Milliseconds between animation frames (0 for static)
hotspot_xfloat32Click-point x position, normalised 0–1 within the image
hotspot_yfloat32Click-point y position, normalised 0–1 within the image
size_pxint32Pixel dimensions of the cursor image (square)
variantstringColour variant: default, black, white, blue, red

Sources

`os` valueSourceCursor sizesVariants
macosSystem cursors (PDF + NSCursor)96px rendereddefault
linux-adwaitaXcursor binaries with hotspot metadata96pxdefault
linux-apple-cursorSVG-rendered Apple-style theme96pxblack, white
linux-bibataSVG-rendered Bibata theme96pxblack, white
linux-google-cursorGoogle Cursor pre-built PNGs200pxblack, white, blue, red
linux-notwaitaSVG-rendered Notwaita theme96pxblack, white
linux-xcursor-proSVG-rendered Xcursor-Pro theme96pxblack, white

Usage

python
from datasets import load_dataset

ds = load_dataset("Fraser/cursors", split="train")

# Get all arrow cursors
arrows = ds.filter(lambda r: r["cursor_type"] == "arrow")

# Get a specific cursor image
row = ds[0]
cursor_image = row["frames"][0]  # PIL Image
hotspot = (row["hotspot_x"], row["hotspot_y"])

Compositing a cursor onto a screenshot

Place a cursor so its hotspot (the click-point) lands at a target pixel position. The cursor is scaled to a realistic size and alpha-composited without artifacts.

python
from datasets import load_dataset
from PIL import Image


def composite_cursor(screenshot, cursor_frame, hotspot_x, hotspot_y,
                     target_x, target_y, cursor_size=32):
    """Place a cursor on a screenshot with the hotspot at (target_x, target_y)."""
    canvas = screenshot.convert("RGBA")
    cw, ch = cursor_frame.size
    scale = cursor_size / max(cw, ch)
    new_w, new_h = max(1, round(cw * scale)), max(1, round(ch * scale))
    cursor_scaled = cursor_frame.convert("RGBA").resize((new_w, new_h), Image.LANCZOS)

    # Offset so the hotspot lands on the target position
    paste_x = target_x - round(hotspot_x * new_w)
    paste_y = target_y - round(hotspot_y * new_h)

    # Crop if the cursor extends past the screenshot edges
    sw, sh = canvas.size
    src_left = max(0, -paste_x)
    src_top = max(0, -paste_y)
    src_right = min(new_w, sw - paste_x)
    src_bottom = min(new_h, sh - paste_y)
    if src_left >= src_right or src_top >= src_bottom:
        return screenshot
    cropped = cursor_scaled.crop((src_left, src_top, src_right, src_bottom))

    canvas.alpha_composite(cropped, (paste_x + src_left, paste_y + src_top))
    return canvas.convert(screenshot.mode)


ds = load_dataset("Fraser/cursors", split="train")

# Pick an arrow cursor from the Adwaita theme
row = ds.filter(lambda r: r["cursor_type"] == "arrow" and r["os"] == "linux-adwaita")[0]

screenshot = Image.open("my_screenshot.png")
result = composite_cursor(
    screenshot,
    row["frames"][0],
    row["hotspot_x"], row["hotspot_y"],
    target_x=500, target_y=300,  # where the arrow tip should point
    cursor_size=32,              # realistic size for a 1080p screenshot
)
result.save("my_screenshot_with_cursor.png")