@vosjs/cli 0.31.0 → 0.32.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.
- package/README.md +5 -3
- package/dist/{chunk-APVJ4MDJ.js → chunk-QJORXTJM.js} +162 -12
- package/dist/chunk-QJORXTJM.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{run-ULH2OMJM.js → run-PYK3XJNH.js} +2 -2
- package/package.json +4 -4
- package/schema/doc.schema.json +49 -1
- package/dist/chunk-APVJ4MDJ.js.map +0 -1
- /package/dist/{run-ULH2OMJM.js.map → run-PYK3XJNH.js.map} +0 -0
package/README.md
CHANGED
|
@@ -143,7 +143,7 @@ A re-record replaces the footage, the cursor track, the frames and everything de
|
|
|
143
143
|
}
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
-
Seven verbs: `wait`, `hover` (`ms` 700), `click`, `type` (`delayMs` 40 per key; `focus: false` skips the focusing click, for a submitting Enter), `scroll`, `move`, `drag` (press, move, release: a range input, a canvas element, a timeline clip). Every step takes an optional unique `id`; give steps ids so a span anchored to a step survives script edits and `vos plan --reuse` can follow it. Because the CLI issues every input itself, the cursor track is synthesized with exact coordinates, exact timing and fresh element rects, which is what powers element-aware auto-zoom and click effects downstream. The schema is [`schema/actions.schema.json`](./schema/actions.schema.json); `vos validate actions.json` checks a script without running anything.
|
|
146
|
+
Seven verbs: `wait`, `hover` (`ms` 700), `click`, `type` (`delayMs` 40 per key; `focus: false` skips the focusing click, for a submitting Enter), `scroll`, `move`, `drag` (press, move, release: a range input, a canvas element, a timeline clip). Every step takes an optional unique `id`; give steps ids so a span anchored to a step survives script edits and `vos plan --reuse` can follow it, and so a layer can name the element a step touched (`overlays[].pin.step`; the recorder keeps each hover, click, type and drag step's element rect on `meta.steps[].rect`). Because the CLI issues every input itself, the cursor track is synthesized with exact coordinates, exact timing and fresh element rects, which is what powers element-aware auto-zoom and click effects downstream. The schema is [`schema/actions.schema.json`](./schema/actions.schema.json); `vos validate actions.json` checks a script without running anything.
|
|
147
147
|
|
|
148
148
|
Verified the flow in agent-browser already? `vos actions from-agent-browser steps.jsonl [--out actions.json] [--url] [--viewport WxH]` writes the script from that walk (each command kept beside its `--json` result, the batch record shape; refs resolve through the last `snapshot -i`), and names every step the recorder cannot follow rather than dropping it.
|
|
149
149
|
|
|
@@ -151,13 +151,15 @@ Verified the flow in agent-browser already? `vos actions from-agent-browser step
|
|
|
151
151
|
|
|
152
152
|
`doc.json` is a `ProjectDoc` from [`@vosjs/studio-core`](../studio-core), all plain JSON. Zoom is `zoom: [{ id, in, out, level, cx, cy, source }]`, trims are `segments`, pacing is `speed`. Edit and re-render; nothing re-runs the browser. The full shape ships as a JSON Schema at [`schema/doc.schema.json`](./schema/doc.schema.json) (a `oneOf`: the recording document and the program document, sharing the layer definitions), and `vos validate <dir>` lints the semantics of either (span overlap, footage bounds, coordinate ranges, export honesty) before you spend a render.
|
|
153
153
|
|
|
154
|
-
**Contracts that bite.** Time is source seconds in `zoom`, `segments`, `speed` and `tilt`, and output seconds in `overlays` and `audio`. Zoom `cx`/`cy
|
|
154
|
+
**Contracts that bite.** Time is source seconds in `zoom`, `segments`, `speed` and `tilt`, and output seconds in `overlays` and `audio`. Zoom `cx`/`cy`, overlay `transform.x`/`y` and a pin's `rect` are normalized fractions of the frame in `[0, 1]` (`0.5, 0.5` is the centre), never pixels. `level` is 1..5. The planners write `source: "auto"`; spans you add or edit carry `source: "manual"`, which a re-plan never touches, and a deleted automatic span is recorded in `doc.rejected` so a re-plan does not bring it back.
|
|
155
155
|
|
|
156
156
|
**Camera styles.** `doc.zoomStyle` is one of `glide` (default), `focus`, `cinema`, `snappy`, `cut`, `keynote` (gliding zooms plus a medium lean toward each focus, the launch-film register), `drift` (slow ambient zooms with a subtle lean) or `none`. In the studio, picking a style also stamps `tiltStyle` and plans the tilt spans; in `doc.json` set `tiltStyle` and `tilt` yourself.
|
|
157
157
|
|
|
158
158
|
**Tilt.** `doc.tilt`: source-anchored, non-overlapping spans where the card leans to a pose and returns to rest: `[{ "id": "u0", "in": 4, "out": 8, "rx": 6, "ry": -9, "source": "manual" }]`. `rx`/`ry` are degrees (±45 hard limit; ±5..18 reads well); `+rx` brings the top edge toward the camera, `+ry` the left edge, so a lean toward a right-side focus is a negative `ry`. Rest is flat. `doc.tiltStyle` (`off`, `subtle`, `medium`, `strong`) is the intensity the planner derives automatic spans from.
|
|
159
159
|
|
|
160
|
-
**Text overlays.** `doc.overlays`: screen-space clips above the card, outside the zoom, output-anchored. `{ "id": "t0", "kind": "text", "start": 1, "duration": 3, "text": "Ship it", "preset": "title", "transform": { "x": 0.5, "y": 0.82, "scale": 1, "rotation": 0 }, "enter": "rise", "exit": "fade" }`. Presets `title`, `caption`, `label`, overridable with `size` (12..200 design px) and `color`; `\n` breaks lines; a lower third
|
|
160
|
+
**Text overlays.** `doc.overlays`: screen-space clips above the card, outside the zoom, output-anchored. `{ "id": "t0", "kind": "text", "start": 1, "duration": 3, "text": "Ship it", "preset": "title", "transform": { "x": 0.5, "y": 0.82, "scale": 1, "rotation": 0 }, "enter": "rise", "exit": "fade" }`. Presets `title`, `caption`, `label`, overridable with `size` (12..200 design px) and `color`; `\n` breaks lines; a caption (a layer with no referent) is a lower third at `y` ≈ 0.82. Enter and exit: `rise`, `fade`, `none`. Fonts load at render start, fail-open to system stacks.
|
|
161
|
+
|
|
162
|
+
**Pinned layers.** A layer ABOUT something on the page names it, and the lowering keeps the two together: `"pin": { "step": "copy", "side": "auto", "mark": "ring", "leader": true }` on any overlay kind places the layer a gap off one side of that step's element and carries it with the element as the camera moves (the layer keeps its screen size; only its place follows). One of `step` (a recorder step's `id`, else its index), `press` (SOURCE seconds; the nearest press names the element, for a human recording) or `rect` (video fractions) names the referent. `side` is `auto` (the first of right, left, below, above whose box fits inside the frame through the layer's life) or a side by name; `gap` is design px (24); `mark` is `ring` or `underline`, a standing highlight on the referent for the layer's life; `leader` draws a hairline from the layer to the referent; `color` is their ink. `transform.x/y` stay the fallback for a pin that cannot resolve, and `vos validate` says why (an unknown step, a step that touched nothing, a scroll inside the layer's window). A layer that cannot name its referent is a caption: place it in the margin, never over the app.
|
|
161
163
|
|
|
162
164
|
**Image and video overlays.** Media kinds on the same lane: `{ "id": "m0", "kind": "image" | "video", "start": 2, "duration": 4, "key": "/logo.png", "width": 0.35, "radius": 12, "opacity": 1, "loop": false, "transform": { … } }`. `key` is a file inside the take directory (`"/logo.png"`) or a URL; `width` is a fraction of the frame width, height follows the media's aspect; corners in design px. Video time is clip-local and muted by design; soundtracks belong to `doc.audio`.
|
|
163
165
|
|
|
@@ -210,9 +210,15 @@ import {
|
|
|
210
210
|
ZOOM_LEVEL_MIN,
|
|
211
211
|
ZOOM_SPAN_MIN,
|
|
212
212
|
docCardLayout,
|
|
213
|
+
docZoomTrack,
|
|
214
|
+
findStep,
|
|
213
215
|
outputEnd,
|
|
216
|
+
pinBox,
|
|
217
|
+
pinRectOnScreen,
|
|
218
|
+
pinReferent,
|
|
214
219
|
ratedSegments,
|
|
215
220
|
recommendedExportResolution,
|
|
221
|
+
resolvePins,
|
|
216
222
|
spanOutputExtent,
|
|
217
223
|
zoomCoversRect,
|
|
218
224
|
cameraModel
|
|
@@ -944,6 +950,7 @@ function lintDoc(docIn) {
|
|
|
944
950
|
if (!isNum(o.duration) || o.duration <= 0) {
|
|
945
951
|
problems.push(`${name}.duration must be > 0 (seconds)`);
|
|
946
952
|
}
|
|
953
|
+
checkPin(o, name, docIn, recording, problems, warnings);
|
|
947
954
|
if (o.kind === "text") {
|
|
948
955
|
if (typeof o.text !== "string")
|
|
949
956
|
problems.push(`${name}.text must be a string`);
|
|
@@ -1455,6 +1462,106 @@ function clicksWithRects(source) {
|
|
|
1455
1462
|
}
|
|
1456
1463
|
return out;
|
|
1457
1464
|
}
|
|
1465
|
+
var PIN_SIDES = ["auto", "right", "left", "below", "above"];
|
|
1466
|
+
var PIN_MARKS = ["none", "ring", "underline"];
|
|
1467
|
+
function checkPin(o, name, docIn, recording, problems, warnings) {
|
|
1468
|
+
if (o.pin === void 0) return;
|
|
1469
|
+
if (!isObj(o.pin)) {
|
|
1470
|
+
problems.push(
|
|
1471
|
+
`${name}.pin must be { step | press | rect, side?, gap?, mark?, leader?, color? }`
|
|
1472
|
+
);
|
|
1473
|
+
return;
|
|
1474
|
+
}
|
|
1475
|
+
const p = o.pin;
|
|
1476
|
+
const named = ["step", "press", "rect"].filter((k) => p[k] !== void 0);
|
|
1477
|
+
if (named.length !== 1) {
|
|
1478
|
+
problems.push(
|
|
1479
|
+
`${name}.pin names its referent by exactly one of step (a recorder step id or index), press (a source second) or rect (video fractions)${named.length ? ` \u2014 got ${named.join(" and ")}` : ""}`
|
|
1480
|
+
);
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
if (p.step !== void 0 && typeof p.step !== "string" && !(isNum(p.step) && Number.isInteger(p.step) && p.step >= 0)) {
|
|
1484
|
+
problems.push(
|
|
1485
|
+
`${name}.pin.step must be a step id (string) or index (integer \u2265 0)`
|
|
1486
|
+
);
|
|
1487
|
+
}
|
|
1488
|
+
if (p.press !== void 0 && !isNum(p.press))
|
|
1489
|
+
problems.push(`${name}.pin.press must be a source second (number)`);
|
|
1490
|
+
if (p.rect !== void 0) {
|
|
1491
|
+
const r = isObj(p.rect) ? p.rect : null;
|
|
1492
|
+
if (!r || !isNum(r.x) || !isNum(r.y) || !isNum(r.w) || !isNum(r.h)) {
|
|
1493
|
+
problems.push(`${name}.pin.rect must be { x, y, w, h }`);
|
|
1494
|
+
} else if (Math.abs(r.x) > 2 || Math.abs(r.y) > 2 || r.w > 2 || r.h > 2) {
|
|
1495
|
+
problems.push(
|
|
1496
|
+
`${name}.pin.rect looks like PIXELS (${String(r.x)}, ${String(r.y)}, ${String(r.w)}\xD7${String(r.h)}) \u2014 it is FRACTIONS of the video frame [0..1] (the zoom cx/cy convention)`
|
|
1497
|
+
);
|
|
1498
|
+
} else if (r.w <= 0 || r.h <= 0) {
|
|
1499
|
+
problems.push(`${name}.pin.rect must have w > 0 and h > 0`);
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
if (p.side !== void 0 && !PIN_SIDES.includes(p.side))
|
|
1503
|
+
problems.push(`${name}.pin.side must be one of ${PIN_SIDES.join(" | ")}`);
|
|
1504
|
+
if (p.gap !== void 0 && (!isNum(p.gap) || p.gap < 0))
|
|
1505
|
+
problems.push(`${name}.pin.gap must be design px \u2265 0`);
|
|
1506
|
+
if (p.mark !== void 0 && !PIN_MARKS.includes(p.mark))
|
|
1507
|
+
problems.push(`${name}.pin.mark must be one of ${PIN_MARKS.join(" | ")}`);
|
|
1508
|
+
if (p.leader !== void 0 && typeof p.leader !== "boolean")
|
|
1509
|
+
problems.push(`${name}.pin.leader must be true or false`);
|
|
1510
|
+
if (p.color !== void 0 && typeof p.color !== "string")
|
|
1511
|
+
problems.push(`${name}.pin.color must be a CSS colour string`);
|
|
1512
|
+
if (problems.some((m) => m.startsWith(`${name}.pin`))) return;
|
|
1513
|
+
if (!recording) {
|
|
1514
|
+
problems.push(
|
|
1515
|
+
`${name}.pin names something on a recording's page; a program has no referents \u2014 place the layer with transform`
|
|
1516
|
+
);
|
|
1517
|
+
return;
|
|
1518
|
+
}
|
|
1519
|
+
const doc = docIn;
|
|
1520
|
+
const steps = doc.source.meta.steps ?? [];
|
|
1521
|
+
if (p.step !== void 0) {
|
|
1522
|
+
const step = findStep(steps, p.step);
|
|
1523
|
+
if (!step) {
|
|
1524
|
+
const known = steps.filter((s) => s.selector).map((s) => s.id !== void 0 ? s.id : String(s.step));
|
|
1525
|
+
problems.push(
|
|
1526
|
+
`${name}.pin.step "${String(p.step)}" is not a step of this take${known.length ? ` \u2014 steps with an element: ${known.join(", ")}` : " \u2014 the take has no step timeline (a human recording); pin by press or rect"}`
|
|
1527
|
+
);
|
|
1528
|
+
return;
|
|
1529
|
+
}
|
|
1530
|
+
if (step.skipped) {
|
|
1531
|
+
problems.push(
|
|
1532
|
+
`${name}.pin.step "${String(p.step)}" was skipped at record time (its selector never became visible), so it has no element to point at`
|
|
1533
|
+
);
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
let ref;
|
|
1538
|
+
try {
|
|
1539
|
+
ref = pinReferent(doc, p);
|
|
1540
|
+
} catch {
|
|
1541
|
+
ref = null;
|
|
1542
|
+
}
|
|
1543
|
+
if (!ref) {
|
|
1544
|
+
problems.push(
|
|
1545
|
+
p.step !== void 0 ? `${name}.pin.step "${String(p.step)}" has no element rect and no press inside its window (a wait, scroll or move step touches nothing) \u2014 pin a hover, click, type or drag step, or a press` : p.press !== void 0 ? `${name}.pin.press ${String(p.press)}s has no press with an element rect within half a second \u2014 the presses are the cursor track's down events` : `${name}.pin.rect could not be read`
|
|
1546
|
+
);
|
|
1547
|
+
return;
|
|
1548
|
+
}
|
|
1549
|
+
if (ref.at !== null && isNum(o.start) && isNum(o.duration)) {
|
|
1550
|
+
const rated = ratedSegments(doc);
|
|
1551
|
+
for (const s of steps) {
|
|
1552
|
+
if (s.tStart <= ref.at) continue;
|
|
1553
|
+
if (s.do !== "scroll" && !s.navigated) continue;
|
|
1554
|
+
const out = spanOutputExtent(rated, s.tStart, s.tEnd);
|
|
1555
|
+
if (!out) continue;
|
|
1556
|
+
if (out.start < o.start + o.duration && out.end > o.start) {
|
|
1557
|
+
warnings.push(
|
|
1558
|
+
`${name} is pinned to something measured at ${ref.at.toFixed(1)}s, but ${s.do === "scroll" ? "a scroll" : "a navigation"} at ${s.tStart.toFixed(1)}s (output ${out.start.toFixed(1)}s) falls inside the layer's window \u2014 the referent may have moved; end the layer before it`
|
|
1559
|
+
);
|
|
1560
|
+
break;
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1458
1565
|
function framingWarnings(docIn, doc, zoom, overlays, warnings) {
|
|
1459
1566
|
try {
|
|
1460
1567
|
const source = isObj(doc.source) ? doc.source : {};
|
|
@@ -1496,24 +1603,54 @@ function framingWarnings(docIn, doc, zoom, overlays, warnings) {
|
|
|
1496
1603
|
}
|
|
1497
1604
|
}
|
|
1498
1605
|
const rated = ratedSegments(docIn);
|
|
1499
|
-
const
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
});
|
|
1606
|
+
const camera = cameraModel(docIn.frame);
|
|
1607
|
+
const zoomTrack = docZoomTrack(docIn);
|
|
1608
|
+
const pins = resolvePins(docIn, layout, camera, zoomTrack);
|
|
1503
1609
|
overlays.forEach((o, i) => {
|
|
1504
|
-
if (!isObj(o) || o.
|
|
1610
|
+
if (!isObj(o) || !isNum(o.start) || !isNum(o.duration)) return;
|
|
1505
1611
|
const tf = isObj(o.transform) ? o.transform : null;
|
|
1506
|
-
if (!tf || !isNum(tf.x) || !isNum(tf.y)
|
|
1612
|
+
if (!tf || !isNum(tf.x) || !isNum(tf.y)) return;
|
|
1613
|
+
const pinned = pins.get(String(o.id));
|
|
1614
|
+
if (pinned) {
|
|
1615
|
+
if (pinned.clamped > 4) {
|
|
1616
|
+
warnings.push(
|
|
1617
|
+
`overlays[${i}] is pinned ${pinned.side} of its referent but the frame has no room there \u2014 it sits ${Math.round(pinned.clamped)} design px off; a smaller box, another side, or a lower zoom level keeps it beside what it names`
|
|
1618
|
+
);
|
|
1619
|
+
}
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
let box;
|
|
1623
|
+
try {
|
|
1624
|
+
box = pinBox(o, layout);
|
|
1625
|
+
} catch {
|
|
1507
1626
|
return;
|
|
1627
|
+
}
|
|
1508
1628
|
for (const c of clicks) {
|
|
1509
1629
|
const out = spanOutputExtent(rated, c.t, c.t + 1e-3);
|
|
1510
1630
|
if (!out || out.start < o.start || out.start > o.start + o.duration)
|
|
1511
1631
|
continue;
|
|
1512
|
-
const
|
|
1513
|
-
|
|
1514
|
-
|
|
1632
|
+
const target = pinRectOnScreen(
|
|
1633
|
+
{
|
|
1634
|
+
x: c.rect.x / w,
|
|
1635
|
+
y: c.rect.y / h,
|
|
1636
|
+
w: c.rect.w / w,
|
|
1637
|
+
h: c.rect.h / h
|
|
1638
|
+
},
|
|
1639
|
+
out.start,
|
|
1640
|
+
layout,
|
|
1641
|
+
camera,
|
|
1642
|
+
zoomTrack
|
|
1643
|
+
);
|
|
1644
|
+
const L = {
|
|
1645
|
+
x: tf.x * layout.W - box.w / 2,
|
|
1646
|
+
y: tf.y * layout.H - box.h / 2,
|
|
1647
|
+
w: box.w,
|
|
1648
|
+
h: box.h
|
|
1649
|
+
};
|
|
1650
|
+
const overlaps2 = L.x < target.x + target.w && L.x + L.w > target.x && L.y < target.y + target.h && L.y + L.h > target.y;
|
|
1651
|
+
if (overlaps2) {
|
|
1515
1652
|
warnings.push(
|
|
1516
|
-
`overlays[${i}] sits over the thing being clicked at ${c.t.toFixed(1)}s (output ${out.start.toFixed(1)}s) \u2014
|
|
1653
|
+
`overlays[${i}] sits over the thing being clicked at ${c.t.toFixed(1)}s (output ${out.start.toFixed(1)}s) \u2014 pin it to that step (pin: { step }) so it sits beside the target and follows it, or move it off`
|
|
1517
1654
|
);
|
|
1518
1655
|
break;
|
|
1519
1656
|
}
|
|
@@ -5894,6 +6031,7 @@ async function recordTake(browser, url, actions, paths, log, opts = {}) {
|
|
|
5894
6031
|
const stepStart = now();
|
|
5895
6032
|
const skippedBefore = skipped.length;
|
|
5896
6033
|
const urlBefore = page.url();
|
|
6034
|
+
let stepRect = null;
|
|
5897
6035
|
switch (step.do) {
|
|
5898
6036
|
case "wait":
|
|
5899
6037
|
await sleep(clampWait(step.ms, now(), maxSeconds));
|
|
@@ -5903,6 +6041,7 @@ async function recordTake(browser, url, actions, paths, log, opts = {}) {
|
|
|
5903
6041
|
break;
|
|
5904
6042
|
case "hover": {
|
|
5905
6043
|
const rect = await boxOf(step.selector);
|
|
6044
|
+
stepRect = rect;
|
|
5906
6045
|
if (rect) {
|
|
5907
6046
|
await moveTo(rect.x + rect.w / 2, rect.y + rect.h / 2);
|
|
5908
6047
|
log(`hover ${step.selector}`);
|
|
@@ -5913,6 +6052,7 @@ async function recordTake(browser, url, actions, paths, log, opts = {}) {
|
|
|
5913
6052
|
}
|
|
5914
6053
|
case "click": {
|
|
5915
6054
|
const rect = await boxOf(step.selector);
|
|
6055
|
+
stepRect = rect;
|
|
5916
6056
|
if (rect) {
|
|
5917
6057
|
await clickAt(rect);
|
|
5918
6058
|
log(`click ${step.selector}`);
|
|
@@ -5923,6 +6063,7 @@ async function recordTake(browser, url, actions, paths, log, opts = {}) {
|
|
|
5923
6063
|
}
|
|
5924
6064
|
case "type": {
|
|
5925
6065
|
const rect = await boxOf(step.selector);
|
|
6066
|
+
stepRect = rect;
|
|
5926
6067
|
if (rect) {
|
|
5927
6068
|
if (step.focus !== false) await clickAt(rect);
|
|
5928
6069
|
const delay = step.delayMs ?? 40;
|
|
@@ -5964,6 +6105,7 @@ async function recordTake(browser, url, actions, paths, log, opts = {}) {
|
|
|
5964
6105
|
let rect;
|
|
5965
6106
|
if (step.selector) {
|
|
5966
6107
|
const box = await boxOf(step.selector);
|
|
6108
|
+
stepRect = box;
|
|
5967
6109
|
if (box) {
|
|
5968
6110
|
rect = box;
|
|
5969
6111
|
start = { x: box.x + box.w / 2, y: box.y + box.h / 2 };
|
|
@@ -6026,7 +6168,15 @@ async function recordTake(browser, url, actions, paths, log, opts = {}) {
|
|
|
6026
6168
|
tStart: +(stepStart / 1e3).toFixed(3),
|
|
6027
6169
|
tEnd: +(now() / 1e3).toFixed(3),
|
|
6028
6170
|
...skipped.length > skippedBefore ? { skipped: true } : {},
|
|
6029
|
-
...page.url() !== urlBefore ? { navigated: true } : {}
|
|
6171
|
+
...page.url() !== urlBefore ? { navigated: true } : {},
|
|
6172
|
+
...stepRect ? {
|
|
6173
|
+
rect: {
|
|
6174
|
+
x: +stepRect.x.toFixed(1),
|
|
6175
|
+
y: +stepRect.y.toFixed(1),
|
|
6176
|
+
w: +stepRect.w.toFixed(1),
|
|
6177
|
+
h: +stepRect.h.toFixed(1)
|
|
6178
|
+
}
|
|
6179
|
+
} : {}
|
|
6030
6180
|
});
|
|
6031
6181
|
}
|
|
6032
6182
|
if (!capped) await sleep(600);
|
|
@@ -10628,4 +10778,4 @@ export {
|
|
|
10628
10778
|
convertAgentBrowser,
|
|
10629
10779
|
run
|
|
10630
10780
|
};
|
|
10631
|
-
//# sourceMappingURL=chunk-
|
|
10781
|
+
//# sourceMappingURL=chunk-QJORXTJM.js.map
|