@vosjs/studio-core 0.45.0 → 0.45.2

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
@@ -1868,6 +1868,12 @@ interface HtmlOverlayClip extends OverlayClipBase {
1868
1868
  * timeline's clock in the preview and in every export chunk alike. One
1869
1869
  * rasterize per frame while on screen. Absent = a still, byte-identical
1870
1870
  * to before the field existed.
1871
+ *
1872
+ * Move the LAYER with `motion` poses, never its text with CSS: the
1873
+ * browser places text on whole device pixels each time it rasterizes, so
1874
+ * text a keyframe drifts or scales slowly steps a pixel at a time beside
1875
+ * shapes that glide. A layer with a motion track is drawn from one raster
1876
+ * of each picture and moves by resampling it, which glides.
1871
1877
  */
1872
1878
  live?: boolean;
1873
1879
  /** Values for a live layer's `{{data.<name>}}` placeholders. */
package/dist/index.js CHANGED
@@ -1515,6 +1515,8 @@ var DESIGN_FRAME_WIDTH = 1920;
1515
1515
  var HTML_LAYER_WARN_BYTES = 32e3;
1516
1516
  var HTML_LAYER_MAX_BYTES = 128e3;
1517
1517
  var HTML_LAYER_LIVE_HZ = 60;
1518
+ var HTML_LAYER_RASTER_SCALE = 2;
1519
+ var HTML_LAYER_RASTER_MAX_AREA = 4096 * 4096;
1518
1520
  var HTML_LAYER_ASSET_HOST = "https://assets.vos.so/";
1519
1521
  function splitTopLevel(value) {
1520
1522
  const out = [];
@@ -5834,6 +5836,35 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
5834
5836
  else { cc.beginPath(); cc.rect(x, y, w, h) }
5835
5837
  }
5836
5838
 
5839
+ // A moving html layer's raster: its picture drawn ONCE at the largest size
5840
+ // its track reaches (so a pose only ever scales it down), into one canvas
5841
+ // per clip, redrawn only when a new picture lands or the frame's size
5842
+ // changes. A still layer in motion rasterizes once; a live one once per
5843
+ // picture, as before.
5844
+ function hlRaster(ol, el, nw, nh) {
5845
+ if (typeof document === 'undefined') return el
5846
+ var hlPk = ol.scale
5847
+ var hlKs = ol.track.keyframes
5848
+ for (var hlKi = 0; hlKi < hlKs.length; hlKi++) if (hlKs[hlKi].value[2] > hlPk) hlPk = hlKs[hlKi].value[2]
5849
+ var hlBW = ol.w * W * hlPk
5850
+ var hlBH = hlBW * nh / nw
5851
+ var hlSS = Math.min(${HTML_LAYER_RASTER_SCALE}, Math.sqrt(${HTML_LAYER_RASTER_MAX_AREA} / Math.max(1, hlBW * hlBH)))
5852
+ var hlRW = Math.max(1, Math.floor(hlBW * hlSS))
5853
+ var hlRH = Math.max(1, Math.floor(hlBH * hlSS))
5854
+ var hlRs = ns.htmlRaster || (ns.htmlRaster = {})
5855
+ var hlR = hlRs[ol.id]
5856
+ if (!hlR) hlR = hlRs[ol.id] = { c: document.createElement('canvas'), el: null }
5857
+ if (hlR.el !== el || hlR.c.width !== hlRW || hlR.c.height !== hlRH) {
5858
+ if (hlR.c.width !== hlRW) hlR.c.width = hlRW
5859
+ if (hlR.c.height !== hlRH) hlR.c.height = hlRH
5860
+ var hlX = hlR.c.getContext('2d')
5861
+ hlX.clearRect(0, 0, hlRW, hlRH)
5862
+ try { hlX.drawImage(el, 0, 0, hlRW, hlRH) } catch (e) { return el }
5863
+ hlR.el = el
5864
+ }
5865
+ return hlR.c
5866
+ }
5867
+
5837
5868
  // Text overlays: visibility signature + "a transition is animating".
5838
5869
  // During a hold the drawn pixels are static, so the signature alone drives
5839
5870
  // redraws (position/text/style edits change it \u2014 live SET_DATA); during
@@ -5894,6 +5925,7 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
5894
5925
  if (ns.htmlKeys) delete ns.htmlKeys[hlK]
5895
5926
  if (ns.htmlWant) delete ns.htmlWant[hlK]
5896
5927
  if (ns.htmlErrors) delete ns.htmlErrors[hlK]
5928
+ if (ns.htmlRaster) delete ns.htmlRaster[hlK]
5897
5929
  }
5898
5930
  }
5899
5931
  // A styled layer's cached layout leaves with its clip.
@@ -6110,7 +6142,15 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
6110
6142
  }
