@vosjs/studio-core 0.22.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 CHANGED
@@ -2337,10 +2337,12 @@ declare function cameraModel(frame: {
2337
2337
  camera?: string | null;
2338
2338
  } | null | undefined): CameraModel;
2339
2339
  /**
2340
- * How much of the level the stage camera spends pulling the focus to the
2341
- * frame's centre: 0 at level 1 (the identity), fully centred from level
2342
- * 1 + CAMERA_CENTRE_RAMP. A smoothstep, so a ramp that passes through the
2343
- * band slides the card without a kink.
2340
+ * The stage camera's centring is a component of the zoom TRACK (0 at rest,
2341
+ * 1 at an apex, eased with the level), so the card's slide and its scale
2342
+ * are one motion. This band is the FALLBACK for a track lowered before the
2343
+ * component existed: centring as a smoothstep of the level over
2344
+ * 1 .. 1 + CAMERA_CENTRE_RAMP. Keyed to the level it front-loaded the
2345
+ * slide, since any ease crosses the band in its first frames (the twitch).
2344
2346
  */
2345
2347
  declare const CAMERA_CENTRE_RAMP = 0.3;
2346
2348
  /**
@@ -2372,7 +2374,14 @@ interface ZoomView {
2372
2374
  ox: number;
2373
2375
  oy: number;
2374
2376
  }
2375
- declare function zoomView(level: number, cx: number, cy: number, layout: CardLayout, camera?: CameraModel): ZoomView;
2377
+ declare function zoomView(level: number, cx: number, cy: number, layout: CardLayout, camera?: CameraModel,
2378
+ /**
2379
+ * The stage camera's centring at this instant, 0..1: the zoom track's
2380
+ * fourth component (0 at rest, 1 at an apex, eased with the level).
2381
+ * Absent = the apex (1) under the stage camera, which is what a span's
2382
+ * stored focus describes; always 0 under the magnifier.
2383
+ */
2384
+ centring?: number): ZoomView;
2376
2385
  /**
2377
2386
  * The visible window as fractions of the canvas (x/y its top-left, w/h its
2378
2387
  * size, both 1/level): what the studio's aiming rect draws and what the
@@ -2380,7 +2389,7 @@ declare function zoomView(level: number, cx: number, cy: number, layout: CardLay
2380
2389
  * under the stage camera; it never does under the magnifier once the focus
2381
2390
  * is clamped.
2382
2391
  */
