# Bigcursor: agent guide

> Bigcursor adds readable cursor movement, natural typing, click feedback, and optional live sounds to real Playwright actions. It helps people follow product walkthroughs, bug reproductions, and coding-agent test recordings.

Canonical website: https://www.bigcursor.dev. HTML docs: https://www.bigcursor.dev/docs. Discovery index: https://www.bigcursor.dev/llms.txt. Source: https://github.com/seflless/bigcursor.

## Install bigcursor skill

Run this in your project and choose your coding agent when prompted. The installer reads skills/bigcursor from the official repository. The agent handles runtime and browser setup when you request a demo.

```sh
npx skills add seflless/bigcursor --skill bigcursor
```

Your agent handles the package and browser setup.

## Usage

### Ask an agent to demo a feature

```text
/bigcursor record a demo of the new UX features in this PR
```

Use the requested app and starting state. Bigcursor needs an actual Playwright Page in the same process as its actions. Reuse a supported browser connection; do not invent a CDP endpoint. The optional recording module can attach to Chrome 153+ without restarting the context. Preserve the existing window and authenticated state, and report source resolution as unverified for attached browsers. An older or muted browser may need a fresh recording session; do not silently replace the user’s starting state.

### Create a product demo

```text
/bigcursor create a product demo of a my to-do app
```

For a standalone example without an existing app, the skill also includes scripts/record-todo.mjs, a self-contained local to-do app and real-input recording script. No account or production app is needed. Copy only that example script into the chosen execution workspace after dependency setup, then run node record-todo.mjs with a durable output directory. It verifies the task was added and completed.

## Choose temporary or repository setup

One-off PR/bug recordings and video-only requests use a unique OS temporary workspace for scripts and missing dependencies; the app’s manifest, lockfile, and source stay unchanged. Product walkthroughs for a current app repository and requests to save/rerun a script use repository scripts and development dependencies, with the existing package manager and lockfile. Explicit output/script paths and instructions to leave the repo unchanged take precedence; ambiguous requests start temporary. Install missing Bigcursor, chrome-capture@0.1.2, compatible Playwright, full Chromium 153+, and a required task-local Node runtime automatically. Reuse compatible installations instead of upgrading them. Save final videos outside disposable tools. Use the published bigcursor package. Do not search for source checkouts or build Bigcursor as a fallback; if no runtime release is available, report the missing publication. Saved scripts and lockfiles must not depend on temporary or personal paths.

## Release status and installation

bigcursor 1.1.1 is published and verified. The skill is available from the official repository. Registry tarball rechecked November 11, 2026: 1.1.1 is npm latest and exports createCursor, typingSpeeds, and bigcursor/recording, with natural typing, cursor dimming, browser bundle, declarations, 35 SVGs, and license notices. Its 58 dist files match the tested build byte for byte. Homepage points to bigcursor.dev, and the README links directly to docs/examples with current installation instructions. Avoid the historical 1.1.0 archive, which has an older API without recording; 0.0.0-stage is only a placeholder. No source checkout or build tools are required.

The runtime package declares Node.js >=22; the optional recording module requires Node.js >=24.11. Both are ESM, with TypeScript declarations and bundled SVG assets. Install the published bigcursor package in the chosen workspace with its package manager; avoid adding another lockfile. Reuse installed compatible dependencies. A one-off recording installs in its private temporary package; a saved demo adds development dependencies in the app repository. Bun is not required to consume Bigcursor. Install full Chromium through the matching installed Playwright version. For recording, import bigcursor/recording from the installed package; runtime helpers are never copied from the skill. If an app’s existing Playwright ships Chrome older than 153, preserve it and add the bigcursor-browser alias described in skills/bigcursor/references/setup.md:

```sh
npm install --save-dev bigcursor@1.1.1 playwright chrome-capture@0.1.2
npx --no-install playwright install chromium
```

If Playwright is already installed, reuse a compatible version rather than adding a conflicting duplicate. The public import is createCursor from bigcursor. bigcursor/playwright is an alias for the package root; bigcursor/internal is for repository previews and is not the automation entry point. Never invent a CLI, skill installer, or API that is absent from the installed package.

## Minimal real-input script

Save as demo.ts and run with bun demo.ts, or use the project’s existing TypeScript runner. Replace the localhost URL and all example locators with your app’s real URL and elements. Use a safe test environment. Bigcursor accepts your existing Playwright Page; it does not launch a browser for you.

```ts
import { chromium } from 'playwright';
import { createCursor } from 'bigcursor';

const browser = await chromium.launch({ headless: false });
try {
  const page = await browser.newPage();
  await page.goto('http://localhost:3000'); // Your app
  const cursor = await createCursor(page, { scale: 4 });

  try {
    await cursor.click(page.getByRole('button', { name: 'Save' }));
    await cursor.type(page.getByLabel('Title'), 'Start', { selectAll: true });
    await cursor.selectText(page.getByText('Select these words.'));
    await cursor.drag(page.getByTestId('card'), page.getByTestId('drop'));
  } finally {
    await cursor.dispose();
  }
} finally {
  await browser.close();
}
```