6111
6143
  ovC.save()
6112
6144
  rr(-olDW / 2, -olDH / 2, olDW, olDH, olRad, ovC); ovC.clip()
6113
- try { ovC.drawImage(olEl, -olDW / 2, -olDH / 2, olDW, olDH) } catch (e) {}
6145
+ // A MOVING html layer is drawn from a raster of its picture, never from
6146
+ // the picture itself: the browser rasterizes an SVG image afresh at
6147
+ // every draw transform and places text on whole device pixels as it
6148
+ // does, so text under a slow move or scale held still and then jumped
6149
+ // a pixel while the shapes beside it glided. A fixed raster moves by
6150
+ // resampling, every frame.
6151
+ var olSrc = ol.html && ol.track ? hlRaster(ol, olEl, olNW, olNH) : olEl
6152
+ if (olSrc !== olEl) ovC.imageSmoothingQuality = 'high'
6153
+ try { ovC.drawImage(olSrc, -olDW / 2, -olDH / 2, olDW, olDH) } catch (e) {}
6114
6154
  ovC.restore()
6115
6155
  if (ol.border && ol.border.width > 0) {
6116
6156
  ovC.strokeStyle = ol.border.color || '#ffffff'
@@ -6231,8 +6271,20 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
6231
6271
  var rbPY = ol.box.py * olMS * s
6232
6272
  var rbW = rtL.width + rbPX * 2
6233
6273
  var rbH = rtN * rtLH + rbPY * 2
6274
+ // A per-unit entrance leaves the clip at full strength while its
6275
+ // units arrive one by one, so the box follows the EARLIEST unit (the
6276
+ // units' own delay, seconds and ease) or it stands empty until the
6277
+ // first word shows. A typewriter's field is there from its first frame.
6278
+ var rbA = 1
6279
+ if (rtFx && rtFx.k !== 'typewriter') {
6280
+ var rbN = 0
6281
+ for (var rbi = 0; rbi < rtN; rbi++) rbN += rtL.lines[rbi].units.length
6282
+ var rbO = rtFx.d === 2 && rbN % 2 === 0 ? 0.5 : 0
6283
+ var rbU = Math.max(0, Math.min(1, (olT - rbO * rtFx.st) / rtFx.dur))
6284
+ rbA = rtFx.k === 'pop' ? Math.min(1, rbU * 2) : 1 - Math.pow(1 - rbU, 3)
6285
+ }
6234
6286
  ovC.save()
6235
- ovC.globalAlpha = olA * ol.box.o
6287
+ ovC.globalAlpha = olA * ol.box.o * rbA
6236
6288
  ovC.fillStyle = ol.box.c
6237
6289
  rr(-rbW / 2, -rbH / 2, rbW, rbH, Math.min(ol.box.r * olMS * s, rbH / 2), ovC)
6238
6290
  ovC.fill()
@@ -9047,8 +9099,18 @@ var ON_FRAME = `(ctx, content, dt) => {
9047
9099
  var tqAx = (tqA[0] - W / 2) * trGsc + W / 2 + trGox * W, tqAy = (tqA[1] - H / 2) * trGsc + H / 2 - trGoy * H
9048
9100
  var tqBx = (tqB[0] - W / 2) * trSc + W / 2 + trOx * W, tqBy = (tqB[1] - H / 2) * trSc + H / 2 - trOy * H
9049
9101
  var tqX2 = tqAx + (tqBx - tqAx) * tqP, tqY2 = tqAy + (tqBy - tqAy) * tqP
9102
+ // A slide pulls the two cards a frame apart, so the lerp would cross
9103
+ // the bare ground between them: the dot rides the card that holds
9104
+ // more of the frame instead, moved with it, and only a card's own
9105
+ // point is ever drawn on that card.
9106
+ var tqOn = true
9107
+ if (trOut.kind === 'slide' || (trIn && trIn.kind === 'slide')) {
9108
+ var tqOut = Math.abs(trGox) + Math.abs(trGoy) <= Math.abs(trOx) + Math.abs(trOy)
9109
+ tqOn = tqOut ? !!trQa : !!trQb
9110
+ tqX2 = tqOut ? tqAx : tqBx; tqY2 = tqOut ? tqAy : tqBy
9111
+ }
9050
9112
  var tqR = trQs || (((d.cursorStyle && d.cursorStyle.size) || 24) * s * 0.5)
9051
- drawCur(ovC, tqX2, tqY2, tqR, 1, 2 * (trQw || s))
9113
+ if (tqOn) drawCur(ovC, tqX2, tqY2, tqR, 1, 2 * (trQw || s))
9052
9114
  }
9053
9115
  ov.sig = ovSig
9054
9116
  ov.active = camActiveNow || !!trOut || pqLive