2383
- declare function zoomViewport(level: number, cx: number, cy: number, layout: CardLayout, camera?: CameraModel): {
2392
+ declare function zoomViewport(level: number, cx: number, cy: number, layout: CardLayout, camera?: CameraModel, centring?: number): {
2384
2393
  x: number;
2385
2394
  y: number;
2386
2395
  w: number;
@@ -2392,7 +2401,7 @@ declare function zoomViewport(level: number, cx: number, cy: number, layout: Car
2392
2401
  * `level`. The aiming rect's corner drag re-derives its focus through this
2393
2402
  * so the rect stays under the pointer in either camera model.
2394
2403
  */
2395
- declare function focusForViewportCentre(cX: number, cY: number, level: number, layout: CardLayout, camera?: CameraModel): {
2404
+ declare function focusForViewportCentre(cX: number, cY: number, level: number, layout: CardLayout, camera?: CameraModel, centring?: number): {
2396
2405
  cx: number;
2397
2406
  cy: number;
2398
2407
  };
package/dist/index.js CHANGED
@@ -1168,8 +1168,13 @@ var ZOOM_STYLES = {
1168
1168
  rampOut: 0.5,
1169
1169
  chainGap: 3,
1170
1170
  pan: 0.55,
1171
- ease: "css-bezier(0.16, 1, 0.3, 1)",
1172
- panEase: "css-bezier(0.22, 1, 0.36, 1)",
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)",
1173
1178
  followSafeRatio: 0.45,
1174
1179
  followRecenter: 0.55,
1175
1180
  followLookahead: 0.4,
@@ -1964,19 +1969,19 @@ function cameraCentring(level) {
1964
1969
  const u = clamp013((level - 1) / CAMERA_CENTRE_RAMP);
1965
1970
  return u * u * (3 - 2 * u);
1966
1971
  }
1967
- function zoomView(level, cx, cy, layout, camera = "card") {
1972
+ function zoomView(level, cx, cy, layout, camera = "card", centring) {
1968
1973
  const L = Math.max(1, level);
1969
1974
  const fx = layout.dx + cx * layout.dw;
1970
1975
  const fy = layout.dy + cy * layout.dh;
1971
1976
  const ox = layout.W / 2;
1972
1977
  const oy = layout.H / 2;
1973
- const t = camera === "stage" ? cameraCentring(L) : 0;
1978
+ const t = camera === "stage" ? clamp013(centring ?? 1) : 0;
1974
1979
  const wcx = fx + (ox - fx) / L * (1 - t);
1975
1980
  const wcy = fy + (oy - fy) / L * (1 - t);
1976
1981
  return { level: L, fx, fy, wcx, wcy, ox, oy };
1977
1982
  }
1978
- function zoomViewport(level, cx, cy, layout, camera = "card") {
1979
- const v = zoomView(level, cx, cy, layout, camera);
1983
+ function zoomViewport(level, cx, cy, layout, camera = "card", centring) {
1984
+ const v = zoomView(level, cx, cy, layout, camera, centring);
1980
1985
  const size = 1 / v.level;
1981
1986
  return {
1982
1987
  x: (v.wcx - layout.W / (2 * v.level)) / layout.W,
@@ -1985,9 +1990,9 @@ function zoomViewport(level, cx, cy, layout, camera = "card") {
1985
1990
  h: size
1986
1991
  };
1987
1992
  }
1988
- function focusForViewportCentre(cX, cY, level, layout, camera = "card") {
1993
+ function focusForViewportCentre(cX, cY, level, layout, camera = "card", centring) {
1989
1994
  const L = Math.max(1, level);
1990
- const t = camera === "stage" ? cameraCentring(L) : 0;
1995
+ const t = camera === "stage" ? clamp013(centring ?? 1) : 0;
1991
1996
  const a = 1 - (1 - t) / L;
1992
1997
  if (a <= 1e-6) return { cx: 0.5, cy: 0.5 };
1993
1998
  const fx = (cX * layout.W - layout.W / 2 * (1 - t) / L) / a;
@@ -4655,13 +4660,13 @@ function zoomTrackFromDoc(zoom, segments, style = ZOOM_STYLES[DEFAULT_ZOOM_STYLE
4655
4660
  let chained = false;
4656
4661
  for (let i = 0; i < mapped.length; i++) {
4657
4662
  const { z, tIn, tOut } = mapped[i];
4658
- const entry = [clampZoomLevel(z.level), z.cx, z.cy];
4663
+ const entry = [clampZoomLevel(z.level), z.cx, z.cy, 1];
4659
4664
  let cur = entry;
4660
4665
  const m = transitionMult(z.transition);
4661
4666
  if (!chained) {
4662
4667
  const start = push2(
4663
4668
  tIn - (style.rampIn - style.rampInOverlap) * m,
4664
- [1, z.cx, z.cy],
4669
+ [1, z.cx, z.cy, 0],
4665
4670
  "none"
4666
4671
  );
4667
4672
  push2(start + style.rampIn * m, entry, spanEase(z.ease, style.ease));
@@ -4669,7 +4674,7 @@ function zoomTrackFromDoc(zoom, segments, style = ZOOM_STYLES[DEFAULT_ZOOM_STYLE
4669
4674
  for (const e of z.followEvents ?? []) {
4670
4675
  const eOut = sourceToTimeline(segments, e.t);
4671
4676
  if (eOut === null || eOut <= tIn || eOut >= tOut) continue;
4672
- const next2 = [cur[0], e.cx, e.cy];
4677
+ const next2 = [cur[0], e.cx, e.cy, 1];
4673
4678
  push2(eOut, cur, "none");
4674
4679
  push2(Math.min(eOut + style.followRecenter, tOut), next2, panEase);
4675
4680
  cur = next2;
@@ -4678,7 +4683,7 @@ function zoomTrackFromDoc(zoom, segments, style = ZOOM_STYLES[DEFAULT_ZOOM_STYLE
4678
4683
  const next = mapped.at(i + 1);
4679
4684
  if (next && next.tIn - tOut <= style.chainGap) {
4680
4685
  const mNext = transitionMult(next.z.transition);
4681
- 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];
4682
4687
  push2(
4683
4688
  Math.min(
4684
4689
  tOut + style.pan * mNext,
@@ -4691,7 +4696,7 @@ function zoomTrackFromDoc(zoom, segments, style = ZOOM_STYLES[DEFAULT_ZOOM_STYLE
4691
4696
  } else {
4692
4697
  push2(
4693
4698
  tOut + style.rampOut * m,
4694
- [1, cur[1], cur[2]],
4699
+ [1, cur[1], cur[2], 0],
4695
4700
  spanEase(z.ease, style.ease)
4696
4701
  );
4697
4702
  chained = false;
@@ -5873,11 +5878,15 @@ var ON_FRAME = `(ctx, content, dt) => {
5873
5878
  // current zoom \u2014 a standard keyframe track in OUTPUT time (hold + arrival pairs
5874
5879
  // expanded by the lowering), sampled with the shared deterministic interpolator.
5875
5880
  // Sampled here, before the rect math, so a cover crop can follow it.
5876
- var lvl = 1, zx = 0.5, zy = 0.5
5881
+ var lvl = 1, zx = 0.5, zy = 0.5, zc = -1
5877
5882
  var zt = d.zoomTrack
5878
5883
  if (zt && zt.keyframes && zt.keyframes.length) {
5879
5884
  var z = TL.sample(zt, tpT, TL.lerpArray)
5880
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]
5881
5890
  }
5882
5891
  var barH = bar.kind && bar.kind !== 'none' ? (bar.height || 44) * s2 : 0
5883
5892
  var availW = Math.max(1, W - ipL - ipR), availH = Math.max(1, H - ipT - ipB - barH)
@@ -5940,8 +5949,11 @@ var ON_FRAME = `(ctx, content, dt) => {
5940
5949
  var wcx = fx, wcy = fy
5941
5950
  if (lvl > 1.001 && !d.zoomSuppressed) {
5942
5951
  if (camStage) {
5943
- var ctu = Math.max(0, Math.min(1, (lvl - 1) / ${CAMERA_CENTRE_RAMP}))
5944
- var ctt = ctu * ctu * (3 - 2 * ctu)
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
+ }
5945
5957
  wcx = fx + ((W / 2 - fx) / lvl) * (1 - ctt)
5946
5958
  wcy = fy + ((H / 2 - fy) / lvl) * (1 - ctt)
5947
5959
  c.translate(W / 2, H / 2); c.scale(lvl, lvl); c.translate(-wcx, -wcy)