Use Playwright assertions or locator waits to verify readiness and results. Keep navigation and assertions in Playwright. Await actions in order, never Promise.all on the same cursor instance. Await the current action before disposing; dispose removes the overlay, not the page. The overlay is reinstalled after navigation on the next action.

## API reference

Durations and delays are milliseconds. Prefer page.getByRole(), page.getByLabel(), and page.getByTestId(). General targets accept a Locator, a CSS selector string, or { x, y } in main-viewport CSS pixels. selectText accepts only a Locator or selector. Locators scroll into view and resolve to their center before movement.

### createCursor(page, options?)

Attach to your existing Playwright page. Options include scale (cursor size), seed (repeatable paths and typing), typing (speed or numeric pace), settle (aim pause, 120 ms by default), fps (input sampling target, not recording FPS), autoHideTimeout (0 by default; positive milliseconds enable idle dimming), hiddenOpacity (0), and dimmedOpacity (0.3).

### cursor.click(target, { duration?, signal? })

Move to the target, slow down on approach, pause to aim, then send real mouse down/up.

### cursor.moveTo(target, { duration?, signal? })

Move without clicking. A locator resolves to its center after scrolling into view. Coordinates are CSS pixels relative to the main viewport.

### cursor.selectText(locator, { duration?, signal? })

Drag from the first visible text line to the last. Accepts a locator or selector for ordinary selectable text, including nested spans and wrapped lines. For inputs, use type with selectAll or a keyboard shortcut.

### cursor.drag(from, to, { duration?, signal? })

Move to the source, hold the mouse, drag to the destination, then release. Sources and destinations may be locators, selectors, or coordinates. The mouse is released even when the drag is cancelled.

### cursor.type(target, text, { speed?, pace?, delay?, selectAll?, signal? })

Click the target and type with varied real key holds and word/sentence pauses. Speeds are slow (3×), default (6×), and fast (8×). Numeric pace overrides the preset. Set selectAll to replace contents; explicit delay selects fixed per-character timing in milliseconds. Unicode graphemes stay together and literal newlines do not submit forms.

### cursor.press(key)

Send a Playwright keyboard shortcut, for example ControlOrMeta+A or Shift+2.

### cursor.wait(milliseconds, signal?)

Add a short presentation pause. Use Playwright assertions or locator waits for application readiness.

### cursor.configure(appearance)

Change cursor size and feedback while the script is running. For example, await cursor.configure({ scale: 4, dimmedOpacity: 0.3 }).

### cursor.hideCursor()

Fully hide the cursor, its trail, and pointer feedback until showCursor is called. Mouse and keyboard input still work; the override survives navigation. This ignores hiddenOpacity.

### cursor.showCursor()

Restore the cursor at its last known position and resume automatic dimming. It resets the inactivity deadline and clears temporary typing dimming.

### cursor.dispose()

Remove the cursor overlay and its listeners. Await any running action before cleanup. Your Playwright page stays open.

## Configuration

createCursor options include scale (default 2.5; examples use 4), seed (42), typing (default speed, 6×), settle (120 ms), fps (60 input samples/second target, NOT recording FPS), autoHideTimeout (0, disabled; set a positive millisecond delay to enable), hiddenOpacity (0), dimmedOpacity (0.3), and keyboard (false). Enable keyboard: true only when modifier-chord badges are wanted; ordinary typed text is never shown in badges. All artwork is bundled; no cursor asset server is needed.

Appearance options: scale, color, filled, motionBlur, dimmedOpacity, hiddenOpacity, autoHideTimeout, pressRadius, pressDuration, pressOpacity, pressScale, holdRadius, holdOpacity, ringWidth, releaseRadius, releaseDuration. Typical defaults: color #397ef3, filled true, motionBlur 0.2, dimmedOpacity 0.3. Use await cursor.configure({ scale: 4 }) to change appearance. Configuration availability follows the installed package version.

Action defaults: drag duration 900 ms, selectText drag duration 1400 ms, and natural typing at default speed (6×). Explicit type delay opts into fixed timing. Pass an AbortSignal to actions that accept signal; held mouse input is released on cancelled drags. Set explicit CSS cursor styles on custom interactive elements (pointer, text, grab/grabbing) so their intent can be detected.

## Recording a walkthrough

The optional bigcursor/recording module owns native capture, live sounds, and capture stabilization. It uses the optional chrome-capture@0.1.2 dependency, full Chrome 153+, and Node 24.11+. Install the recording dependencies above; scripts only import package APIs. Save it as record-demo.mjs and run node record-demo.mjs. It starts after app readiness and writes out/demo.mp4 with AV1 video and Opus tab audio; no FFmpeg, extension, virtual audio driver, or permission picker is needed.

