@vosjs/studio-core 0.47.0 → 0.49.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/dist/index.d.ts +32 -7
- package/dist/index.js +18 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -397,6 +397,13 @@ interface RecordingMeta {
|
|
|
397
397
|
* whole take, so Chrome letterboxes the resized content — surface a notice.
|
|
398
398
|
*/
|
|
399
399
|
resizedDuringTake?: boolean;
|
|
400
|
+
/**
|
|
401
|
+
* How round the footage's own corners are, in cursor-space units (a recorded
|
|
402
|
+
* window's points). Outside them the footage is opaque: a window recorded
|
|
403
|
+
* alone is black there. A card drawn around the footage is at least this
|
|
404
|
+
* round, or those corners show as notches. Absent or 0 = square footage.
|
|
405
|
+
*/
|
|
406
|
+
cornerRadius?: number;
|
|
400
407
|
/**
|
|
401
408
|
* Page URL/title at record start (seeds the browser-bar mock's address pill).
|
|
402
409
|
* Query/hash are stripped at capture for privacy.
|
|
@@ -404,12 +411,26 @@ interface RecordingMeta {
|
|
|
404
411
|
pageUrl?: string;
|
|
405
412
|
pageTitle?: string;
|
|
406
413
|
/**
|
|
407
|
-
*
|
|
408
|
-
*
|
|
409
|
-
*
|
|
410
|
-
|
|
414
|
+
* The application an `'app'` take recorded, where a page take says
|
|
415
|
+
* `pageUrl`: its name as the OS shows it, and its bundle id or executable
|
|
416
|
+
* name. Never a window title, which carries document and account names.
|
|
417
|
+
*/
|
|
418
|
+
app?: {
|
|
419
|
+
name: string;
|
|
420
|
+
id?: string;
|
|
421
|
+
};
|
|
422
|
+
/**
|
|
423
|
+
* What the frame contains. Absent = 'tab' (back-compat). `'window'` and
|
|
424
|
+
* `'monitor'` are a BROWSER's display captures: they use CursorEvent.sx/sy +
|
|
425
|
+
* the geometry rects below to map cursor → capture px (see
|
|
426
|
+
* normalizeCaptureSpace), and tab-only studio features (browser-bar mock,
|
|
427
|
+
* letterbox notice) are gated off for them. `'app'` is one application's
|
|
428
|
+
* window recorded by a desktop producer: the frame IS the window, the cursor
|
|
429
|
+
* is already in the frame's own space (`width × height` are the window's
|
|
430
|
+
* points, `captureWidth × captureHeight` its pixels), and the footage
|
|
431
|
+
* carries the window's own title bar, so no bar is drawn over it.
|
|
411
432
|
*/
|
|
412
|
-
captureSurface?: 'tab' | 'window' | 'monitor';
|
|
433
|
+
captureSurface?: 'tab' | 'window' | 'monitor' | 'app';
|
|
413
434
|
/**
|
|
414
435
|
* Target-tab browser-window bounds at record start, screen-coord CSS px
|
|
415
436
|
* (window.screenX/Y + outerWidth/Height). Anchor for 'window' captures.
|
|
@@ -463,10 +484,12 @@ interface RecordingMeta {
|
|
|
463
484
|
* track from automation (exact coords, fresh rects, coverage 1 by
|
|
464
485
|
* construction) and encode WebM; `ingest` is someone else's recording
|
|
465
486
|
* brought in as a take (`vos ingest`, or a file dropped on the studio),
|
|
466
|
-
* whose cursor track, if any, came from a trace beside it;
|
|
487
|
+
* whose cursor track, if any, came from a trace beside it; `desktop` is a
|
|
488
|
+
* capture helper recording an application's window, its cursor either
|
|
489
|
+
* sampled from the real pointer or synthesized from a script; absent means
|
|
467
490
|
* the extension.
|
|
468
491
|
*/
|
|
469
|
-
producer?: 'extension' | 'cli' | 'ingest';
|
|
492
|
+
producer?: 'extension' | 'cli' | 'ingest' | 'desktop';
|
|
470
493
|
/**
|
|
471
494
|
* The step timeline: when each actions.json step ran, in SOURCE
|
|
472
495
|
* seconds. This is what makes a cut re-anchorable across re-records — a
|
|
@@ -3705,6 +3728,8 @@ interface DigestTakeFacts {
|
|
|
3705
3728
|
producer: string;
|
|
3706
3729
|
pageUrl: string | null;
|
|
3707
3730
|
pageTitle: string | null;
|
|
3731
|
+
/** The recorded application's name, on an `'app'` take. */
|
|
3732
|
+
app: string | null;
|
|
3708
3733
|
hasMic: boolean;
|
|
3709
3734
|
hasSystemAudio: boolean;
|
|
3710
3735
|
hasCursor: boolean;
|
package/dist/index.js
CHANGED
|
@@ -506,7 +506,8 @@ function deriveViewportCrop(cursor, meta) {
|
|
|
506
506
|
}
|
|
507
507
|
function normalizeCaptureSpace(cursor, meta) {
|
|
508
508
|
const surface = meta.captureSurface ?? "tab";
|
|
509
|
-
if (surface === "tab"
|
|
509
|
+
if (surface === "tab" || surface === "app")
|
|
510
|
+
return { cursor, meta, coverage: 1 };
|
|
510
511
|
const anchor = surface === "window" ? meta.windowRect : meta.screenRect;
|
|
511
512
|
const capW = meta.captureWidth ?? 0;
|
|
512
513
|
const capH = meta.captureHeight ?? 0;
|
|
@@ -620,11 +621,12 @@ function projectFromArtifact(artifact, videoUrl, opts = {}) {
|
|
|
620
621
|
const norm = normalizeCaptureSpace(artifact.cursor, artifact.meta);
|
|
621
622
|
const { cursor, meta } = norm;
|
|
622
623
|
const unfocused = surface === "window" && (artifact.meta.windowFocusedFrac ?? 1) < WINDOW_FOCUS_MIN;
|
|
623
|
-
const
|
|
624
|
+
const movedAnchor = surface !== "app" && artifact.meta.windowMovedDuringTake === true;
|
|
625
|
+
const coverage = surface === "monitor" || movedAnchor || unfocused ? 0 : norm.coverage;
|
|
624
626
|
if (artifact.cursor.length > 0 && coverage < CAPTURE_COVERAGE_MIN) {
|
|
625
627
|
console.warn(
|
|
626
628
|
"[studio] dropping cursor track \u2014",
|
|
627
|
-
surface === "monitor" ? "entire-screen takes have no cursor effects (untrackable outside browser pages)" :
|
|
629
|
+
surface === "monitor" ? "entire-screen takes have no cursor effects (untrackable outside browser pages)" : movedAnchor ? "window moved/resized during the take" : unfocused ? `browser window focused only ${Math.round((artifact.meta.windowFocusedFrac ?? 0) * 100)}% of the take \u2014 a different window was likely shared` : `coverage ${norm.coverage.toFixed(2)} (wrong surface shared, or unusable capture geometry)`
|
|
628
630
|
);
|
|
629
631
|
}
|
|
630
632
|
const doc = {
|
|
@@ -8565,6 +8567,11 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
8565
8567
|
cardX = dx; cardY = dy - barH; cardW = dw; cardH = dh + barH
|
|
8566
8568
|
}
|
|
8567
8569
|
var radius = (cfr.radius || 0) * s2
|
|
8570
|
+
// Footage of a window is round at its own corners and opaque outside them.
|
|
8571
|
+
// The card is at least as round, or those corners show as notches. Under
|
|
8572
|
+
// cover the card crops the footage and its corners are not the card's.
|
|
8573
|
+
var ftR = (actM ? actM.footageRadius : d.footageRadius) || 0
|
|
8574
|
+
if (ftR > 0 && !fitCover) radius = Math.max(radius, ftR * dw)
|
|
8568
8575
|
var shadow = cfr.shadow || 0
|
|
8569
8576
|
// The shadow's colour (a #rrggbb; the strengths are its alpha) and the
|
|
8570
8577
|
// optional tight CONTACT layer that makes a light card sit on a light
|
|
@@ -9562,6 +9569,7 @@ function lowerToComposition(input) {
|
|
|
9562
9569
|
})),
|
|
9563
9570
|
cursorStyle: doc.cursor,
|
|
9564
9571
|
cursorSpace: { w: doc.source.meta.width, h: doc.source.meta.height },
|
|
9572
|
+
...footageRadiusData(doc.source.meta, doc.source.crop),
|
|
9565
9573
|
// The other media (concat): each with its element's source, its crop
|
|
9566
9574
|
// and its own cursor in its own capture space; absent = one media.
|
|
9567
9575
|
...doc.media && doc.media.length ? {
|
|
@@ -9586,6 +9594,7 @@ function lowerToComposition(input) {
|
|
|
9586
9594
|
y: round9(p.y)
|
|
9587
9595
|
})),
|
|
9588
9596
|
cursorSpace: { w: m.meta.width, h: m.meta.height },
|
|
9597
|
+
...footageRadiusData(m.meta, m.crop),
|
|
9589
9598
|
// The card this media wears (its own placement, bar, corner,
|
|
9590
9599
|
// shadow, border, fit and focus over the take's), resolved
|
|
9591
9600
|
// here so ON_FRAME swaps one object and reads no document.
|
|
@@ -9860,6 +9869,11 @@ function pinsDataOf(doc, pins) {
|
|
|
9860
9869
|
function round42(v) {
|
|
9861
9870
|
return Math.round(v * 1e5) / 1e5;
|
|
9862
9871
|
}
|
|
9872
|
+
function footageRadiusData(meta, crop) {
|
|
9873
|
+
const r = meta.cornerRadius;
|
|
9874
|
+
if (!r || !(r > 0) || crop || !(meta.width > 0)) return {};
|
|
9875
|
+
return { footageRadius: round42(r / meta.width) };
|
|
9876
|
+
}
|
|
9863
9877
|
function clickFxData(doc, rated) {
|
|
9864
9878
|
const fx = doc.cursor.clickFx;
|
|
9865
9879
|
const on = fx.style !== "none" || fx.press;
|
|
@@ -10774,6 +10788,7 @@ function buildDigest(input) {
|
|
|
10774
10788
|
producer: meta.producer ?? "extension",
|
|
10775
10789
|
pageUrl: meta.pageUrl ?? null,
|
|
10776
10790
|
pageTitle: meta.pageTitle ?? null,
|
|
10791
|
+
app: meta.app?.name ?? null,
|
|
10777
10792
|
hasMic: Boolean(doc.source.micKey) || meta.hasMic === true,
|
|
10778
10793
|
hasSystemAudio: meta.hasAudio === true,
|
|
10779
10794
|
hasCursor: doc.source.cursor.length > 0,
|