Repository navigation
v0.41.0 — a real mouse pointer
Demo recordings can now show a real mouse pointer: an SVG arrow that glides to what it's about to click, pauses, and presses. Viewers see where to look before anything happens.
Added
createHumanCursor(): a visible, human-paced pointer (#51)
import { createHumanCursor, cursorHighlight, resetCursor } from '@argo-video/cli';
await cursorHighlight(page, { mode: 'click' });
const cursor = await createHumanCursor(page, { seed: 'my-demo', size: 30 });
await cursor.click(page.getByRole('button', { name: 'Continue' }));
await cursor.moveTo(page.getByRole('link', { name: 'Details' }), { durationMs: 900 });
await cursor.dispose();
await resetCursor(page);- Natural, repeatable movement. The pointer follows a slightly irregular curve that eases in and out, and a short pause precedes each click. Paths are seeded, so re-recording a demo gives the same motion, which keeps Argo's shader-transition cache valid.
- Real mouse events. Every step of the path is a real
page.mouse.move(), so hover states,cursorHighlight, andtrackCursortelemetry all respond as they would to a person. - Clicks go through Playwright. The press itself uses
locator.click(), so if the layout shifts while the pointer is travelling (a late image, a toast), Playwright waits or retargets instead of clicking the wrong spot. - The pointer doesn't hide the label. It lands inside the control's padding by default.
targetsets a different point inside the element, anddurationMs,dwellMs,holdMsandafterMstune the timing. - Works across a whole demo. It survives page navigation, and one instance can carry through every scene so the pointer never jumps back to the centre. Pair
cursor.click(field)withdemoType()so typing follows visible travel.
cursorHighlight({ mode: 'click' }): brief locator circles
A new mode for cursorHighlight and video.cursorHighlight. Instead of a ring that constantly follows the mouse, a circle briefly contracts toward the pointer tip in three cases: when the pointer first appears, on each click, and when Control or Meta is released on its own. Chords like Control+A and Meta+C don't trigger it.
In click mode the circles sit above overlays and below the pointer. The default mode: 'continuous' is unchanged: the existing ring and click ripple keep their old layers beneath overlays, so recordings made before this release render the same.
A self-contained demo is included at demos/pseudo-cursor.demo.ts. It needs no app server, TTS engine or API keys: watch it.
Contributors
Thank you to @OleksandrKucherenko for #51. It started as a working prototype posted in #37, with a recorded video showing the idea, and grew into a finished feature. Every review point was addressed with a test written before its fix. I reverted the fixes one at a time and each revert failed a test, which is exactly what you want from a test suite. #37 was filed by @salir-admin, who pointed out that a recording with no visible pointer leaves viewers unsure where to look.
The path generation adapts ideas from CloverLabsAI/human-cursor (MIT), and moving via real mouse events follows feder-cr/invisible_playwright (MIT). Both are credited in the source.
Verified
891 tests on Node 20 and 24, Chromium/Firefox/WebKit smoke, and an end-to-end run of the packed tarball. npm audit clean.
Full changelog: v0.40.0...v0.41.0