```ts
import { chromium } from 'playwright';
import { createCursor } from 'bigcursor';
import { launchForPreset, startRecording } from 'bigcursor/recording';

const { browser, context, preset } = await launchForPreset(chromium, 'archive');
try {
  const page = await context.newPage();
  await page.goto('http://localhost:3000');
  await page.getByRole('button', { name: 'Save' }).waitFor();
  const cursor = await createCursor(page, { scale: 4, seed: 42 });
  const recording = await startRecording(page, preset); // App audio + live click/key sounds
  try {
    await cursor.type(page.getByLabel('Title'), 'Make something great.');
    await cursor.click(page.getByRole('button', { name: 'Save' }));
    await cursor.wait(900);
  } finally {
    try {
      const stats = await recording.stop('out/demo.mp4');
      console.log(stats); // Actual dimensions, audio track, warnings, finalization time
    } finally {
      await cursor.dispose();
    }
  }
} finally {
  await browser.close();
}
```

In the verified bigcursor 1.1.1 release: dimmedOpacity (0.3 by default) is the cursor level while typing or selecting text. Automatic idle dimming is off by default: autoHideTimeout: 0 disables it. A positive timeout such as 500 starts the 180 ms dimming transition after that many milliseconds without mouse activity. Its target is hiddenOpacity (0 by default, fully transparent). Editing dims immediately and lasts 350 ms after the last key/input; mouse movement or clicking clears it, and held pointers keep their drag/selection feedback. The lower applicable opacity wins, without multiplying effects. All three settings work with createCursor and cursor.configure and survive navigation. hideCursor fully hides pointer artwork until showCursor resumes automatic behavior; manual hiding also survives navigation. The homepage gesture demos disable dimming; a dedicated Auto dimming example opts in.

Natural typing is built into createCursor. Set typing: { speed: 'slow' } (3×), 'default' (6×, used when omitted), or 'fast' (8×), or pass speed to cursor.type for one action. Numeric pace (0.25–8) overrides the preset. Only real typing timing changes; pointer movement, presentation holds, and individual sounds stay at normal speed. Explicit delay selects fixed timing. Record at the chosen speed rather than time-compressing video or audio.

The homepage has click, natural typing, selection, drag, and auto-dimming previews, using the package renderer, seeded typing timing, and the same procedural click and Type/Press sound engines as native recording. Audio is synthesized with Web Audio; no sound files are bundled or downloaded. Enable sound to hear the previews; they start muted. Slow, Default, and Fast change typing cadence without speeding up individual sounds. These are visual previews; the accompanying Playwright snippets perform real input. For live effects in your own Playwright session without recording, call installInteractionSounds(page) from bigcursor/recording and dispose the returned controller afterward. createCursor alone does not enable audio.

Await recording.stop before closing the browser. The helper enables app audio and injects quiet live click/typing sounds, including direct text insertion and shortcuts. Set sounds: false for app audio alone or audio: false, sounds: false for silence. These are recording options. createCursor includes varied real key holds and word/sentence pauses directly. Explicit per-call delay opts into fixed timing. Text remains exact. Typing uses the extracted Cuelume Type/Press cue with its MIT notice preserved; sound envelopes stay independent of typing cadence and rapid keystrokes are not throttled. Sounds and their audio contexts are cleaned up at stop. No automatic narration or music mixing is included. Inspect actual motion and audio: encoded dimensions, audio-track presence, and requested FPS alone cannot prove source resolution, audible sound, or distinct captured frames. Default presets request 60fps; 120fps needs suitable hardware and headed Chrome. AV1/Opus compatibility may require a separate H.264/AAC export.

## Verification and safety

Use non-sensitive test data and a local or test app. Ask for missing URL, credentials, or flow requirements; do not guess destructive production actions. Keep videos local unless the user requests sharing. Report the exact script/run command and actual assertion results. Do not replace user interactions with DOM mutation, fake events, or an animation and call that a passing E2E test.

## Limitations

Bigcursor is not a video editor, an autonomous coding agent, or an assertion library. Recording is optional through bigcursor/recording. It does not guarantee capture frame rate. Website previews use visual timelines; createCursor delivers real Playwright input.

Targets are measured before movement and can move afterward; Bigcursor does not reproduce all locator.click actionability checks. selectText assumes ordinary left-to-right selectable text, including nested spans and wrapped lines. For inputs, use cursor.type with selectAll or keyboard shortcuts; specialized editors may need explicit coordinates or keyboard input.

CSS cursor inference has limits for closed shadow roots, cross-origin frames, native controls, and custom cursor images. Busy cursor artwork is static. Browser CSP and permissions still apply. Bundled assets require no remote requests; Bigcursor itself does not upload recordings or send telemetry. Your app and recorder can have their own network behavior.

## More resources

- [Focused examples](https://www.bigcursor.dev/#examples)
- [Pointer Lab](https://www.bigcursor.dev/workbench)
- [Source and issues](https://github.com/seflless/bigcursor)
- [Playwright videos](https://playwright.dev/docs/videos)
- [Playwright assertions](https://playwright.dev/docs/test-assertions)
