Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
0f0f201
fix(type): use insertText for framework-compatible input typing
arielconti10 Mar 5, 2026
26992dc
fix(recording): resolve typeText hang, stale frames, and orphaned Chrome
arielconti10 Mar 5, 2026
b14d5c8
fix(chrome): prevent kill() hang when process already exited
arielconti10 Mar 5, 2026
2c35fe9
fix: annotate chrome cleanup catches
arielconti10 Mar 7, 2026
54db72f
fix: address review findings on typing, process cleanup, and signals
arielconti10 Jul 3, 2026
c0641b4
feat(timeline): record step timing metadata
EfeDurmaz16 May 15, 2026
79621b3
feat: add navigateHref action
brooksy4503 Jun 13, 2026
d43ce1b
feat(dsl): add upload action for file input via CDP setFileInputFiles
Mar 11, 2026
2c30609
perf: compositor prefetch, single-pass GIF, EXDEV rename fallback
arielconti10 Jul 7, 2026
6795762
feat: autozoom from PR 26 by lgariv, adapted
arielconti10 Jul 7, 2026
7303952
fix(core): escape theme strings embedded in the injected overlay script
arielconti10 Jul 18, 2026
cac1e84
fix(core): fail cleanly when the CDP connection errors or drops
arielconti10 Jul 18, 2026
cdfae0a
refactor(webreel): extract shared compositeRecording helper
arielconti10 Jul 18, 2026
8b2a968
refactor(webreel): use compositeRecording in composite command
arielconti10 Jul 18, 2026
d49b0f5
refactor(core): unify GIF filter graph between finalizeGif and compos…
arielconti10 Jul 18, 2026
c185224
refactor(core): remove dead durationS parameter from autozoom API
arielconti10 Jul 18, 2026
3253a9d
test(webreel): add compositing.test.ts for compositeRecording helper
arielconti10 Jul 18, 2026
7009bcf
fix(record): queue watch-mode re-records instead of overlapping runs
arielconti10 Jul 18, 2026
3fca3d4
ci: record example videos in CI to verify the real pipeline
arielconti10 Jul 18, 2026
c5e893c
fix(core): add sha256 digest verification and URL allowlisting to dow…
arielconti10 Jul 18, 2026
e81af8e
docs: sync README config tables and record flags with shipped surface
arielconti10 Jul 18, 2026
c44e62a
test: add v8 coverage instrumentation to both packages
arielconti10 Jul 18, 2026
ebba8cc
fix(core): enforce host allowlist on chrome and ffmpeg download URLs
arielconti10 Jul 18, 2026
6596670
fix(deps): force ws >=7.5.11 and raise engines floor to maintained Node
arielconti10 Jul 18, 2026
97ac9c7
fix(core): verify sha256 of downloaded ffmpeg archives where published
arielconti10 Jul 18, 2026
d7a4ea0
test(core): cover download digest verification and archive path valid…
arielconti10 Jul 18, 2026
6b7f755
fix(deps): constrain ws override to the 7.x line
arielconti10 Jul 18, 2026
8670c02
fix(core): treat ffmpeg pipe failure as abort instead of crash or hang
arielconti10 Jul 18, 2026
2b4e17b
fix(core): wait for cursor path consumption before dispatching the ac…
arielconti10 Jul 18, 2026
857e89b
test(webreel): characterize runVideo orchestration
arielconti10 Jul 18, 2026
06048c7
fix(core): launch Chrome with its sandbox enabled by default
arielconti10 Jul 18, 2026
452c765
test(core): characterize compositor ffmpeg-argument assembly
arielconti10 Jul 18, 2026
32b22c4
test(core): characterize click/key CDP dispatch
arielconti10 Jul 18, 2026
acddc32
ci: run tests with coverage in CI (report-only, non-gating)
arielconti10 Jul 18, 2026
eaee320
fix: remove unused constructor param flagged by eslint
arielconti10 Jul 18, 2026
9207e53
Merge branch 'advisor/006-dedupe-compositing-orchestration' into advi…
arielconti10 Jul 18, 2026
bfd659e
Merge branch 'advisor/008-characterization-tests-coverage' into advis…
arielconti10 Jul 18, 2026
f6cda7f
refactor(core): add shared ffmpeg invocation helper
arielconti10 Jul 18, 2026
d2139da
refactor(config): split config.ts into lib/config/{loader,includes,va…
arielconti10 Jul 18, 2026
982831b
refactor(core): route media.ts through runFfmpegSync helper
arielconti10 Jul 18, 2026
008a821
refactor(core): route applyZoomPass through runFfmpegAsync helper
arielconti10 Jul 18, 2026
4fffce6
refactor(core): route compositeFrames through spawnFfmpegStreaming he…
arielconti10 Jul 18, 2026
c403934
refactor(core): route recorder ffmpeg spawn through spawnFfmpegStream…
arielconti10 Jul 18, 2026
36e13a7
refactor(config): introduce declarative field registry in lib/config/…
arielconti10 Jul 18, 2026
892d7a3
feat(config): generate the JSON Schema from the field registry
arielconti10 Jul 18, 2026
da8484f
ci: add schema drift gate after Build
arielconti10 Jul 18, 2026
5a907d2
test(core): add ffmpeg-run characterization tests; fix dead SIGKILL e…
arielconti10 Jul 18, 2026
1409c73
fix(config): format generated schema through prettier to match the dr…
arielconti10 Jul 18, 2026
c6e5586
Merge branch 'advisor/007-recording-ci-job' into advisor/015-autozoom…
arielconti10 Jul 18, 2026
a87d73f
perf(core): merge zoompan and HUD overlay into one ffmpeg pass
arielconti10 Jul 18, 2026
7309b3c
Merge branch 'advisor/014-config-validation-single-source' into fix/t…
arielconti10 Jul 19, 2026
5e8f563
Merge branch 'advisor/002-cdp-error-disconnect-handlers' into fix/typ…
arielconti10 Jul 19, 2026
5a8b21b
Merge branch 'advisor/003-watch-mode-overlap-guard' into fix/type-ins…
arielconti10 Jul 19, 2026
413d377
Merge branch 'advisor/004-ws-override-node-engines' into fix/type-ins…
arielconti10 Jul 19, 2026
62d4e45
Merge branch 'advisor/005-hud-overlay-escaping' into fix/type-inserttext
arielconti10 Jul 19, 2026
f267dad
Merge branch 'advisor/009-cursor-path-complete-sync' into fix/type-in…
arielconti10 Jul 19, 2026
9caccee
Merge branch 'advisor/010-binary-download-integrity' into fix/type-in…
arielconti10 Jul 19, 2026
33f132e
Merge branch 'advisor/011-chrome-sandbox-default' into fix/type-inser…
arielconti10 Jul 19, 2026
e077ee2
Merge branch 'advisor/012-readme-config-sync' into fix/type-inserttext
arielconti10 Jul 19, 2026
c2897be
test(webreel): expect the onConnectionLost callback in the connectCDP…
arielconti10 Jul 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 51 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,55 @@ jobs:
- name: Build
run: pnpm build

- name: Schema drift check
run: |
pnpm --filter webreel run schema:generate
git diff --exit-code apps/docs/public/schema/v1.json

- name: Test
run: pnpm test
run: pnpm test -- --coverage

record:
needs: ci
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4

- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm

- run: pnpm install --frozen-lockfile

- name: Install ffmpeg
run: |
sudo apt-get update && sudo apt-get install -y ffmpeg
echo "FFMPEG_PATH=$(which ffmpeg)" >> "$GITHUB_ENV"

- name: Cache Chrome for Testing
uses: actions/cache@v4
with:
path: ~/.webreel
key: ${{ runner.os }}-webreel-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-webreel-

- name: Build
run: pnpm build

- name: Record example videos
env:
SKIP_SYNC: "1"
EXAMPLES_FILTER: "hello-world form-filling gif-output"
run: bash scripts/record-examples.sh

- name: Upload recordings on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: recorded-examples
path: examples/*/videos/
retention-days: 7
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ coverage
*.log
package-lock.json
demo-reel.mp4

.idea/
videos/
webreel.config.json
87 changes: 49 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ webreel record hero login
webreel record -c custom.config.json
webreel record --watch
webreel record --verbose
webreel record --dry-run
webreel record --frames
```

### Preview
Expand All @@ -130,7 +132,7 @@ webreel preview hero --verbose

### Composite

Re-composite videos from stored raw recordings and timelines without re-recording:
Re-composite videos from stored raw recordings and timelines without re-recording. Timeline JSON includes cursor frames, sound events, and per-step `startMs` / `endMs` metadata so recordings can be synced with chapters, logs, or other external traces:

```bash
webreel composite
Expand Down Expand Up @@ -165,58 +167,67 @@ webreel record --help

### Actions

| Action | Fields | Description |
| ------------ | ------------------------------------------------------ | ------------------------------------ |
| `pause` | `ms` | Wait for a duration |
| `click` | `text` or `selector`, optional `within`, `modifiers` | Move cursor to an element and click |
| `key` | `key` (e.g. `"cmd+z"`), optional `label` | Press a key or key combo |
| `type` | `text`, optional `target`, `charDelay` | Type text character by character |
| `scroll` | optional `x`, `y`, `selector` | Scroll the page or an element |
| `wait` | `selector` or `text`, optional `timeout` | Wait for an element to appear |
| `screenshot` | `output` | Capture a PNG screenshot |
| `drag` | `from` and `to` (each with `text`/`selector`/`within`) | Drag from one element to another |
| `moveTo` | `text` or `selector`, optional `within` | Move cursor to an element |
| `navigate` | `url` | Navigate to a new URL mid-video |
| `hover` | `text` or `selector`, optional `within` | Hover over an element (triggers CSS) |
| `select` | `selector`, `value` | Select a value in a dropdown |
| Action | Fields | Description |
| -------------- | ------------------------------------------------------------ | ------------------------------------ |
| `pause` | `ms` | Wait for a duration |
| `click` | `text` or `selector`, optional `within`, `modifiers` | Move cursor to an element and click |
| `key` | `key` (e.g. `"cmd+z"`), optional `label` | Press a key or key combo |
| `type` | `text`, optional `selector`, `within`, `charDelay`, `method` | Type text character by character |
| `scroll` | optional `x`, `y`, `selector` | Scroll the page or an element |
| `wait` | `selector` or `text`, optional `timeout` | Wait for an element to appear |
| `screenshot` | `output` | Capture a PNG screenshot |
| `drag` | `from` and `to` (each with `text`/`selector`/`within`) | Drag from one element to another |
| `moveTo` | `text` or `selector`, optional `within` | Move cursor to an element |
| `navigate` | `url` | Navigate to a new URL mid-video |
| `navigateHref` | `selector` | Navigate to a link element's href |
| `hover` | `text` or `selector`, optional `within` | Hover over an element (triggers CSS) |
| `select` | `selector`, `value` | Select a value in a dropdown |
| `upload` | `selector`, `filePath` | Set a file on a file input |

All steps (except `pause`) accept an optional `delay` field (ms to wait after the step). Use `defaultDelay` at the top-level or per-video to set a default.

### Config options

#### Top-level

| Field | Default | Description |
| -------------- | --------- | -------------------------------------------- |
| `$schema` | - | JSON Schema URL for IDE autocompletion |
| `outDir` | `videos/` | Default output directory for videos |
| `baseUrl` | `""` | Prepended to relative video URLs |
| `viewport` | 1080x1080 | Default browser viewport dimensions |
| `theme` | - | Default cursor and HUD overlay customization |
| `include` | - | Array of step files prepended to all videos |
| `defaultDelay` | - | Default delay (ms) after each step |
| `videos` | required | Object mapping video names to their configs |
| Field | Default | Description |
| -------------- | --------------- | ------------------------------------------------------------ |
| `$schema` | - | JSON Schema URL for IDE autocompletion |
| `outDir` | `videos/` | Default output directory for videos |
| `baseUrl` | `""` | Prepended to relative video URLs |
| `viewport` | 1080x1080 | Default browser viewport dimensions |
| `theme` | - | Default cursor and HUD overlay customization |
| `include` | - | Array of step files prepended to all videos |
| `defaultDelay` | - | Default delay (ms) after each step |
| `clickDwell` | random 80-180ms | Milliseconds the cursor pauses before clicking (0 = instant) |
| `sfx` | - | Sound effects configuration for click and keystroke sounds |
| `videos` | required | Object mapping video names to their configs |

#### Per-video

| Field | Default | Description |
| -------------- | ------------- | ------------------------------------------------------ |
| `url` | required | URL to navigate to |
| `baseUrl` | inherited | Prepended to relative URLs |
| `viewport` | inherited | Browser viewport dimensions |
| `zoom` | - | CSS zoom level applied to the page |
| `waitFor` | - | CSS selector to wait for before start |
| `output` | `<name>.mp4` | Output file path (.mp4, .gif, or .webm) |
| `thumbnail` | `{ time: 0 }` | Object with `time` (seconds) or `enabled: false` |
| `include` | inherited | Array of paths to JSON files whose steps are prepended |
| `theme` | inherited | Cursor and HUD overlay customization |
| `defaultDelay` | inherited | Default delay (ms) after each step |
| Field | Default | Description |
| -------------- | ------------- | ---------------------------------------------------------- |
| `url` | required | URL to navigate to |
| `baseUrl` | inherited | Prepended to relative URLs |
| `viewport` | inherited | Browser viewport dimensions |
| `zoom` | - | CSS zoom level applied to the page |
| `fps` | `60` | Recording frame rate (1-120) |
| `quality` | `80` | Output quality (1-100); higher values produce larger files |
| `waitFor` | - | CSS selector to wait for before start |
| `output` | `<name>.mp4` | Output file path (.mp4, .gif, or .webm) |
| `thumbnail` | `{ time: 0 }` | Object with `time` (seconds) or `enabled: false` |
| `include` | inherited | Array of paths to JSON files whose steps are prepended |
| `theme` | inherited | Cursor and HUD overlay customization |
| `defaultDelay` | inherited | Default delay (ms) after each step |
| `clickDwell` | inherited | Milliseconds the cursor pauses before clicking |
| `sfx` | inherited | Sound effects configuration for click and keystroke sounds |
| `autoZoom` | `false` | Cinematic zoom into each action (bool or object) |

## Development

### Prerequisites

- [Node.js](https://nodejs.org/) (v18+)
- [Node.js](https://nodejs.org/) (v20+)
- [pnpm](https://pnpm.io/)

### Setup
Expand Down
Loading