recordable 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/README.md +198 -44
  2. package/dist/actions.d.ts +8 -0
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +11 -5
  5. package/dist/actions.js.map +1 -1
  6. package/dist/audio/track.d.ts +10 -0
  7. package/dist/audio/track.d.ts.map +1 -1
  8. package/dist/audio/track.js +19 -0
  9. package/dist/audio/track.js.map +1 -1
  10. package/dist/browser/cursor.d.ts +8 -6
  11. package/dist/browser/cursor.d.ts.map +1 -1
  12. package/dist/browser/cursor.js +32 -21
  13. package/dist/browser/cursor.js.map +1 -1
  14. package/dist/browser/dom.d.ts +33 -13
  15. package/dist/browser/dom.d.ts.map +1 -1
  16. package/dist/browser/dom.js +158 -56
  17. package/dist/browser/dom.js.map +1 -1
  18. package/dist/browser/page-zoom.d.ts +11 -0
  19. package/dist/browser/page-zoom.d.ts.map +1 -0
  20. package/dist/browser/page-zoom.js +37 -0
  21. package/dist/browser/page-zoom.js.map +1 -0
  22. package/dist/browser/play-button.d.ts.map +1 -1
  23. package/dist/browser/play-button.js.map +1 -1
  24. package/dist/browser/runtime.d.ts +1 -0
  25. package/dist/browser/runtime.d.ts.map +1 -1
  26. package/dist/browser/runtime.js +22 -14
  27. package/dist/browser/runtime.js.map +1 -1
  28. package/dist/browser/targets.d.ts.map +1 -0
  29. package/dist/{targets.js → browser/targets.js} +3 -2
  30. package/dist/browser/targets.js.map +1 -0
  31. package/dist/compose/boundaries.d.ts +13 -0
  32. package/dist/compose/boundaries.d.ts.map +1 -0
  33. package/dist/compose/boundaries.js +49 -0
  34. package/dist/compose/boundaries.js.map +1 -0
  35. package/dist/compose/mix.d.ts +3 -2
  36. package/dist/compose/mix.d.ts.map +1 -1
  37. package/dist/compose/mix.js +9 -4
  38. package/dist/compose/mix.js.map +1 -1
  39. package/dist/compose/recordable.d.ts +28 -3
  40. package/dist/compose/recordable.d.ts.map +1 -1
  41. package/dist/compose/recordable.js +75 -18
  42. package/dist/compose/recordable.js.map +1 -1
  43. package/dist/compose/session.d.ts +20 -8
  44. package/dist/compose/session.d.ts.map +1 -1
  45. package/dist/compose/session.js +120 -38
  46. package/dist/compose/session.js.map +1 -1
  47. package/dist/config.d.ts.map +1 -1
  48. package/dist/config.js +4 -3
  49. package/dist/config.js.map +1 -1
  50. package/dist/errors.d.ts +1 -1
  51. package/dist/errors.d.ts.map +1 -1
  52. package/dist/errors.js.map +1 -1
  53. package/dist/ffmpeg.d.ts +3 -0
  54. package/dist/ffmpeg.d.ts.map +1 -1
  55. package/dist/ffmpeg.js +22 -4
  56. package/dist/ffmpeg.js.map +1 -1
  57. package/dist/formats/json.d.ts +2 -1
  58. package/dist/formats/json.d.ts.map +1 -1
  59. package/dist/formats/json.js.map +1 -1
  60. package/dist/formats/markdown/method.d.ts.map +1 -1
  61. package/dist/formats/markdown/method.js +4 -3
  62. package/dist/formats/markdown/method.js.map +1 -1
  63. package/dist/fs.d.ts +16 -0
  64. package/dist/fs.d.ts.map +1 -1
  65. package/dist/fs.js +33 -4
  66. package/dist/fs.js.map +1 -1
  67. package/dist/index.d.ts +1 -0
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/logger.d.ts.map +1 -1
  70. package/dist/logger.js +3 -1
  71. package/dist/logger.js.map +1 -1
  72. package/dist/result.d.ts +30 -0
  73. package/dist/result.d.ts.map +1 -0
  74. package/dist/result.js +8 -0
  75. package/dist/result.js.map +1 -0
  76. package/dist/timing.d.ts +2 -0
  77. package/dist/timing.d.ts.map +1 -1
  78. package/dist/timing.js +10 -4
  79. package/dist/timing.js.map +1 -1
  80. package/dist/validate.d.ts.map +1 -1
  81. package/dist/validate.js +11 -10
  82. package/dist/validate.js.map +1 -1
  83. package/dist/video/recorder.d.ts +26 -3
  84. package/dist/video/recorder.d.ts.map +1 -1
  85. package/dist/video/recorder.js +50 -32
  86. package/dist/video/recorder.js.map +1 -1
  87. package/dist/video/stitch.js +3 -17
  88. package/dist/video/stitch.js.map +1 -1
  89. package/dist/voiceover/compile.d.ts.map +1 -1
  90. package/dist/voiceover/compile.js +42 -24
  91. package/dist/voiceover/compile.js.map +1 -1
  92. package/dist/voiceover/elevenlabs.d.ts.map +1 -1
  93. package/dist/voiceover/elevenlabs.js +41 -11
  94. package/dist/voiceover/elevenlabs.js.map +1 -1
  95. package/dist/voiceover/mock.d.ts.map +1 -1
  96. package/dist/voiceover/mock.js +38 -15
  97. package/dist/voiceover/mock.js.map +1 -1
  98. package/package.json +20 -6
  99. package/recordable.schema.json +81 -0
  100. package/dist/targets.d.ts.map +0 -1
  101. package/dist/targets.js.map +0 -1
  102. /package/dist/{targets.d.ts → browser/targets.d.ts} +0 -0
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # recordable
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/recordable.svg)](https://www.npmjs.com/package/recordable)
4
+
3
5
  Programmatic, repeatable browser screen recording. Describe a session as a fluent
4
6
  chain of actions — `visit`, `click`, `type`, `zoom`, `scroll` — and `recordable`
5
7
  drives a real [Puppeteer](https://pptr.dev/) browser and captures a clean MP4,
@@ -22,12 +24,14 @@ await new Recordable({ typingSpeed: 120 })
22
24
  .scroll("bottom")
23
25
  .resetZoom()
24
26
  .wait(1500)
25
- .run(); // finalises automatically — no start()/stop()
27
+ .run(); // finalises automatically — bookends are optional
26
28
  ```
27
29
 
28
- Recording is **on by default** and finalises when `.run()` ends there's no
29
- `start()`/`stop()`. Use `pause()` / `resume()` to carve out anything you don't
30
- want on camera; every captured segment is stitched into one seamless MP4.
30
+ Recording is **on by default** and finalises when `.run()` ends. Use `pause()` /
31
+ `resume()` to carve out anything you don't want on camera; every captured segment
32
+ is stitched into one seamless MP4. Need explicit bookends or several output files?
33
+ `start()` / `end()` / `split()` move the file boundaries (see
34
+ [Multiple output files](#multiple-output-files-start--end--split)).
31
35
 
32
36
  ## Features
33
37
 
@@ -45,9 +49,10 @@ want on camera; every captured segment is stitched into one seamless MP4.
45
49
  - **Manual steps / logins** — `resumeOnPlay()` waits for an in-page ▶ Play button
46
50
  (see below), so you can sign in by hand before recording.
47
51
  - **Auto-scroll** to bring elements into view before interacting.
48
- - **Declarative JSON scripts + CLI** — author a recording as JSON (with a published
49
- schema for editor autocomplete) and run it with `npx recordable demo.json`, no
50
- install or TypeScript required.
52
+ - **Declarative scripts (JSON _or_ Markdown) + CLI** — author a recording as data,
53
+ not code, and run it with `npx recordable demo.json` / `demo.md`, no install or
54
+ TypeScript required. JSON ships a published schema for editor autocomplete;
55
+ Markdown adds prose narration for voiceover.
51
56
 
52
57
  ## Install
53
58
 
@@ -57,7 +62,7 @@ npm install recordable
57
62
 
58
63
  Frames are captured via the Chrome DevTools Protocol and encoded with **FFmpeg** —
59
64
  there's no external screen-recorder dependency. The ffmpeg binary ships via
60
- [`@ffmpeg-installer/ffmpeg`](https://www.npmjs.com/package/@ffmpeg-installer/ffmpeg),
65
+ [`ffmpeg-static`](https://www.npmjs.com/package/ffmpeg-static),
61
66
  so there's nothing else to install (a system `ffmpeg` on your `PATH` is used as a
62
67
  fallback).
63
68
 
@@ -93,27 +98,132 @@ local copy) and your editor gives you autocomplete, required-key checking, and
93
98
  typo catching for every action — no TypeScript needed. The schema is published as
94
99
  `recordable.schema.json`.
95
100
 
96
- Run a script from code with `runScript` (or `fromJSON` to build without running):
101
+ Run a JSON script from code by handing it to a `Recordable` a parsed object or
102
+ the raw file string both work:
103
+
104
+ ```ts
105
+ import { readFileSync } from "node:fs";
106
+ import { Recordable } from "recordable";
107
+
108
+ const script = readFileSync("./demo.json", "utf8");
109
+ await new Recordable({ baseDir: "." }).fromJSON(script).run();
110
+ ```
111
+
112
+ `baseDir` is the script's folder — `recordable` resolves relative `visit` URLs
113
+ and a relative `outputDir` against it. (Standalone `runScript` / `fromJSON`
114
+ helpers are also exported if you prefer a single call.)
115
+
116
+ ## Declarative scripts (Markdown)
117
+
118
+ Markdown is the richest authoring surface — the **same actions as JSON**, written
119
+ as backtick method-call spans, with optional narration prose woven around them for
120
+ voiceover. YAML frontmatter carries the [config](#configuration); an optional
121
+ `voiceover` block opts into narration audio (`voiceover: true` reads provider /
122
+ voice from the environment, or pass an object to set them inline).
123
+
124
+ Two flavours, mixable in one document:
125
+
126
+ **1. A fenced action list** — one call per line, no prose. The closest Markdown
127
+ gets to JSON; compiles to the exact same actions:
128
+
129
+ ````md
130
+ ---
131
+ viewport: { width: 1280, height: 800 }
132
+ ---
133
+
134
+ ```
135
+ pause()
136
+ visit("./index.html")
137
+ resume()
138
+ zoom(1.4, { origin: "#email" })
139
+ type("#email", "hello@example.com")
140
+ click("text:Sign up", { waitForNav: true })
141
+ waitFor("text:Thanks", { state: "visible" })
142
+ resetZoom()
143
+ ```
144
+ ````
145
+
146
+ **2. Inline markers in prose** — drop call spans into narration; each fires at its
147
+ position in the spoken line. With `voiceover` on, the prose is read aloud and waits
148
+ are timed to the narration:
149
+
150
+ ```md
151
+ ---
152
+ typingSpeed: 16
153
+ voiceover: true
154
+ ---
155
+
156
+ `visit("./signin.html")` Welcome — first we sign in with our work account
157
+ `type("#email", "maya@example.com")` then our password
158
+ `type("#password", "•••••")` `click("#signInBtn", { waitForNav: true })` — and
159
+ we're straight into the dashboard.
160
+ ```
161
+
162
+ Each backtick span holds exactly one call; its arguments are the method's
163
+ arguments, identical to the chainable API and the JSON `action` keys. Whole-line
164
+ `//` comments are stripped before parsing, so toggle-comment in your editor is
165
+ safe. Run a Markdown file through the [CLI](#cli) (`npx recordable demo.md`) or
166
+ from code:
97
167
 
98
168
  ```ts
99
- import { runScript } from "recordable";
100
- import demo from "./demo.json" with { type: "json" };
169
+ import { readFileSync } from "node:fs";
170
+ import { Recordable } from "recordable";
101
171
 
102
- await runScript(demo);
172
+ const md = readFileSync("./demo.md", "utf8");
173
+ await new Recordable({ baseDir: "." }).fromMarkdown(md).run();
103
174
  ```
104
175
 
105
- ### CLI
176
+ ## Voiceover
106
177
 
107
- Or run a JSON file directly **no install required** via `npx`:
178
+ A Markdown script can narrate itself. The prose around your inline markers becomes
179
+ spoken audio (text-to-speech), and the markers are **timed to the narration** — each
180
+ action fires at its position in the spoken line, so the demo and the voice stay in
181
+ sync without hand-tuned `wait`s.
182
+
183
+ Opt in from frontmatter. With credentials in the environment, `voiceover: true` is
184
+ all a document needs; spell out a `voiceover` object to set provider / voice / model
185
+ inline (it overrides the environment):
186
+
187
+ ```yaml
188
+ voiceover: true
189
+ ```
190
+
191
+ ```yaml
192
+ voiceover:
193
+ provider: elevenlabs # or `mock` for silent, offline audio
194
+ voiceId: EXAVITQu4vr4xnSDxMaL
195
+ modelId: eleven_multilingual_v2
196
+ ```
197
+
198
+ **Credentials & defaults** come from a `.env` loaded automatically from **beside the
199
+ document** (copy [`.env.example`](.env.example)):
200
+
201
+ ```sh
202
+ ELEVENLABS_API_KEY=... # required for real synthesis
203
+ RECORDABLE_TTS_PROVIDER=elevenlabs # or `mock` for silent, offline audio
204
+ RECORDABLE_VOICE_ID=... # default voice when frontmatter omits it
205
+ RECORDABLE_MODEL_ID=eleven_multilingual_v2
206
+ ```
207
+
208
+ Generated audio is written to the `assetsDir` (default `assets/`, beside the output)
209
+ and cached, so re-running an unchanged script doesn't re-synthesize. Validate a
210
+ voiceover script without hitting the TTS API — or a browser — with `recordable
211
+ demo.md --check`. For a music bed or a hand-recorded narration file, drop it straight
212
+ onto the timeline with `audio(path, opts?)` (see the [API](#recording)).
213
+
214
+ ## CLI
215
+
216
+ Run a JSON **or** Markdown file directly — **no install required** via `npx`:
108
217
 
109
218
  ```sh
110
219
  npx recordable demo.json
220
+ npx recordable demo.md
111
221
  ```
112
222
 
113
223
  ```
114
- recordable <script.json> [options]
224
+ recordable <script.json | script.md> [options]
115
225
 
116
- --check Validate the script and exit (no browser, no recording)
226
+ --check Validate the script and exit (no browser, no audio, no recording)
117
227
  --headless Run without a visible browser window
118
228
  --silent Suppress recorder console output
119
229
  --out-dir <dir> Output directory (overrides the script's config)
@@ -195,8 +305,9 @@ new Recordable()
195
305
  ```
196
306
 
197
307
  No `pause()`/`resume()` needed — `insert` seals the current segment and recording
198
- resumes into a fresh one on the next action automatically. (Audio on the clip is
199
- currently dropped; voiceover support is on the roadmap.)
308
+ resumes into a fresh one on the next action automatically. (Audio on the inserted
309
+ clip itself is currently dropped — narration voiceover is a separate, supported
310
+ feature, authored in [Markdown](#declarative-scripts-markdown).)
200
311
 
201
312
  **Cross-fades.** Pass `fadeIn` / `fadeOut` (ms) to dissolve rather than hard-cut.
202
313
  A fade blends the clip with the **neighbouring recorded footage** (a true
@@ -206,6 +317,39 @@ on `fadeOut`, while an outro's `fadeOut` dissolves down to black. Omit them for
206
317
  hard cut. A cross-fade of _d_ ms overlaps the two pieces by _d_, shortening the
207
318
  timeline by that much at each faded boundary.
208
319
 
320
+ ## Multiple output files (`start` / `end` / `split`)
321
+
322
+ `pause()`/`resume()` carve off-camera gaps **within one file**. To produce
323
+ **separate files**, move the file boundaries with `start()` / `end()` / `split()`:
324
+
325
+ ```ts
326
+ await new Recordable({ outputName: "demo" })
327
+ .start("intro") // open the first file (content before it is off-camera)
328
+ .visit("https://example.com")
329
+ .click("text:Get started")
330
+ .split("checkout") // close "intro", open the next — camera keeps rolling
331
+ .click("text:Buy")
332
+ .end() // close "checkout"; the teardown below runs off-camera
333
+ .click("text:Sign out")
334
+ .run(); // → demo-intro.mp4, demo-checkout.mp4
335
+ ```
336
+
337
+ - **Boundaries default to the script edges.** With no `start()`, recording opens
338
+ at the top; with no `end()`, it closes at the bottom — so a plain script is one
339
+ file, exactly as before. Add only the bookend you need.
340
+ - **`pause`/`resume` ≠ `start`/`end`.** `resume()` continues the _same_ file (the
341
+ gap is stitched out); `start()`/`split()` open a _new_ file. `split() ≡ end() +
342
+ start()` fused with no gap; for two files _with_ an off-camera gap between them,
343
+ use `end()` … `start()`.
344
+ - **Naming.** Each file is `${outputName}-${label ?? index}.mp4`; a label always
345
+ wins. A single unlabelled file stays `${outputName}.mp4`.
346
+ - **Audio is per-file** — each output is standalone with its own zero-based
347
+ timeline; a clip is assigned to the file containing its start.
348
+
349
+ `run()` resolves to a `RecordableResult` — `{ status, files: [{ path, label,
350
+ index, durationMs, bytes }], outputDir, durationMs, elapsedMs, warnings }` — so
351
+ you can find every file that was written. Hard failures throw instead.
352
+
209
353
  ## API
210
354
 
211
355
  Create an instance with optional [config](#configuration), chain actions, then
@@ -213,16 +357,22 @@ Create an instance with optional [config](#configuration), chain actions, then
213
357
 
214
358
  ### Recording
215
359
 
216
- Recording is on by default and finalises automatically on `.run()`. These control
217
- what lands on camera:
218
-
219
- | Method | Description |
220
- | ------------------------ | ----------------------------------------------------------------------------------------------------------------- |
221
- | `pause()` | Stop capturing; the chain keeps running off-camera. |
222
- | `resume()` | Resume capturing in a fresh segment, immediately. |
223
- | `waitForPlay(message?)` | Block until the user clicks the in-page ▶ Play button (or presses Enter); leaves recording state untouched. |
224
- | `resumeOnPlay(message?)` | Wait for Play, then resume capturing — `waitForPlay().resume()`. |
225
- | `insert(path, opts?)` | Splice an external clip (intro / outro / mid-roll) into the timeline; `opts.fadeIn`/`fadeOut` (ms) cross-fade it. |
360
+ Recording is on by default and finalises automatically on `.run()`, which resolves
361
+ to a [`RecordableResult`](#multiple-output-files-start--end--split). `pause`/`resume`
362
+ control what lands on camera _within_ a file; `start`/`end`/`split` move the file
363
+ boundaries to produce [separate files](#multiple-output-files-start--end--split):
364
+
365
+ | Method | Description |
366
+ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
367
+ | `pause()` | Stop capturing; the chain keeps running off-camera. |
368
+ | `resume()` | Resume capturing in a fresh segment, immediately. |
369
+ | `start(name?)` | Open an output file (opening boundary); content before the first `start()` is off-camera. `name` labels the file. |
370
+ | `end()` | Close the current output file (closing boundary); content after it runs off-camera. |
371
+ | `split(name?)` | Close the current file and open the next in one move, camera still rolling — `end()` + `start()` with no gap. |
372
+ | `waitForPlay(message?)` | Block until the user clicks the in-page ▶ Play button (or presses Enter); leaves recording state untouched. |
373
+ | `resumeOnPlay(message?)` | Wait for ▶ Play, then resume capturing — `waitForPlay().resume()`. |
374
+ | `insert(path, opts?)` | Splice an external clip (intro / outro / mid-roll) into the timeline; `opts.fadeIn`/`fadeOut` (ms) cross-fade it. |
375
+ | `audio(path, opts?)` | Lay an existing audio file (mp3/wav) onto the timeline here — narration, music bed, SFX. Blocks until the clip ends by default (`opts.wait: false` plays it over following actions); `opts.volume` gains it. |
226
376
 
227
377
  ### Navigation & waiting
228
378
 
@@ -234,15 +384,15 @@ what lands on camera:
234
384
 
235
385
  ### Interactions
236
386
 
237
- | Method | Description |
238
- | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
387
+ | Method | Description |
388
+ | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
239
389
  | `click(target, { waitForNav?, followNewTab? })` | Click an element. Returns immediately by default; pass `{ waitForNav: true }` when the click triggers a full-page navigation, or `{ followNewTab: true }` to keep recording in a tab the click opens (see notes below). |
240
- | `hover(target)` | Move onto an element to reveal `:hover` state (no click). |
241
- | `type(target, text, { duration? })` | Type into a field with human-like timing; `duration` (ms) spreads keystrokes evenly with no jitter. |
242
- | `clear(target)` | Select-all + delete the contents of a field. |
243
- | `select(target, value)` | Choose an option in a native `<select>` by `value`, or by `:option-index(N)` / `:option-label(Text)` (see note below; OS-drawn list isn't captured). |
244
- | `key(key)` | Press a key, e.g. `"Escape"`, `"Enter"`, `"Tab"`. |
245
- | `mouse(target \| {x, y})` | Move the cursor to an element or coordinates. |
390
+ | `hover(target)` | Move onto an element to reveal `:hover` state (no click). |
391
+ | `type(target, text, { duration? })` | Type into a field with human-like timing; `duration` (ms) spreads keystrokes evenly with no jitter. |
392
+ | `clear(target)` | Select-all + delete the contents of a field. |
393
+ | `select(target, value)` | Choose an option in a native `<select>` by `value`, or by `:option-index(N)` / `:option-label(Text)` (see note below; OS-drawn list isn't captured). |
394
+ | `key(key)` | Press a key, e.g. `"Escape"`, `"Enter"`, `"Tab"`. |
395
+ | `mouse(target \| {x, y})` | Move the cursor to an element or coordinates. |
246
396
 
247
397
  > The browser draws an open `<select>`'s option list with the OS, outside the page,
248
398
  > so the screencast can't capture it — `select()` shows the cursor and the value
@@ -267,12 +417,12 @@ what lands on camera:
267
417
 
268
418
  ### Camera
269
419
 
270
- | Method | Description |
271
- | ------------------------------------- | ----------------------------------------------------------------- |
272
- | `scroll(target, { duration? })` | Smooth-scroll to `"top"`/`"bottom"`, a selector, or a Y position. |
273
- | `zoom(level, { origin?, duration? })` | Smoothly scale from an origin (keyword, `%`, or selector). |
274
- | `resetZoom({ duration? })` | Smoothly return to 1×. |
275
- | `setConfig(config)` | Merge config mid-sequence (takes effect at that point). |
420
+ | Method | Description |
421
+ | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
422
+ | `scroll(target, { container?, duration? })` | Smooth-scroll to `"top"`/`"bottom"`, a selector, or a Y position. `container` scrolls a named overflow pane (modal, sidebar, list) instead of the window. |
423
+ | `zoom(level, { origin?, duration? })` | Smoothly scale from an origin (keyword, `%`, or selector). |
424
+ | `resetZoom({ duration? })` | Smoothly return to 1×. |
425
+ | `setConfig(config)` | Merge config mid-sequence (takes effect at that point). |
276
426
 
277
427
  ### Targeting
278
428
 
@@ -305,11 +455,13 @@ new Recordable({
305
455
  viewport: { width: 1920, height: 1080 },
306
456
  pageZoom: 1, // browser page zoom (Ctrl +/−); <1 reflows to fit more on screen
307
457
  fps: 30,
308
- outputDir: "./output",
458
+ outputDir: "output", // relative paths resolve against baseDir
309
459
  outputName: "recordable",
310
460
  outputTimestamp: true, // prepend an ISO timestamp to the filename
461
+ assetsDir: "assets", // where generated voiceover audio is written (relative to baseDir)
311
462
  headless: false,
312
- language: "", // BCP-47 locale, e.g. "fr-FR" (--lang + Accept-Language); "" = system
463
+ launchArgs: [], // extra Chromium flags, e.g. ["--no-sandbox"] for CI/containers
464
+ language: "", // BCP-47 locale, e.g. "fr-FR" (--lang + --accept-lang + Accept-Language); "" = system
313
465
  typingSpeed: 7, // characters per second
314
466
  videoCrf: 18, // lower = better quality, larger file
315
467
  videoCodec: "libx264",
@@ -323,6 +475,7 @@ new Recordable({
323
475
  scrollDuration: 1200, // ms for the scroll action's transition
324
476
  cursor: true, // show the animated cursor overlay
325
477
  visitTimeout: 30_000, // ms for navigation / waitFor
478
+ baseDir: "", // dir that relative visit URLs, outputDir & assetsDir resolve against; "" = cwd
326
479
  });
327
480
  ```
328
481
 
@@ -336,6 +489,7 @@ npm test # unit + ffmpeg I/O tests
336
489
  npm run test:e2e # opt-in end-to-end pipeline run (launches a browser)
337
490
  npx tsx my-script.ts # run a recording script directly
338
491
  node dist/cli.js demo.json # run a JSON script through the CLI locally
492
+ node dist/cli.js demo.md # run a Markdown script through the CLI locally
339
493
  ```
340
494
 
341
495
  The JSON action set and its schema are both generated from one manifest in
package/dist/actions.d.ts CHANGED
@@ -4,6 +4,13 @@ import * as z from "zod";
4
4
  * discriminator). strictObject so an unknown key (a typo) fails validation.
5
5
  */
6
6
  declare const ACTIONS: {
7
+ start: z.ZodObject<{
8
+ name: z.ZodOptional<z.ZodString>;
9
+ }, z.core.$strict>;
10
+ end: z.ZodObject<{}, z.core.$strict>;
11
+ split: z.ZodObject<{
12
+ name: z.ZodOptional<z.ZodString>;
13
+ }, z.core.$strict>;
7
14
  pause: z.ZodObject<{}, z.core.$strict>;
8
15
  resume: z.ZodObject<{}, z.core.$strict>;
9
16
  waitForPlay: z.ZodObject<{
@@ -100,6 +107,7 @@ declare const ACTIONS: {
100
107
  }, z.core.$strict>;
101
108
  scroll: z.ZodObject<{
102
109
  target: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
110
+ container: z.ZodOptional<z.ZodString>;
103
111
  duration: z.ZodOptional<z.ZodNumber>;
104
112
  }, z.core.$strict>;
105
113
  zoom: z.ZodObject<{
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAezB;;;GAGG;AACH,QAAA,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+D0B,CAAC;AAYxC,sEAAsE;AACtE,MAAM,MAAM,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAuChE;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAgBjD;AAED;;;;;;GAMG;AACH,iBAAS,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAcxD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,CA2C3E;AAED,wEAAwE;AACxE,OAAO,EAAE,OAAO,EAAE,CAAC;AAEnB,iFAAiF;AACjF,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAezB;;;GAGG;AACH,QAAA,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmE0B,CAAC;AAcxC,sEAAsE;AACtE,MAAM,MAAM,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAuChE;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAgBjD;AAED;;;;;;GAMG;AACH,iBAAS,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAcxD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,CAkD3E;AAED,wEAAwE;AACxE,OAAO,EAAE,OAAO,EAAE,CAAC;AAEnB,iFAAiF;AACjF,OAAO,EAAE,SAAS,EAAE,CAAC"}
package/dist/actions.js CHANGED
@@ -16,6 +16,9 @@ const XY = z.strictObject({ x: z.number(), y: z.number() });
16
16
  */
17
17
  const ACTIONS = {
18
18
  // Recording control
19
+ start: z.strictObject({ name: z.string().optional() }),
20
+ end: z.strictObject({}),
21
+ split: z.strictObject({ name: z.string().optional() }),
19
22
  pause: z.strictObject({}),
20
23
  resume: z.strictObject({}),
21
24
  waitForPlay: z.strictObject({ message: z.string().optional() }),
@@ -63,6 +66,7 @@ const ACTIONS = {
63
66
  // Scrolling / zoom
64
67
  scroll: z.strictObject({
65
68
  target: z.union([z.string(), z.number()]),
69
+ container: z.string().optional(),
66
70
  duration: z.number().optional(),
67
71
  }),
68
72
  zoom: z.strictObject({
@@ -80,6 +84,8 @@ const ACTIONS = {
80
84
  * fact not derivable from the schema.
81
85
  */
82
86
  const POSITIONAL_OPTIONAL = {
87
+ start: ["name"],
88
+ split: ["name"],
83
89
  waitForPlay: ["message"],
84
90
  resumeOnPlay: ["message"],
85
91
  };
@@ -155,7 +161,7 @@ function buildArgs(step, name) {
155
161
  export function callToAction(name, args) {
156
162
  const schema = ACTIONS[name];
157
163
  if (!schema) {
158
- throw new Error(`Unknown action "${name}" — valid actions: ${Object.keys(ACTIONS).join(", ")}`);
164
+ throw new RecordableError("CONFIG_INVALID", `Unknown action "${name}" — valid actions: ${Object.keys(ACTIONS).join(", ")}`);
159
165
  }
160
166
  const step = { action: name };
161
167
  let i = 0;
@@ -163,23 +169,23 @@ export function callToAction(name, args) {
163
169
  if (i < args.length)
164
170
  step[key] = args[i++];
165
171
  else if (!isOptional(name, key))
166
- throw new Error(`Action "${name}" is missing required "${key}"`);
172
+ throw new RecordableError("CONFIG_INVALID", `Action "${name}" is missing required "${key}"`);
167
173
  }
168
174
  const bag = bagKeys(name);
169
175
  if (i < args.length && bag.length) {
170
176
  const obj = args[i++];
171
177
  if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
172
- throw new Error(`Action "${name}": expected a trailing options object, got ${JSON.stringify(obj)}`);
178
+ throw new RecordableError("CONFIG_INVALID", `Action "${name}": expected a trailing options object, got ${JSON.stringify(obj)}`);
173
179
  }
174
180
  for (const [k, v] of Object.entries(obj)) {
175
181
  if (!bag.includes(k)) {
176
- throw new Error(`Action "${name}": unknown key "${k}" — valid keys: ${bag.join(", ")}`);
182
+ throw new RecordableError("CONFIG_INVALID", `Action "${name}": unknown key "${k}" — valid keys: ${bag.join(", ")}`);
177
183
  }
178
184
  step[k] = v;
179
185
  }
180
186
  }
181
187
  if (i < args.length) {
182
- throw new Error(`Action "${name}": too many arguments (expected at most ${i}, got ${args.length})`);
188
+ throw new RecordableError("CONFIG_INVALID", `Action "${name}": too many arguments (expected at most ${i}, got ${args.length})`);
183
189
  }
184
190
  validateAction(step);
185
191
  return step;
@@ -1 +1 @@
1
- {"version":3,"file":"actions.js","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"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"}
@@ -24,6 +24,16 @@ export declare class AudioTrack {
24
24
  durationMs: number;
25
25
  }>;
26
26
  }
27
+ /**
28
+ * Partition clips across a run's output files (ROADMAP §6: per-file audio). A
29
+ * clip is assigned to the file *containing its start* — the last file whose
30
+ * global `startMs` is at or before the clip — then rebased to that file's own
31
+ * zero-based timeline. A clip overrunning its file's end is left for the mixer
32
+ * to trim (and warn). Returns one clip list per file, aligned to `files`.
33
+ */
34
+ export declare function partitionAudioByFiles(clips: readonly AudioClip[], files: readonly {
35
+ startMs: number;
36
+ }[]): AudioClip[][];
27
37
  /**
28
38
  * Build the `filter_complex` chain that delays each clip to its `startMs`,
29
39
  * applies volume, and mixes them. Input index `i+1` (input 0 is the video).
@@ -1 +1 @@
1
- {"version":3,"file":"track.d.ts","sourceRoot":"","sources":["../../src/audio/track.ts"],"names":[],"mappings":"AAYA,oEAAoE;AACpE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;uEACuE;AACvE,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IAEzC,oCAAoC;IACpC,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,kEAAkE;IAClE,IAAI,IAAI,SAAS,SAAS,EAAE;IAI5B;;;OAGG;IACG,GAAG,CACP,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GAChC,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAOpD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,GAAG;IAC7D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAeA;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,OAAO,EAAE,MAAM,EACf,KAAK,SAAK,GACT;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,CAOpC"}
1
+ {"version":3,"file":"track.d.ts","sourceRoot":"","sources":["../../src/audio/track.ts"],"names":[],"mappings":"AAYA,oEAAoE;AACpE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;uEACuE;AACvE,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IAEzC,oCAAoC;IACpC,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,kEAAkE;IAClE,IAAI,IAAI,SAAS,SAAS,EAAE;IAI5B;;;OAGG;IACG,GAAG,CACP,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GAChC,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAUpD;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,KAAK,EAAE,SAAS;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,GACpC,SAAS,EAAE,EAAE,CAUf;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,GAAG;IAC7D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAeA;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,OAAO,EAAE,MAAM,EACf,KAAK,SAAK,GACT;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,CAOpC"}
@@ -25,6 +25,25 @@ export class AudioTrack {
25
25
  return { startMs, durationMs };
26
26
  }
27
27
  }
28
+ /**
29
+ * Partition clips across a run's output files (ROADMAP §6: per-file audio). A
30
+ * clip is assigned to the file *containing its start* — the last file whose
31
+ * global `startMs` is at or before the clip — then rebased to that file's own
32
+ * zero-based timeline. A clip overrunning its file's end is left for the mixer
33
+ * to trim (and warn). Returns one clip list per file, aligned to `files`.
34
+ */
35
+ export function partitionAudioByFiles(clips, files) {
36
+ const groups = files.map(() => []);
37
+ for (const c of clips) {
38
+ let idx = 0;
39
+ for (let i = 0; i < files.length; i++)
40
+ if (files[i].startMs <= c.startMs)
41
+ idx = i;
42
+ if (groups[idx])
43
+ groups[idx].push({ ...c, startMs: c.startMs - files[idx].startMs });
44
+ }
45
+ return groups;
46
+ }
28
47
  /**
29
48
  * Build the `filter_complex` chain that delays each clip to its `startMs`,
30
49
  * applies volume, and mixes them. Input index `i+1` (input 0 is the video).
@@ -1 +1 @@
1
- {"version":3,"file":"track.js","sourceRoot":"","sources":["../../src/audio/track.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAkB/C;uEACuE;AACvE,MAAM,OAAO,UAAU;IACJ,KAAK,GAAgB,EAAE,CAAC;IAEzC,oCAAoC;IACpC,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED,kEAAkE;IAClE,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,GAAG,CACP,IAAY,EACZ,OAAe,EACf,UAA+B,EAAE;QAEjC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YACnB,MAAM,IAAI,eAAe,CAAC,gBAAgB,EAAE,0BAA0B,IAAI,EAAE,CAAC,CAAC;QAChF,MAAM,UAAU,GAAG,CAAC,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;QACpD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACvE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IACjC,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAA2B;IAI1D,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACjC,MAAM,KAAK,GAAG,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACxD,IAAI,CAAC,CAAC,MAAM,IAAI,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QACzE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAE3D,OAAO,CAAC,IAAI,CACV,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,eAAe,KAAK,CAAC,MAAM,oBAAoB,CAClE,CAAC;IACF,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AACvC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,KAA2B,EAC3B,OAAe,EACf,KAAK,GAAG,EAAE;IAEV,MAAM,IAAI,GAAuC,EAAE,CAAC;IACpD,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,UAAU,GAAG,OAAO,CAAC,CAAC;QAC9D,IAAI,MAAM,GAAG,KAAK;YAAE,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"track.js","sourceRoot":"","sources":["../../src/audio/track.ts"],"names":[],"mappings":"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"}
@@ -17,7 +17,7 @@ export declare class Cursor {
17
17
  park(): void;
18
18
  /** Restore the parked position (if any) and re-inject — called on resume so the
19
19
  * new segment opens with the cursor where the previous one ended. */
20
- unpark(page: Page, zoom?: ZoomState, pageZoom?: number): Promise<void>;
20
+ unpark(page: Page, zoom?: ZoomState): Promise<void>;
21
21
  /**
22
22
  * Ensure the cursor overlay exists and sits at the carried position, then sync
23
23
  * the real mouse there. Safe to call repeatedly: it creates the overlay if the
@@ -25,18 +25,20 @@ export declare class Cursor {
25
25
  * repositions it — so a resume() can restore the cursor even when the overlay
26
26
  * survived the off-camera gap.
27
27
  */
28
- inject(page: Page, zoom?: ZoomState, pageZoom?: number): Promise<void>;
28
+ inject(page: Page, zoom?: ZoomState): Promise<void>;
29
29
  /** Ease the overlay (and the real mouse) to viewport coords `toX,toY`. */
30
- moveTo(page: Page, toX: number, toY: number, zoom: ZoomState, pageZoom?: number): Promise<void>;
30
+ moveTo(page: Page, toX: number, toY: number, zoom: ZoomState): Promise<void>;
31
31
  /**
32
32
  * Convert viewport coords → document coords for the overlay's transform.
33
33
  * When documentElement has a CSS transform (zoom), position:fixed children
34
34
  * are positioned relative to that ancestor (not the viewport) and scroll with
35
35
  * the page, so we add scroll and apply the inverse zoom transform.
36
36
  *
37
- * `pageZoom` is the static CSS `zoom` on documentElement (the pageZoom config).
38
- * The overlay inherits that zoom, so its translate renders `pageZoom`× larger
39
- * divide it out so the cursor still lands on the target's visual position.
37
+ * Note: the `pageZoom` config (genuine browser zoom via chrome.tabs.setZoom)
38
+ * needs no handling here. Page zoom rescales the CSS pixel itself, so the
39
+ * overlay, the content, and Puppeteer's `boundingBox()`/`mouse` coords all share
40
+ * one post-zoom coordinate space — feeding the overlay those raw coords keeps it
41
+ * aligned with the target automatically.
40
42
  */
41
43
  private _toDocCoords;
42
44
  /** Briefly scale the cursor down to signal a press. */
@@ -1 +1 @@
1
- {"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/browser/cursor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AAOtC,mFAAmF;AACnF,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;;GAIG;AACH,qBAAa,MAAM;IAIjB,OAAO,CAAC,GAAG,CAAkB;IAK7B,OAAO,CAAC,MAAM,CAAyC;IAEvD,4EAA4E;IAC5E,IAAI,IAAI,IAAI;IAIZ;0EACsE;IAChE,MAAM,CACV,IAAI,EAAE,IAAI,EACV,IAAI,GAAE,SAAkC,EACxC,QAAQ,SAAI,GACX,OAAO,CAAC,IAAI,CAAC;IAQhB;;;;;;OAMG;IACG,MAAM,CACV,IAAI,EAAE,IAAI,EACV,IAAI,GAAE,SAAkC,EACxC,QAAQ,SAAI,GACX,OAAO,CAAC,IAAI,CAAC;IAiEhB,0EAA0E;IACpE,MAAM,CACV,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,SAAS,EACf,QAAQ,SAAI,GACX,OAAO,CAAC,IAAI,CAAC;IAiChB;;;;;;;;;OASG;YACW,YAAY;IAiB1B,uDAAuD;IACjD,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CAa7C"}
1
+ {"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/browser/cursor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AAiBtC,mFAAmF;AACnF,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;;GAIG;AACH,qBAAa,MAAM;IAIjB,OAAO,CAAC,GAAG,CAAkB;IAK7B,OAAO,CAAC,MAAM,CAAyC;IAEvD,4EAA4E;IAC5E,IAAI,IAAI,IAAI;IAIZ;0EACsE;IAChE,MAAM,CACV,IAAI,EAAE,IAAI,EACV,IAAI,GAAE,SAAkC,GACvC,OAAO,CAAC,IAAI,CAAC;IAQhB;;;;;;OAMG;IACG,MAAM,CACV,IAAI,EAAE,IAAI,EACV,IAAI,GAAE,SAAkC,GACvC,OAAO,CAAC,IAAI,CAAC;IA2EhB,0EAA0E;IACpE,MAAM,CACV,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,IAAI,CAAC;IAoChB;;;;;;;;;;;OAWG;YACW,YAAY;IAa1B,uDAAuD;IACjD,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CAa7C"}