@vosjs/studio-core 0.21.0 → 0.22.1
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 +113 -7
- package/dist/index.js +200 -55
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -132,6 +132,9 @@ var DEFAULT_CURSOR_STYLE = {
|
|
|
132
132
|
visible: true,
|
|
133
133
|
smoothing: 0.15,
|
|
134
134
|
size: 24,
|
|
135
|
+
// The dot every earlier take was cut with; a NEW take opens on the
|
|
136
|
+
// arrow (projectFromArtifact sets it), so a document that stores
|
|
137
|
+
// 'default' keeps its dot.
|
|
135
138
|
style: "default",
|
|
136
139
|
hideWhenIdle: true,
|
|
137
140
|
clickFx: DEFAULT_CLICK_FX
|
|
@@ -157,6 +160,10 @@ var BASE_FRAME_STYLE = {
|
|
|
157
160
|
radius: 12,
|
|
158
161
|
shadow: 0.4,
|
|
159
162
|
border: 0,
|
|
163
|
+
// The stage camera: a new take's zoom centres its target and shows the
|
|
164
|
+
// ground past the card's edge. A document without the field keeps the
|
|
165
|
+
// clamped magnifier it was cut with (see FrameStyle.camera).
|
|
166
|
+
camera: "stage",
|
|
160
167
|
// 'native' = the recording's own aspect ratio (meta.width/height). See ASPECT_RATIOS.
|
|
161
168
|
aspectRatio: "native",
|
|
162
169
|
browserBar: DEFAULT_BROWSER_BAR
|
|
@@ -431,7 +438,9 @@ function projectFromArtifact(artifact, videoUrl, opts = {}) {
|
|
|
431
438
|
zoom: [],
|
|
432
439
|
// planner runs once the doc is loaded (editor) or planned (CLI)
|
|
433
440
|
audio: [],
|
|
434
|
-
|
|
441
|
+
// A new take wears the OS pointer; DEFAULT_CURSOR_STYLE keeps the dot
|
|
442
|
+
// so a document that stores it renders as it was cut.
|
|
443
|
+
cursor: { ...DEFAULT_CURSOR_STYLE, style: "arrow" },
|
|
435
444
|
cam: { ...DEFAULT_CAM_STYLE },
|
|
436
445
|
frame: {
|
|
437
446
|
...baseFrame,
|
|
@@ -445,7 +454,9 @@ function projectFromArtifact(artifact, videoUrl, opts = {}) {
|
|
|
445
454
|
url: pageDisplayUrl(artifact.meta.pageUrl)
|
|
446
455
|
}
|
|
447
456
|
},
|
|
448
|
-
|
|
457
|
+
// 60 fps: the footage duplicates frames, the camera does not, and a
|
|
458
|
+
// 0.5 s glide at 30 fps is fifteen visible steps.
|
|
459
|
+
export: { resolution: "1080p", fps: 60, format: "mp4" }
|
|
449
460
|
};
|
|
450
461
|
return { doc, videoUrl };
|
|
451
462
|
}
|
|
@@ -1132,6 +1143,12 @@ function clamp(v, lo, hi) {
|
|
|
1132
1143
|
// src/zoomStyle.ts
|
|
1133
1144
|
var ZOOM_STYLES = {
|
|
1134
1145
|
// Cursorful strategy — one steady zoom per activity session, travel by pans.
|
|
1146
|
+
// The camera's timing was measured against a Cursorful take of the same
|
|
1147
|
+
// steps: a zoom-in of ~0.55 s on a heavy ease-out (most of the move in
|
|
1148
|
+
// the first quarter second, a long settle), a zoom-out of ~0.45 s, and
|
|
1149
|
+
// holds of four to five seconds per beat. The old 1.1 s ramp started
|
|
1150
|
+
// 0.75 s BEFORE the click and landed 0.35 s after it, so the frame was
|
|
1151
|
+
// moving more of the time than it was resting.
|
|
1135
1152
|
glide: {
|
|
1136
1153
|
autoZoom: true,
|
|
1137
1154
|
clusterGap: 3,
|
|
@@ -1139,22 +1156,27 @@ var ZOOM_STYLES = {
|
|
|
1139
1156
|
targetFill: 0.42,
|
|
1140
1157
|
minLevel: 1.3,
|
|
1141
1158
|
maxLevel: 1.8,
|
|
1142
|
-
lead: 0.
|
|
1143
|
-
hold:
|
|
1159
|
+
lead: 0.35,
|
|
1160
|
+
hold: 1.2,
|
|
1144
1161
|
followByDefault: true,
|
|
1145
1162
|
typingZoom: true,
|
|
1146
1163
|
typingGap: 2.5,
|
|
1147
1164
|
typingHold: 1.1,
|
|
1148
1165
|
typingMinLevel: 1.4,
|
|
1149
|
-
rampIn:
|
|
1150
|
-
rampInOverlap: 0.
|
|
1151
|
-
rampOut:
|
|
1152
|
-
chainGap:
|
|
1153
|
-
pan:
|
|
1154
|
-
|
|
1155
|
-
|
|
1166
|
+
rampIn: 0.55,
|
|
1167
|
+
rampInOverlap: 0.2,
|
|
1168
|
+
rampOut: 0.5,
|
|
1169
|
+
chainGap: 3,
|
|
1170
|
+
pan: 0.55,
|
|
1171
|
+
// The reference's corner trace at 60 fps: a quarter of the move by a
|
|
1172
|
+
// fifth of the time, two thirds by half, the rest a settle. That is
|
|
1173
|
+
// CSS `ease` (0.25, 0.1, 0.25, 1), a small lead-in and a long tail;
|
|
1174
|
+
// (0.16, 1, 0.3, 1) put half the move in the first sixty milliseconds
|
|
1175
|
+
// and read as a twitch.
|
|
1176
|
+
ease: "css-bezier(0.25, 0.1, 0.25, 1)",
|
|
1177
|
+
panEase: "css-bezier(0.3, 0.05, 0.25, 1)",
|
|
1156
1178
|
followSafeRatio: 0.45,
|
|
1157
|
-
followRecenter: 0.
|
|
1179
|
+
followRecenter: 0.55,
|
|
1158
1180
|
followLookahead: 0.4,
|
|
1159
1181
|
tilt: { intensity: "off" }
|
|
1160
1182
|
},
|
|
@@ -1865,10 +1887,29 @@ function camBubbleRect(cam, W, H = 1080) {
|
|
|
1865
1887
|
radius: cam.shape === "rounded" ? (cam.radius ?? 18) * s : size / 2
|
|
1866
1888
|
};
|
|
1867
1889
|
}
|
|
1868
|
-
function focusBounds(level, layout) {
|
|
1890
|
+
function focusBounds(level, layout, camera = "card") {
|
|
1869
1891
|
if (level <= 1.001) {
|
|
1870
1892
|
return { minX: 0.5, maxX: 0.5, minY: 0.5, maxY: 0.5 };
|
|
1871
1893
|
}
|
|
1894
|
+
if (camera === "stage") {
|
|
1895
|
+
const x2 = stageAxisBounds(
|
|
1896
|
+
layout.dx,
|
|
1897
|
+
layout.dw,
|
|
1898
|
+
layout.cardX,
|
|
1899
|
+
layout.cardW,
|
|
1900
|
+
layout.W,
|
|
1901
|
+
level
|
|
1902
|
+
);
|
|
1903
|
+
const y2 = stageAxisBounds(
|
|
1904
|
+
layout.dy,
|
|
1905
|
+
layout.dh,
|
|
1906
|
+
layout.cardY,
|
|
1907
|
+
layout.cardH,
|
|
1908
|
+
layout.H,
|
|
1909
|
+
level
|
|
1910
|
+
);
|
|
1911
|
+
return { minX: x2.min, maxX: x2.max, minY: y2.min, maxY: y2.max };
|
|
1912
|
+
}
|
|
1872
1913
|
const x = axisBounds(
|
|
1873
1914
|
layout.dx,
|
|
1874
1915
|
layout.dw,
|
|
@@ -1898,8 +1939,19 @@ function axisBounds(anchorOff, anchorSize, coverOff, coverSize, viewport, level)
|
|
|
1898
1939
|
}
|
|
1899
1940
|
return { min: clamp013(lo), max: clamp013(hi) };
|
|
1900
1941
|
}
|
|
1901
|
-
function
|
|
1902
|
-
const b =
|
|
1942
|
+
function stageAxisBounds(anchorOff, anchorSize, coverOff, coverSize, viewport, level) {
|
|
1943
|
+
const b = CAMERA_COVER_MIN / 2 * viewport;
|
|
1944
|
+
let lo = (coverOff + b / level - anchorOff) / anchorSize;
|
|
1945
|
+
let hi = (coverOff + coverSize - b / level - anchorOff) / anchorSize;
|
|
1946
|
+
if (lo > hi) {
|
|
1947
|
+
const mid = (lo + hi) / 2;
|
|
1948
|
+
lo = mid;
|
|
1949
|
+
hi = mid;
|
|
1950
|
+
}
|
|
1951
|
+
return { min: clamp013(lo), max: clamp013(hi) };
|
|
1952
|
+
}
|
|
1953
|
+
function clampFocus(cx, cy, level, layout, camera = "card") {
|
|
1954
|
+
const b = focusBounds(level, layout, camera);
|
|
1903
1955
|
return {
|
|
1904
1956
|
cx: Math.min(b.maxX, Math.max(b.minX, cx)),
|
|
1905
1957
|
cy: Math.min(b.maxY, Math.max(b.minY, cy))
|
|
@@ -1908,6 +1960,45 @@ function clampFocus(cx, cy, level, layout) {
|
|
|
1908
1960
|
function clamp013(v) {
|
|
1909
1961
|
return Math.max(0, Math.min(1, v));
|
|
1910
1962
|
}
|
|
1963
|
+
function cameraModel(frame) {
|
|
1964
|
+
return frame?.camera === "stage" ? "stage" : "card";
|
|
1965
|
+
}
|
|
1966
|
+
var CAMERA_CENTRE_RAMP = 0.3;
|
|
1967
|
+
var CAMERA_COVER_MIN = 0.8;
|
|
1968
|
+
function cameraCentring(level) {
|
|
1969
|
+
const u = clamp013((level - 1) / CAMERA_CENTRE_RAMP);
|
|
1970
|
+
return u * u * (3 - 2 * u);
|
|
1971
|
+
}
|
|
1972
|
+
function zoomView(level, cx, cy, layout, camera = "card", centring) {
|
|
1973
|
+
const L = Math.max(1, level);
|
|
1974
|
+
const fx = layout.dx + cx * layout.dw;
|
|
1975
|
+
const fy = layout.dy + cy * layout.dh;
|
|
1976
|
+
const ox = layout.W / 2;
|
|
1977
|
+
const oy = layout.H / 2;
|
|
1978
|
+
const t = camera === "stage" ? clamp013(centring ?? 1) : 0;
|
|
1979
|
+
const wcx = fx + (ox - fx) / L * (1 - t);
|
|
1980
|
+
const wcy = fy + (oy - fy) / L * (1 - t);
|
|
1981
|
+
return { level: L, fx, fy, wcx, wcy, ox, oy };
|
|
1982
|
+
}
|
|
1983
|
+
function zoomViewport(level, cx, cy, layout, camera = "card", centring) {
|
|
1984
|
+
const v = zoomView(level, cx, cy, layout, camera, centring);
|
|
1985
|
+
const size = 1 / v.level;
|
|
1986
|
+
return {
|
|
1987
|
+
x: (v.wcx - layout.W / (2 * v.level)) / layout.W,
|
|
1988
|
+
y: (v.wcy - layout.H / (2 * v.level)) / layout.H,
|
|
1989
|
+
w: size,
|
|
1990
|
+
h: size
|
|
1991
|
+
};
|
|
1992
|
+
}
|
|
1993
|
+
function focusForViewportCentre(cX, cY, level, layout, camera = "card", centring) {
|
|
1994
|
+
const L = Math.max(1, level);
|
|
1995
|
+
const t = camera === "stage" ? clamp013(centring ?? 1) : 0;
|
|
1996
|
+
const a = 1 - (1 - t) / L;
|
|
1997
|
+
if (a <= 1e-6) return { cx: 0.5, cy: 0.5 };
|
|
1998
|
+
const fx = (cX * layout.W - layout.W / 2 * (1 - t) / L) / a;
|
|
1999
|
+
const fy = (cY * layout.H - layout.H / 2 * (1 - t) / L) / a;
|
|
2000
|
+
return { cx: (fx - layout.dx) / layout.dw, cy: (fy - layout.dy) / layout.dh };
|
|
2001
|
+
}
|
|
1911
2002
|
function levelForFocusFraction(frac) {
|
|
1912
2003
|
if (!(frac > 0)) return clampZoomLevel(Number.POSITIVE_INFINITY);
|
|
1913
2004
|
return clampZoomLevel(Math.max(1.1, 1 / frac));
|
|
@@ -2812,6 +2903,7 @@ function followFocusEvents(span, cursor, space, layout, options = {}) {
|
|
|
2812
2903
|
const safeRatio = options.safeRatio ?? FOLLOW_SAFE_RATIO;
|
|
2813
2904
|
const recenter = options.recenter ?? FOLLOW_RECENTER;
|
|
2814
2905
|
const lookahead = options.lookahead ?? 0;
|
|
2906
|
+
const camera = options.camera ?? "card";
|
|
2815
2907
|
const level = clampZoomLevel(span.level);
|
|
2816
2908
|
if (!cursor.length || !space.w || !space.h || level <= 1.001) {
|
|
2817
2909
|
return { entry: null, events: [] };
|
|
@@ -2822,12 +2914,7 @@ function followFocusEvents(span, cursor, space, layout, options = {}) {
|
|
|
2822
2914
|
ny: clamp014(e.y / space.h)
|
|
2823
2915
|
}));
|
|
2824
2916
|
if (!pts.length) return { entry: null, events: [] };
|
|
2825
|
-
|
|
2826
|
-
for (const p of pts) {
|
|
2827
|
-
if (p.t > span.in) break;
|
|
2828
|
-
entryPt = p;
|
|
2829
|
-
}
|
|
2830
|
-
const entry = clampFocus(entryPt.nx, entryPt.ny, level, layout);
|
|
2917
|
+
const entry = clampFocus(span.cx, span.cy, level, layout, camera);
|
|
2831
2918
|
const thrX = safeRatio * layout.W / (2 * level * layout.dw);
|
|
2832
2919
|
const thrY = safeRatio * layout.H / (2 * level * layout.dh);
|
|
2833
2920
|
const events = [];
|
|
@@ -2840,7 +2927,7 @@ function followFocusEvents(span, cursor, space, layout, options = {}) {
|
|
|
2840
2927
|
if (p.t < nextAllowed) continue;
|
|
2841
2928
|
if (Math.abs(p.nx - cx) > thrX || Math.abs(p.ny - cy) > thrY) {
|
|
2842
2929
|
const target = lookahead > 0 ? sampleAt2(pts, Math.min(p.t + lookahead, span.out)) : p;
|
|
2843
|
-
const f = clampFocus(target.nx, target.ny, level, layout);
|
|
2930
|
+
const f = clampFocus(target.nx, target.ny, level, layout, camera);
|
|
2844
2931
|
if (Math.abs(f.cx - cx) < 1e-3 && Math.abs(f.cy - cy) < 1e-3) continue;
|
|
2845
2932
|
events.push({ t: round2(p.t), cx: round2(f.cx), cy: round2(f.cy) });
|
|
2846
2933
|
cx = f.cx;
|
|
@@ -4573,13 +4660,13 @@ function zoomTrackFromDoc(zoom, segments, style = ZOOM_STYLES[DEFAULT_ZOOM_STYLE
|
|
|
4573
4660
|
let chained = false;
|
|
4574
4661
|
for (let i = 0; i < mapped.length; i++) {
|
|
4575
4662
|
const { z, tIn, tOut } = mapped[i];
|
|
4576
|
-
const entry = [clampZoomLevel(z.level), z.cx, z.cy];
|
|
4663
|
+
const entry = [clampZoomLevel(z.level), z.cx, z.cy, 1];
|
|
4577
4664
|
let cur = entry;
|
|
4578
4665
|
const m = transitionMult(z.transition);
|
|
4579
4666
|
if (!chained) {
|
|
4580
4667
|
const start = push2(
|
|
4581
4668
|
tIn - (style.rampIn - style.rampInOverlap) * m,
|
|
4582
|
-
[1, z.cx, z.cy],
|
|
4669
|
+
[1, z.cx, z.cy, 0],
|
|
4583
4670
|
"none"
|
|
4584
4671
|
);
|
|
4585
4672
|
push2(start + style.rampIn * m, entry, spanEase(z.ease, style.ease));
|
|
@@ -4587,7 +4674,7 @@ function zoomTrackFromDoc(zoom, segments, style = ZOOM_STYLES[DEFAULT_ZOOM_STYLE
|
|
|
4587
4674
|
for (const e of z.followEvents ?? []) {
|
|
4588
4675
|
const eOut = sourceToTimeline(segments, e.t);
|
|
4589
4676
|
if (eOut === null || eOut <= tIn || eOut >= tOut) continue;
|
|
4590
|
-
const next2 = [cur[0], e.cx, e.cy];
|
|
4677
|
+
const next2 = [cur[0], e.cx, e.cy, 1];
|
|
4591
4678
|
push2(eOut, cur, "none");
|
|
4592
4679
|
push2(Math.min(eOut + style.followRecenter, tOut), next2, panEase);
|
|
4593
4680
|
cur = next2;
|
|
@@ -4596,7 +4683,7 @@ function zoomTrackFromDoc(zoom, segments, style = ZOOM_STYLES[DEFAULT_ZOOM_STYLE
|
|
|
4596
4683
|
const next = mapped.at(i + 1);
|
|
4597
4684
|
if (next && next.tIn - tOut <= style.chainGap) {
|
|
4598
4685
|
const mNext = transitionMult(next.z.transition);
|
|
4599
|
-
const nextValue = [clampZoomLevel(next.z.level), next.z.cx, next.z.cy];
|
|
4686
|
+
const nextValue = [clampZoomLevel(next.z.level), next.z.cx, next.z.cy, 1];
|
|
4600
4687
|
push2(
|
|
4601
4688
|
Math.min(
|
|
4602
4689
|
tOut + style.pan * mNext,
|
|
@@ -4609,7 +4696,7 @@ function zoomTrackFromDoc(zoom, segments, style = ZOOM_STYLES[DEFAULT_ZOOM_STYLE
|
|
|
4609
4696
|
} else {
|
|
4610
4697
|
push2(
|
|
4611
4698
|
tOut + style.rampOut * m,
|
|
4612
|
-
[1, cur[1], cur[2]],
|
|
4699
|
+
[1, cur[1], cur[2], 0],
|
|
4613
4700
|
spanEase(z.ease, style.ease)
|
|
4614
4701
|
);
|
|
4615
4702
|
chained = false;
|
|
@@ -5791,11 +5878,15 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
5791
5878
|
// current zoom \u2014 a standard keyframe track in OUTPUT time (hold + arrival pairs
|
|
5792
5879
|
// expanded by the lowering), sampled with the shared deterministic interpolator.
|
|
5793
5880
|
// Sampled here, before the rect math, so a cover crop can follow it.
|
|
5794
|
-
var lvl = 1, zx = 0.5, zy = 0.5
|
|
5881
|
+
var lvl = 1, zx = 0.5, zy = 0.5, zc = -1
|
|
5795
5882
|
var zt = d.zoomTrack
|
|
5796
5883
|
if (zt && zt.keyframes && zt.keyframes.length) {
|
|
5797
5884
|
var z = TL.sample(zt, tpT, TL.lerpArray)
|
|
5798
5885
|
lvl = z[0]; zx = z[1]; zy = z[2]
|
|
5886
|
+
// The stage camera's centring rides the track (0 rest, 1 apex, eased
|
|
5887
|
+
// with the level); a three-component track (a document lowered before
|
|
5888
|
+
// the component existed) falls back to the level band below.
|
|
5889
|
+
if (z.length > 3) zc = z[3]
|
|
5799
5890
|
}
|
|
5800
5891
|
var barH = bar.kind && bar.kind !== 'none' ? (bar.height || 44) * s2 : 0
|
|
5801
5892
|
var availW = Math.max(1, W - ipL - ipR), availH = Math.max(1, H - ipT - ipB - barH)
|
|
@@ -5844,9 +5935,31 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
5844
5935
|
// ceZs = the zoom transform's device scale, for the two values below that
|
|
5845
5936
|
// are sized in DEVICE pixels inside a scaled user space.
|
|
5846
5937
|
var ceZs = 1
|
|
5938
|
+
// The camera model (cfr.camera; MIRRORS layout.ts zoomView \u2014 change them
|
|
5939
|
+
// together). The magnifier scales the card about the focus, which stays
|
|
5940
|
+
// where it is on screen; the stage camera also slides the card so the
|
|
5941
|
+
// focus lands at the frame's centre, blended in over CAMERA_CENTRE_RAMP
|
|
5942
|
+
// of level (a smoothstep, 0 at level 1) so a ramp through the band slides
|
|
5943
|
+
// without a kink, and past the card's edge the ground shows. wcx/wcy is
|
|
5944
|
+
// the content point at the frame's centre under either model; the two
|
|
5945
|
+
// branches are the same map, the magnifier's kept in its old float order
|
|
5946
|
+
// so every existing document renders byte-identically.
|
|
5947
|
+
var camStage = cfr.camera === 'stage'
|
|
5948
|
+
var fx = dx + zx * dw, fy = dy + zy * dh
|
|
5949
|
+
var wcx = fx, wcy = fy
|
|
5847
5950
|
if (lvl > 1.001 && !d.zoomSuppressed) {
|
|
5848
|
-
|
|
5849
|
-
|
|
5951
|
+
if (camStage) {
|
|
5952
|
+
var ctt = zc
|
|
5953
|
+
if (ctt < 0) {
|
|
5954
|
+
var ctu = Math.max(0, Math.min(1, (lvl - 1) / ${CAMERA_CENTRE_RAMP}))
|
|
5955
|
+
ctt = ctu * ctu * (3 - 2 * ctu)
|
|
5956
|
+
}
|
|
5957
|
+
wcx = fx + ((W / 2 - fx) / lvl) * (1 - ctt)
|
|
5958
|
+
wcy = fy + ((H / 2 - fy) / lvl) * (1 - ctt)
|
|
5959
|
+
c.translate(W / 2, H / 2); c.scale(lvl, lvl); c.translate(-wcx, -wcy)
|
|
5960
|
+
} else {
|
|
5961
|
+
c.translate(fx, fy); c.scale(lvl, lvl); c.translate(-fx, -fy)
|
|
5962
|
+
}
|
|
5850
5963
|
ceZs = lvl
|
|
5851
5964
|
}
|
|
5852
5965
|
// The card's shadows are cast by a body drawn OFF-CANVAS and brought back
|
|
@@ -5988,6 +6101,34 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
5988
6101
|
// cursor coordinate space + drawn radius (shared by click effects + the dot)
|
|
5989
6102
|
var space = (actM ? actM.cursorSpace : d.cursorSpace) || { w: vw, h: vh }
|
|
5990
6103
|
var curSize = ((d.cursorStyle && d.cursorStyle.size) || 24) * s2 * 0.5
|
|
6104
|
+
// The pointer's shape: an OS-style arrow (tip on the recorded point, a
|
|
6105
|
+
// black body with a white edge, the shape of the pointer on the viewer's
|
|
6106
|
+
// own screen) or the white dot every earlier take was cut with. One
|
|
6107
|
+
// painter for both draw sites (in the card, and the ghost across a
|
|
6108
|
+
// boundary); r is the dot's radius, so an arrow stands 2r tall.
|
|
6109
|
+
var curArrow = !!(d.cursorStyle && d.cursorStyle.style === 'arrow')
|
|
6110
|
+
function drawCur(cc, x, y, r, a, lw) {
|
|
6111
|
+
cc.save()
|
|
6112
|
+
if (curArrow) {
|
|
6113
|
+
var h = 2 * r
|
|
6114
|
+
var P = [[0, 0], [0, 0.72], [0.19, 0.55], [0.31, 0.83], [0.43, 0.78], [0.31, 0.5], [0.55, 0.5]]
|
|
6115
|
+
cc.beginPath()
|
|
6116
|
+
cc.moveTo(x, y)
|
|
6117
|
+
for (var pi = 1; pi < P.length; pi++) cc.lineTo(x + P[pi][0] * h, y + P[pi][1] * h)
|
|
6118
|
+
cc.closePath()
|
|
6119
|
+
cc.lineJoin = 'round'
|
|
6120
|
+
cc.fillStyle = 'rgba(0,0,0,' + (0.92 * a) + ')'
|
|
6121
|
+
cc.strokeStyle = 'rgba(255,255,255,' + (0.95 * a) + ')'
|
|
6122
|
+
cc.lineWidth = Math.max(1, lw * 0.75)
|
|
6123
|
+
cc.fill(); cc.stroke()
|
|
6124
|
+
} else {
|
|
6125
|
+
cc.fillStyle = 'rgba(255,255,255,' + (0.95 * a) + ')'
|
|
6126
|
+
cc.strokeStyle = 'rgba(0,0,0,' + (0.4 * a) + ')'
|
|
6127
|
+
cc.lineWidth = lw
|
|
6128
|
+
cc.beginPath(); cc.arc(x, y, r, 0, Math.PI * 2); cc.fill(); cc.stroke()
|
|
6129
|
+
}
|
|
6130
|
+
cc.restore()
|
|
6131
|
+
}
|
|
5991
6132
|
|
|
5992
6133
|
// click effects \u2014 pure f(t): d.clicks are
|
|
5993
6134
|
// OUTPUT-anchored records baked at lowering (sorted by ot; re-baked on every
|
|
@@ -6161,16 +6302,14 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
6161
6302
|
// moving: each pass leaves its point, mapped out of the zoom.
|
|
6162
6303
|
if (trOut) {
|
|
6163
6304
|
var tqX = ax, tqY = ay
|
|
6164
|
-
if (lvl > 1.001 && !d.zoomSuppressed) {
|
|
6305
|
+
if (lvl > 1.001 && !d.zoomSuppressed) {
|
|
6306
|
+
if (camStage) { tqX = W / 2 + (ax - wcx) * lvl; tqY = H / 2 + (ay - wcy) * lvl }
|
|
6307
|
+
else { tqX = fx + (ax - fx) * lvl; tqY = fy + (ay - fy) * lvl }
|
|
6308
|
+
}
|
|
6165
6309
|
if (tpG) trQa = [tqX, tqY]
|
|
6166
6310
|
else { trQb = [tqX, tqY]; trQs = curSize * ckPress; trQw = s2 }
|
|
6167
6311
|
} else if (cuA > 0.01) {
|
|
6168
|
-
c
|
|
6169
|
-
c.fillStyle = 'rgba(255,255,255,' + (0.95 * cuA) + ')'
|
|
6170
|
-
c.strokeStyle = 'rgba(0,0,0,' + (0.4 * cuA) + ')'
|
|
6171
|
-
c.lineWidth = 2 * s2
|
|
6172
|
-
c.beginPath(); c.arc(ax, ay, curSize * ckPress, 0, Math.PI * 2); c.fill(); c.stroke()
|
|
6173
|
-
c.restore()
|
|
6312
|
+
drawCur(c, ax, ay, curSize * ckPress, cuA, 2 * s2)
|
|
6174
6313
|
}
|
|
6175
6314
|
}
|
|
6176
6315
|
if (fitCover) c.restore()
|
|
@@ -6255,12 +6394,7 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
6255
6394
|
var tqBx = (tqB[0] - W / 2) * trSc + W / 2 + trOx * W, tqBy = (tqB[1] - H / 2) * trSc + H / 2 - trOy * H
|
|
6256
6395
|
var tqX2 = tqAx + (tqBx - tqAx) * tqP, tqY2 = tqAy + (tqBy - tqAy) * tqP
|
|
6257
6396
|
var tqR = trQs || (((d.cursorStyle && d.cursorStyle.size) || 24) * s * 0.5)
|
|
6258
|
-
ovC
|
|
6259
|
-
ovC.fillStyle = 'rgba(255,255,255,0.95)'
|
|
6260
|
-
ovC.strokeStyle = 'rgba(0,0,0,0.4)'
|
|
6261
|
-
ovC.lineWidth = 2 * (trQw || s)
|
|
6262
|
-
ovC.beginPath(); ovC.arc(tqX2, tqY2, tqR, 0, Math.PI * 2); ovC.fill(); ovC.stroke()
|
|
6263
|
-
ovC.restore()
|
|
6397
|
+
drawCur(ovC, tqX2, tqY2, tqR, 1, 2 * (trQw || s))
|
|
6264
6398
|
}
|
|
6265
6399
|
ov.sig = ovSig
|
|
6266
6400
|
ov.active = camActiveNow || !!trOut
|
|
@@ -6599,6 +6733,7 @@ function lowerToComposition(input) {
|
|
|
6599
6733
|
const layout = docCardLayout(doc);
|
|
6600
6734
|
const meta = doc.source.meta;
|
|
6601
6735
|
const zoomStyle = resolveZoomStyle(doc.zoomStyle, doc.zoomParams);
|
|
6736
|
+
const camera = cameraModel(doc.frame);
|
|
6602
6737
|
const zoomSpans = restSpansThroughTransitions(
|
|
6603
6738
|
doc.zoom,
|
|
6604
6739
|
rated,
|
|
@@ -6614,13 +6749,17 @@ function lowerToComposition(input) {
|
|
|
6614
6749
|
{
|
|
6615
6750
|
safeRatio: zoomStyle.followSafeRatio,
|
|
6616
6751
|
recenter: zoomStyle.followRecenter,
|
|
6617
|
-
lookahead: zoomStyle.followLookahead
|
|
6752
|
+
lookahead: zoomStyle.followLookahead,
|
|
6753
|
+
camera
|
|
6618
6754
|
}
|
|
6619
6755
|
);
|
|
6620
6756
|
if (f.entry)
|
|
6621
6757
|
return { ...z, cx: f.entry.cx, cy: f.entry.cy, followEvents: f.events };
|
|
6622
6758
|
}
|
|
6623
|
-
return {
|
|
6759
|
+
return {
|
|
6760
|
+
...z,
|
|
6761
|
+
...clampFocus(z.cx, z.cy, clampZoomLevel(z.level), layout, camera)
|
|
6762
|
+
};
|
|
6624
6763
|
});
|
|
6625
6764
|
const data = {
|
|
6626
6765
|
videoSrc: doc.source.videoKey,
|
|
@@ -7176,15 +7315,14 @@ function sceneChanges(bins, opts = {}) {
|
|
|
7176
7315
|
}
|
|
7177
7316
|
|
|
7178
7317
|
// src/digest/framing.ts
|
|
7179
|
-
function zoomWindow(span, layout) {
|
|
7318
|
+
function zoomWindow(span, layout, camera = "card") {
|
|
7180
7319
|
const L = Math.max(1, span.level);
|
|
7181
|
-
const { cx, cy } = clampFocus(span.cx, span.cy, L, layout);
|
|
7182
|
-
const
|
|
7183
|
-
const
|
|
7184
|
-
const
|
|
7185
|
-
const
|
|
7186
|
-
const
|
|
7187
|
-
const py1 = fy + (layout.H - fy) / L;
|
|
7320
|
+
const { cx, cy } = clampFocus(span.cx, span.cy, L, layout, camera);
|
|
7321
|
+
const v = zoomViewport(L, cx, cy, layout, camera);
|
|
7322
|
+
const px0 = v.x * layout.W;
|
|
7323
|
+
const px1 = (v.x + v.w) * layout.W;
|
|
7324
|
+
const py0 = v.y * layout.H;
|
|
7325
|
+
const py1 = (v.y + v.h) * layout.H;
|
|
7188
7326
|
return {
|
|
7189
7327
|
x0: (px0 - layout.dx) / layout.dw,
|
|
7190
7328
|
x1: (px1 - layout.dx) / layout.dw,
|
|
@@ -7192,9 +7330,9 @@ function zoomWindow(span, layout) {
|
|
|
7192
7330
|
y1: (py1 - layout.dy) / layout.dh
|
|
7193
7331
|
};
|
|
7194
7332
|
}
|
|
7195
|
-
function zoomCoversRect(span, rect, layout, tol = 0.02) {
|
|
7333
|
+
function zoomCoversRect(span, rect, layout, tol = 0.02, camera = "card") {
|
|
7196
7334
|
if (span.level <= 1.001) return true;
|
|
7197
|
-
const w = zoomWindow(span, layout);
|
|
7335
|
+
const w = zoomWindow(span, layout, camera);
|
|
7198
7336
|
return rect.x >= w.x0 - tol && rect.x + rect.w <= w.x1 + tol && rect.y >= w.y0 - tol && rect.y + rect.h <= w.y1 + tol;
|
|
7199
7337
|
}
|
|
7200
7338
|
|
|
@@ -9812,6 +9950,8 @@ export {
|
|
|
9812
9950
|
AUDIO_PLAN_STEP,
|
|
9813
9951
|
BACKGROUND_Z,
|
|
9814
9952
|
BASE_FRAME_STYLE,
|
|
9953
|
+
CAMERA_CENTRE_RAMP,
|
|
9954
|
+
CAMERA_COVER_MIN,
|
|
9815
9955
|
CAMERA_FAR,
|
|
9816
9956
|
CAMERA_NEAR,
|
|
9817
9957
|
CAM_CHAIN_GAP,
|
|
@@ -9978,6 +10118,8 @@ export {
|
|
|
9978
10118
|
camRectFromPose,
|
|
9979
10119
|
camRestPose,
|
|
9980
10120
|
camTrackFromDoc,
|
|
10121
|
+
cameraCentring,
|
|
10122
|
+
cameraModel,
|
|
9981
10123
|
cardEnter,
|
|
9982
10124
|
cardExit,
|
|
9983
10125
|
cardFields,
|
|
@@ -10032,6 +10174,7 @@ export {
|
|
|
10032
10174
|
exportSizeFor,
|
|
10033
10175
|
extractClicks,
|
|
10034
10176
|
focusBounds,
|
|
10177
|
+
focusForViewportCentre,
|
|
10035
10178
|
followFocusEvents,
|
|
10036
10179
|
frameGeometry,
|
|
10037
10180
|
freezeLane,
|
|
@@ -10159,6 +10302,8 @@ export {
|
|
|
10159
10302
|
zoomLane,
|
|
10160
10303
|
zoomSpanForRange,
|
|
10161
10304
|
zoomTrackFromDoc,
|
|
10305
|
+
zoomView,
|
|
10306
|
+
zoomViewport,
|
|
10162
10307
|
zoomWindow
|
|
10163
10308
|
};
|
|
10164
10309
|
//# sourceMappingURL=index.js.map
|