{"_id":"@webreel/core","_rev":"5-f5145fccda4715b4297e7149d17c21ab","name":"@webreel/core","dist-tags":{"latest":"0.1.4"},"versions":{"0.1.0":{"name":"@webreel/core","version":"0.1.0","keywords":["video","recording","browser","headless","chrome","cdp","screencast","automation"],"license":"Apache-2.0","_id":"@webreel/core@0.1.0","maintainers":[{"name":"ctate","email":"chris@studiotate.com"}],"homepage":"https://github.com/vercel-labs/webreel#readme","bugs":{"url":"https://github.com/vercel-labs/webreel/issues"},"dist":{"shasum":"4f72242765cac1fd1e63f7994bbf79f7356c2191","tarball":"https://registry.npmjs.org/@webreel/core/-/core-0.1.0.tgz","fileCount":94,"integrity":"sha512-HqM7HO8UMVIPk/fCSCDEV3lgDiA1vL4V5jijOD2RaCl3dQiYzHgo/FLLUWjTOsiQ6v74pqK3GTKCM2lJ0dR6ZQ==","signatures":[{"sig":"MEUCIFIlrfIvr1BBqTM5RdS3JgsC7XZTT6WYQrGprtoSEDfAAiEAjw35w+oLsSvXvCFIh32Fjq4l/Q1OZCVtxHHnIzxELnY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":262766},"type":"module","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"583ba72a7d59f64146a4fcebbad4c5634fa32db1","scripts":{"dev":"tsc --watch","test":"vitest run","build":"rm -rf dist && tsc","clean":"rm -rf dist","type-check":"tsc --noEmit"},"_npmUser":{"name":"ctate","email":"chris@studiotate.com"},"repository":{"url":"git+https://github.com/vercel-labs/webreel.git","type":"git","directory":"packages/@webreel/core"},"_npmVersion":"10.9.0","description":"Core recording engine for webreel - headless Chrome capture, cursor animation, and video compositing.","directories":{},"_nodeVersion":"22.12.0","dependencies":{"sharp":"^0.34.5","chrome-remote-interface":"^0.33.2"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"5.9.3","@types/node":"25.3.0","@types/chrome-remote-interface":"^0.33.0"},"_npmOperationalInternal":{"tmp":"tmp/core_0.1.0_1772404766562_0.3179073070438485","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@webreel/core","version":"0.1.1","keywords":["video","recording","browser","headless","chrome","cdp","screencast","automation"],"license":"Apache-2.0","_id":"@webreel/core@0.1.1","maintainers":[{"name":"ctate","email":"chris@studiotate.com"}],"homepage":"https://github.com/vercel-labs/webreel#readme","bugs":{"url":"https://github.com/vercel-labs/webreel/issues"},"dist":{"shasum":"2aaefe0f55c1c0897e623ca913090acffb6ce3b2","tarball":"https://registry.npmjs.org/@webreel/core/-/core-0.1.1.tgz","fileCount":95,"integrity":"sha512-3NOkp94UqF0vxM5GQX4fskt+a9a9ALC26qadP/Y7fkZco01of3jIIACTiGB10RUJ9bg26CjhFYDDrPqnQP2d2Q==","signatures":[{"sig":"MEYCIQC5KXI1Bij73jHVxs/nKP256OV4XiArC7J5OgNQt9JGogIhAINLt0Bji4MMbgStFV6YO0wuU/Q9y1TF55wBqAKk3kqP","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":273745},"type":"module","_from":"file:webreel-core-0.1.1.tgz","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"dev":"tsc --watch","test":"vitest run","build":"rm -rf dist && tsc","clean":"rm -rf dist","type-check":"tsc --noEmit"},"_npmUser":{"name":"ctate","email":"chris@studiotate.com"},"_resolved":"/private/var/folders/bw/l_mkbwg9061dn0frt5258s180000gn/T/7415f89f32623d8507ab7e6280e9bea2/webreel-core-0.1.1.tgz","_integrity":"sha512-3NOkp94UqF0vxM5GQX4fskt+a9a9ALC26qadP/Y7fkZco01of3jIIACTiGB10RUJ9bg26CjhFYDDrPqnQP2d2Q==","repository":{"url":"git+https://github.com/vercel-labs/webreel.git","type":"git","directory":"packages/@webreel/core"},"_npmVersion":"10.9.0","description":"Core recording engine for webreel - headless Chrome capture, cursor animation, and video compositing.","directories":{},"_nodeVersion":"22.12.0","dependencies":{"sharp":"^0.34.5","chrome-remote-interface":"^0.33.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"5.9.3","@types/node":"25.3.0","@types/chrome-remote-interface":"^0.33.0"},"_npmOperationalInternal":{"tmp":"tmp/core_0.1.1_1772405070387_0.9294997608420248","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@webreel/core","version":"0.1.2","keywords":["video","recording","browser","headless","chrome","cdp","screencast","automation"],"license":"Apache-2.0","_id":"@webreel/core@0.1.2","maintainers":[{"name":"ctate","email":"chris@studiotate.com"}],"homepage":"https://github.com/vercel-labs/webreel#readme","bugs":{"url":"https://github.com/vercel-labs/webreel/issues"},"dist":{"shasum":"7349d0469dc0c68db9b4092415d3e7a0b76eaea3","tarball":"https://registry.npmjs.org/@webreel/core/-/core-0.1.2.tgz","fileCount":95,"integrity":"sha512-1l0UThoEdyxU4/0TnpHoNURs3gDgCT+BSiM7+zsoFJR6tAgKjSiHtvlMmvced4FuDOBaphCVCXFwDkb+sG7rOQ==","signatures":[{"sig":"MEUCIF/OJOQYmnhigjCdEUkKvoIKL7CiYp5pYW3qP7DD9G3xAiEAzikoowqe/c4CoX7K1IC0r/J2ge9q2yHN7WzaRCOp6MU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":274538},"type":"module","_from":"file:webreel-core-0.1.2.tgz","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"dev":"tsc --watch","test":"vitest run","build":"rm -rf dist && tsc","clean":"rm -rf dist","type-check":"tsc --noEmit"},"_npmUser":{"name":"ctate","email":"chris@studiotate.com"},"_resolved":"/private/var/folders/bw/l_mkbwg9061dn0frt5258s180000gn/T/982e161831862475ed64c4d8dbe443f9/webreel-core-0.1.2.tgz","_integrity":"sha512-1l0UThoEdyxU4/0TnpHoNURs3gDgCT+BSiM7+zsoFJR6tAgKjSiHtvlMmvced4FuDOBaphCVCXFwDkb+sG7rOQ==","repository":{"url":"git+https://github.com/vercel-labs/webreel.git","type":"git","directory":"packages/@webreel/core"},"_npmVersion":"10.9.0","description":"Core recording engine for webreel - headless Chrome capture, cursor animation, and video compositing.","directories":{},"_nodeVersion":"22.12.0","dependencies":{"sharp":"^0.34.5","chrome-remote-interface":"^0.33.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"5.9.3","@types/node":"25.3.0","@types/chrome-remote-interface":"^0.33.0"},"_npmOperationalInternal":{"tmp":"tmp/core_0.1.2_1772406002265_0.7062623650845707","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@webreel/core","version":"0.1.3","keywords":["video","recording","browser","headless","chrome","cdp","screencast","automation"],"license":"Apache-2.0","_id":"@webreel/core@0.1.3","maintainers":[{"name":"ctate","email":"chris@studiotate.com"}],"homepage":"https://webreel.dev","bugs":{"url":"https://github.com/vercel-labs/webreel/issues"},"dist":{"shasum":"aa24a97b3cbd2fb00b59a7d207065459c0b88536","tarball":"https://registry.npmjs.org/@webreel/core/-/core-0.1.3.tgz","fileCount":95,"integrity":"sha512-4jDNdAWahWNIII8tKwilUmK7iUH+V5FltXR60Bc1J6Z6kTNhVuO6mY6/I/2HAUmkevoQD2D2NSCT+GJ9CCF40Q==","signatures":[{"sig":"MEQCIGXdDiL5Md+KdWp8GUBu1TuPLTohhx0yfmwHtIUzN5frAiAxV6+DJDFD55nh5riL/efVbURo+fPoRokd8+cNy54kbQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":274651},"type":"module","_from":"file:webreel-core-0.1.3.tgz","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"dev":"tsc --watch","test":"vitest run","build":"rm -rf dist && tsc","clean":"rm -rf dist","type-check":"tsc --noEmit"},"_npmUser":{"name":"ctate","email":"chris@studiotate.com"},"_resolved":"/private/var/folders/bw/l_mkbwg9061dn0frt5258s180000gn/T/58c9250e9205b52c627ba6239c30b5ad/webreel-core-0.1.3.tgz","_integrity":"sha512-4jDNdAWahWNIII8tKwilUmK7iUH+V5FltXR60Bc1J6Z6kTNhVuO6mY6/I/2HAUmkevoQD2D2NSCT+GJ9CCF40Q==","repository":{"url":"git+https://github.com/vercel-labs/webreel.git","type":"git","directory":"packages/@webreel/core"},"_npmVersion":"10.9.0","description":"Core recording engine for webreel - headless Chrome capture, cursor animation, and video compositing.","directories":{},"_nodeVersion":"22.12.0","dependencies":{"sharp":"^0.34.5","chrome-remote-interface":"^0.33.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"5.9.3","@types/node":"25.3.0","@types/chrome-remote-interface":"^0.33.0"},"_npmOperationalInternal":{"tmp":"tmp/core_0.1.3_1772406450041_0.4520059947687085","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"@webreel/core","version":"0.1.4","description":"Core recording engine for webreel - headless Chrome capture, cursor animation, and video compositing.","homepage":"https://webreel.dev","repository":{"type":"git","url":"git+https://github.com/vercel-labs/webreel.git","directory":"packages/@webreel/core"},"bugs":{"url":"https://github.com/vercel-labs/webreel/issues"},"keywords":["video","recording","browser","headless","chrome","cdp","screencast","automation"],"license":"Apache-2.0","publishConfig":{"access":"public"},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"engines":{"node":">=18"},"dependencies":{"chrome-remote-interface":"^0.33.2","sharp":"^0.34.5"},"devDependencies":{"@types/chrome-remote-interface":"^0.33.0","@types/node":"25.3.0","typescript":"5.9.3"},"scripts":{"clean":"rm -rf dist","build":"rm -rf dist && tsc","type-check":"tsc --noEmit","dev":"tsc --watch","test":"vitest run"},"_id":"@webreel/core@0.1.4","_integrity":"sha512-RvWZdN4ebsZF1lx3eZNEL5cg7YHSB/MbbaBxFrNGQdcORXjFFvli6n7exwLkknFgfvrFH5qD3O37jOHub4JX8g==","_resolved":"/private/var/folders/bw/l_mkbwg9061dn0frt5258s180000gn/T/7e7e7b1ce652bc6f12aa04160811a2e2/webreel-core-0.1.4.tgz","_from":"file:webreel-core-0.1.4.tgz","_nodeVersion":"22.12.0","_npmVersion":"10.9.0","dist":{"integrity":"sha512-RvWZdN4ebsZF1lx3eZNEL5cg7YHSB/MbbaBxFrNGQdcORXjFFvli6n7exwLkknFgfvrFH5qD3O37jOHub4JX8g==","shasum":"c4bef2f8da2b69de39759f7c4cbdbaa1a75b37cb","tarball":"https://registry.npmjs.org/@webreel/core/-/core-0.1.4.tgz","fileCount":95,"unpackedSize":277022,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDHB58YIVO0MTE/y1zLT7Q7t2PLXYhxCWwyAhJ5i+fMgAiEAzuzb5qjzO9EI73jhnVZ6Ox4f04EXtMIrq9EgZzoaCN8="}]},"_npmUser":{"name":"ctate","email":"chris@studiotate.com"},"directories":{},"maintainers":[{"name":"ctate","email":"chris@studiotate.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/core_0.1.4_1772472774002_0.959691866110209"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-01T22:39:26.456Z","modified":"2026-03-02T17:32:54.330Z","0.1.0":"2026-03-01T22:39:26.697Z","0.1.1":"2026-03-01T22:44:30.548Z","0.1.2":"2026-03-01T23:00:02.423Z","0.1.3":"2026-03-01T23:07:30.206Z","0.1.4":"2026-03-02T17:32:54.185Z"},"bugs":{"url":"https://github.com/vercel-labs/webreel/issues"},"license":"Apache-2.0","homepage":"https://webreel.dev","keywords":["video","recording","browser","headless","chrome","cdp","screencast","automation"],"repository":{"type":"git","url":"git+https://github.com/vercel-labs/webreel.git","directory":"packages/@webreel/core"},"description":"Core recording engine for webreel - headless Chrome capture, cursor animation, and video compositing.","maintainers":[{"name":"ctate","email":"chris@studiotate.com"}],"readme":"# @webreel/core\n\nChrome automation, recording, and overlay engine for webreel.\n\nLaunches a headless Chrome instance via the Chrome DevTools Protocol, captures screenshots at ~60fps, and encodes the result to MP4 with ffmpeg. Provides actions for clicking, typing, dragging, and cursor animation, plus on-screen overlays for keystroke labels and a custom cursor.\n\n## Installation\n\n```bash\nnpm install @webreel/core\n```\n\n## Examples\n\n<!-- EXAMPLES:START -->\n\n**[custom-theme](../../../examples/custom-theme)** - Demonstrates fully customizing the cursor overlay and keystroke HUD appearance using a code editor page.\n\n<video src=\"../../../examples/custom-theme/videos/custom-theme.mp4\" controls muted width=\"100%\"></video>\n\n**[drag-and-drop](../../../examples/drag-and-drop)** - Demonstrates dragging elements between positions on a kanban board.\n\n<video src=\"../../../examples/drag-and-drop/videos/drag-and-drop.mp4\" controls muted width=\"100%\"></video>\n\n**[form-filling](../../../examples/form-filling)** - Demonstrates typing into form fields and clicking a submit button, simulating a login flow.\n\n<video src=\"../../../examples/form-filling/videos/form-filling.mp4\" controls muted width=\"100%\"></video>\n\n**[gif-output](../../../examples/gif-output)** - Demonstrates outputting the recording as an animated GIF instead of the default MP4.\n\n<video src=\"../../../examples/gif-output/videos/gif-output.gif\" controls muted width=\"100%\"></video>\n\n**[hello-world](../../../examples/hello-world)** - The simplest possible webreel example. Opens a landing page and clicks the call-to-action button.\n\n<video src=\"../../../examples/hello-world/videos/hello-world.mp4\" controls muted width=\"100%\"></video>\n\n**[keyboard-shortcuts](../../../examples/keyboard-shortcuts)** - Demonstrates pressing key combos and displaying them in the keystroke HUD overlay. Uses a code editor page as the target.\n\n<video src=\"../../../examples/keyboard-shortcuts/videos/keyboard-shortcuts.mp4\" controls muted width=\"100%\"></video>\n\n**[mobile-viewport](../../../examples/mobile-viewport)** - Demonstrates recording at mobile device dimensions using a finance app interface.\n\n<video src=\"../../../examples/mobile-viewport/videos/mobile-viewport.mp4\" controls muted width=\"100%\"></video>\n\n**[modifier-clicks](../../../examples/modifier-clicks)** - Demonstrates clicking elements with modifier keys held down, simulating multi-select in a file manager.\n\n<video src=\"../../../examples/modifier-clicks/videos/modifier-clicks.mp4\" controls muted width=\"100%\"></video>\n\n**[multi-demo](../../../examples/multi-demo)** - Demonstrates defining multiple videos in a single config file, each producing its own output from the same page.\n\n<video src=\"../../../examples/multi-demo/videos/homepage.mp4\" controls muted width=\"100%\"></video>\n\n**[page-scrolling](../../../examples/page-scrolling)** - Demonstrates scrolling the page and scrolling within a specific container element on a blog post layout.\n\n<video src=\"../../../examples/page-scrolling/videos/page-scrolling.mp4\" controls muted width=\"100%\"></video>\n\n**[screenshots](../../../examples/screenshots)** - Demonstrates capturing PNG screenshots at specific points during a recording. Useful for generating static marketing assets or documentation images alongside videos.\n\n<video src=\"../../../examples/screenshots/videos/screenshots.mp4\" controls muted width=\"100%\"></video>\n\n**[shared-steps](../../../examples/shared-steps)** - Demonstrates using `include` to share common setup steps across videos. The shared steps dismiss a cookie consent banner before the main video steps run.\n\n<video src=\"../../../examples/shared-steps/shared-steps.mp4\" controls muted width=\"100%\"></video>\n\n**[webm-output](../../../examples/webm-output)** - Demonstrates outputting the recording as a WebM video using VP9 encoding.\n\n<video src=\"../../../examples/webm-output/webm-output.webm\" controls muted width=\"100%\"></video>\n\n<!-- EXAMPLES:END -->\n\n## Usage\n\n```ts\nimport {\n  RecordingContext,\n  launchChrome,\n  connectCDP,\n  navigate,\n  clickAt,\n  pressKey,\n  pause,\n  Recorder,\n  InteractionTimeline,\n  compose,\n} from \"@webreel/core\";\n\nconst ctx = new RecordingContext();\nctx.setMode(\"record\");\n\nconst chrome = await launchChrome({ headless: true });\nconst client = await connectCDP(chrome.port);\n\nawait client.Page.enable();\nawait client.Runtime.enable();\nawait client.Emulation.setDeviceMetricsOverride({\n  width: 1080,\n  height: 1080,\n  deviceScaleFactor: 2,\n  mobile: false,\n});\n\nconst timeline = new InteractionTimeline(1080, 1080, { zoom: 2 });\nctx.setTimeline(timeline);\n\nawait navigate(client, \"https://example.com\");\n\nconst recorder = new Recorder(1080, 1080);\nrecorder.setTimeline(timeline);\nawait recorder.start(client, \"demo.mp4\", ctx);\n\nawait pause(500);\nawait clickAt(ctx, client, 540, 400);\nawait pressKey(ctx, client, \"cmd+a\");\nawait pause(1000);\n\nawait recorder.stop();\n\nawait compose(recorder.getTempVideoPath(), timeline.toJSON(), \"demo.mp4\");\n\nawait client.close();\nchrome.kill();\n```\n\n## API\n\n### Chrome\n\n#### `launchChrome(options?): Promise<ChromeInstance>`\n\nLaunches a Chrome process with remote debugging enabled.\n\n| Option     | Type      | Default | Description          |\n| ---------- | --------- | ------- | -------------------- |\n| `headless` | `boolean` | `true`  | Run in headless mode |\n\nReturns a `ChromeInstance` with `process`, `port`, and `kill()`.\n\n### Recorder\n\n#### `new Recorder(width?, height?, assetsDir?)`\n\nCreates a recorder that captures screenshots and encodes them to MP4.\n\n#### `recorder.start(client, outputPath, ctx?): Promise<void>`\n\nBegin capturing frames. Pass an optional `RecordingContext` to track cursor position and timeline events.\n\n#### `recorder.stop(): Promise<void>`\n\nStop capturing, encode to MP4 with sound effects, and clean up temp files.\n\n### Actions\n\nAll action functions that animate the cursor take a `RecordingContext` as their first argument.\n\n| Function                                           | Description                                       |\n| -------------------------------------------------- | ------------------------------------------------- |\n| `navigate(client, url)`                            | Navigate to a URL and wait for load               |\n| `waitForSelector(client, selector, timeout?)`      | Poll until a CSS selector matches                 |\n| `findElementByText(client, text, within?)`         | Find an element's bounding box by text content    |\n| `findElementBySelector(client, selector, within?)` | Find an element's bounding box by CSS selector    |\n| `moveCursorTo(ctx, client, x, y)`                  | Animate the overlay cursor to a position          |\n| `clickAt(ctx, client, x, y, modifiers?)`           | Move cursor and click with optional modifier keys |\n| `pressKey(ctx, client, key, label?)`               | Press a key combo (e.g. `\"cmd+z\"`) with overlay   |\n| `typeText(ctx, client, text, delayMs?)`            | Type text character by character                  |\n| `dragFromTo(ctx, client, fromBox, toBox)`          | Drag between two elements                         |\n| `captureScreenshot(client, outputPath)`            | Save a PNG screenshot                             |\n| `pause(ms?)`                                       | Wait for a duration (default 1200ms)              |\n| `modKey()`                                         | Returns `\"cmd\"` on macOS, `\"ctrl\"` elsewhere      |\n\n### Overlays\n\n| Function                                           | Description                                           |\n| -------------------------------------------------- | ----------------------------------------------------- |\n| `injectOverlays(client, theme?, initialPosition?)` | Add cursor and keystroke overlay elements to the page |\n| `showKeys(client, labels)`                         | Display keystroke labels on screen                    |\n| `hideKeys(client)`                                 | Hide the keystroke overlay                            |\n\n## Prerequisites\n\n- [Google Chrome](https://www.google.com/chrome/) (or Chromium)\n- [ffmpeg](https://ffmpeg.org/)\n\nSet `CHROME_PATH` to override the default Chrome location.\n\n## License\n\nApache-2.0\n","readmeFilename":"README.md"}