@vosjs/studio-core 0.38.0 → 0.39.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 +13 -5
- package/dist/index.js +163 -388
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2740,63 +2740,30 @@ function styledTextOf(clip) {
|
|
|
2740
2740
|
h: hashOf(JSON.stringify([l, fs]))
|
|
2741
2741
|
};
|
|
2742
2742
|
}
|
|
2743
|
-
function
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
}
|
|
2754
|
-
let current = "";
|
|
2755
|
-
for (const token of overlayTokens(line)) {
|
|
2756
|
-
if (!current) {
|
|
2757
|
-
current = token;
|
|
2758
|
-
continue;
|
|
2759
|
-
}
|
|
2760
|
-
if (measure(current + token) <= maxPx) {
|
|
2761
|
-
current += token;
|
|
2762
|
-
} else {
|
|
2763
|
-
out.push(current);
|
|
2764
|
-
current = token;
|
|
2743
|
+
function textRunsOf(clip) {
|
|
2744
|
+
const styled = styledTextOf(clip);
|
|
2745
|
+
if (styled) return styled;
|
|
2746
|
+
const style = resolveOverlayStyle(clip);
|
|
2747
|
+
return {
|
|
2748
|
+
l: overlayLines(overlayPlainText(clip)).map((t) => t ? [{ t }] : []),
|
|
2749
|
+
fs: [
|
|
2750
|
+
{
|
|
2751
|
+
w: style.weight,
|
|
2752
|
+
...style.fontStyle === "italic" ? { i: 1 } : {}
|
|
2765
2753
|
}
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
}
|
|
2769
|
-
return out.length ? out : [""];
|
|
2770
|
-
}
|
|
2771
|
-
function graphemesOf2(line) {
|
|
2772
|
-
if (typeof Intl !== "undefined" && typeof Intl.Segmenter === "function") {
|
|
2773
|
-
return [
|
|
2774
|
-
...new Intl.Segmenter(void 0, { granularity: "grapheme" }).segment(
|
|
2775
|
-
line
|
|
2776
|
-
)
|
|
2777
|
-
].map((s) => s.segment);
|
|
2778
|
-
}
|
|
2779
|
-
return [...line];
|
|
2780
|
-
}
|
|
2781
|
-
function overlaySegments(text, unit) {
|
|
2782
|
-
const lines = overlayLines(text);
|
|
2783
|
-
if (unit === "block") return [];
|
|
2784
|
-
if (unit === "line") return lines.map((l) => [l]);
|
|
2785
|
-
if (unit === "word") return lines.map(overlayTokens);
|
|
2786
|
-
return lines.map(graphemesOf2);
|
|
2754
|
+
]
|
|
2755
|
+
};
|
|
2787
2756
|
}
|
|
2788
2757
|
var FX_DIR = { forward: 0, reverse: 1, center: 2 };
|
|
2789
2758
|
function resolveOverlayFx(clip, clipDuration) {
|
|
2790
2759
|
const spec = overlayFxSpec(clip) ?? clip.fx ?? null;
|
|
2791
2760
|
if (!spec) return null;
|
|
2792
2761
|
const unit = spec.unit ?? "block";
|
|
2793
|
-
const
|
|
2794
|
-
const
|
|
2795
|
-
const
|
|
2796
|
-
const
|
|
2797
|
-
|
|
2798
|
-
0
|
|
2799
|
-
) : n;
|
|
2762
|
+
const lines = overlayLines(overlayPlainText(clip));
|
|
2763
|
+
const count = (per) => lines.reduce((sum, line) => sum + per(line), 0);
|
|
2764
|
+
const words = () => count((line) => tokenRanges(line).length);
|
|
2765
|
+
const n = unit === "block" ? 1 : unit === "line" ? lines.length : unit === "word" ? words() : count((line) => graphemesOf(line).length);
|
|
2766
|
+
const upperN = unit === "line" && clip.maxWidth ? words() : n;
|
|
2800
2767
|
const typewriter = spec.fx === "typewriter";
|
|
2801
2768
|
const dur = typewriter ? 1e-3 : Math.min(2, Math.max(0.05, spec.duration ?? OVERLAY_TRANSITION_DUR));
|
|
2802
2769
|
const defaultStagger = typewriter ? 0.05 : unit === "block" ? 0 : 0.06;
|
|
@@ -2812,9 +2779,7 @@ function resolveOverlayFx(clip, clipDuration) {
|
|
|
2812
2779
|
d: FX_DIR[spec.direction ?? "forward"] ?? 0,
|
|
2813
2780
|
st: round14(st),
|
|
2814
2781
|
dur: round14(dur),
|
|
2815
|
-
tt: round14(st * (upperN - 1) + dur)
|
|
2816
|
-
units,
|
|
2817
|
-
n
|
|
2782
|
+
tt: round14(st * (upperN - 1) + dur)
|
|
2818
2783
|
};
|
|
2819
2784
|
}
|
|
2820
2785
|
function overlayFontString(style, scale, s) {
|
|
@@ -2838,35 +2803,21 @@ function overlayRect(clip, measure, frameW, frameH = 1080, mediaAspect) {
|
|
|
2838
2803
|
return { ...base, w: w2, h: w2 / (mediaAspect || 16 / 9) };
|
|
2839
2804
|
}
|
|
2840
2805
|
const style = resolveOverlayStyle(clip);
|
|
2841
|
-
const font = overlayFontString(style, scale, 1);
|
|
2842
2806
|
const ls = style.letterSpacing * scale;
|
|
2843
|
-
const
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
)
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
);
|
|
2858
|
-
w = laid.width;
|
|
2859
|
-
lineCount = laid.lines.length;
|
|
2860
|
-
} else {
|
|
2861
|
-
const width = (t) => measure(t, font, ls);
|
|
2862
|
-
const lines = clip.maxWidth ? wrapOverlayLines(
|
|
2863
|
-
overlayLines(overlayPlainText(clip)),
|
|
2864
|
-
width,
|
|
2865
|
-
clip.maxWidth * frameW
|
|
2866
|
-
) : overlayLines(overlayPlainText(clip));
|
|
2867
|
-
for (const line of lines) w = Math.max(w, width(line));
|
|
2868
|
-
lineCount = lines.length;
|
|
2869
|
-
}
|
|
2807
|
+
const runs = textRunsOf(clip);
|
|
2808
|
+
const fonts = runs.fs.map(
|
|
2809
|
+
(f) => overlayFontString(
|
|
2810
|
+
{ ...style, weight: f.w, fontStyle: f.i ? "italic" : "normal" },
|
|
2811
|
+
scale,
|
|
2812
|
+
1
|
|
2813
|
+
)
|
|
2814
|
+
);
|
|
2815
|
+
const laid = layoutText(
|
|
2816
|
+
{ lines: runs.l, maxWidth: clip.maxWidth ? clip.maxWidth * frameW : 0 },
|
|
2817
|
+
(t, f) => measure(t, fonts[f], ls)
|
|
2818
|
+
);
|
|
2819
|
+
const w = laid.width;
|
|
2820
|
+
const lineCount = laid.lines.length;
|
|
2870
2821
|
const lineH = style.size * scale * style.lineHeight;
|
|
2871
2822
|
const box = resolveOverlayBox(clip);
|
|
2872
2823
|
const padX = box ? box.padX * scale : 0;
|
|
@@ -5592,334 +5543,155 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
|
|
|
5592
5543
|
ovC.textAlign = 'center'
|
|
5593
5544
|
ovC.textBaseline = 'middle'
|
|
5594
5545
|
ovC.letterSpacing = ((ol.ls || 0) * olMS * s) + 'px'
|
|
5595
|
-
//
|
|
5596
|
-
//
|
|
5597
|
-
//
|
|
5598
|
-
//
|
|
5599
|
-
//
|
|
5600
|
-
//
|
|
5546
|
+
// Every text layer is laid out by the layout module, ONCE: a styled one
|
|
5547
|
+
// from its runs (ol.rt: lines of runs, each set its own way), a plain
|
|
5548
|
+
// one from its lines, each a single run in the layer's own style. The
|
|
5549
|
+
// layout is kept per clip under a key of everything it was measured
|
|
5550
|
+
// with, so a frame that only moves, fades or reveals the layer measures
|
|
5551
|
+
// nothing. Fragments draw left to right from each line's left edge; a
|
|
5552
|
+
// per-unit entrance animates the layout's units, each a few parts of
|
|
5553
|
+
// fragments.
|
|
5554
|
+
var rtFonts = [ovC.font]
|
|
5601
5555
|
if (ol.rt) {
|
|
5602
|
-
var rtFonts = [ovC.font]
|
|
5603
5556
|
for (var rfi = 1; rfi < ol.rt.fs.length; rfi++) {
|
|
5604
5557
|
rtFonts.push((ol.rt.fs[rfi].i ? 'italic ' : '') + ol.rt.fs[rfi].w + ' ' + olPx + 'px ' + ol.stack)
|
|
5605
5558
|
}
|
|
5606
|
-
var rtFx = ol.fx && ol.fx.units.length ? ol.fx : null
|
|
5607
|
-
var rtMax = ol.mw ? ol.mw * W : 0
|
|
5608
|
-
var rtKey = ol.rt.h + '|' + rtFonts[0] + '|' + ((ol.ls || 0) * olMS * s) + '|' + rtMax + '|' + (rtFx ? rtFx.u : '') + '|' + (ns.fontEpoch || 0)
|
|
5609
|
-
var rtAll = ns.textLayouts || (ns.textLayouts = {})
|
|
5610
|
-
var rtHit = rtAll[ol.id]
|
|
5611
|
-
if (!rtHit || rtHit.k !== rtKey) {
|
|
5612
|
-
rtHit = rtAll[ol.id] = {
|
|
5613
|
-
k: rtKey,
|
|
5614
|
-
L: TXL.layoutText(
|
|
5615
|
-
{ lines: ol.rt.l, maxWidth: rtMax, unit: rtFx ? rtFx.u : undefined },
|
|
5616
|
-
function (mt, mf) { ovC.font = rtFonts[mf]; return ovC.measureText(mt).width }
|
|
5617
|
-
)
|
|
5618
|
-
}
|
|
5619
|
-
ovC.font = rtFonts[0]
|
|
5620
|
-
}
|
|
5621
|
-
var rtL = rtHit.L
|
|
5622
|
-
var rtN = rtL.lines.length
|
|
5623
|
-
var rtLH = olPx * (ol.lh || ${OVERLAY_LINE_HEIGHT})
|
|
5624
|
-
var rtY0 = -((rtN - 1) * rtLH) / 2
|
|
5625
|
-
// A line's left edge: lines sit centred on the anchor and align
|
|
5626
|
-
// against the widest, as the plain layer's do.
|
|
5627
|
-
var rtLeft = function (lw) {
|
|
5628
|
-
var xo = ol.align === 'left' ? (lw - rtL.width) / 2 : ol.align === 'right' ? (rtL.width - lw) / 2 : 0
|
|
5629
|
-
return xo - lw / 2
|
|
5630
|
-
}
|
|
5631
|
-
if (ol.box) {
|
|
5632
|
-
var rbPX = ol.box.px * olMS * s
|
|
5633
|
-
var rbPY = ol.box.py * olMS * s
|
|
5634
|
-
var rbW = rtL.width + rbPX * 2
|
|
5635
|
-
var rbH = rtN * rtLH + rbPY * 2
|
|
5636
|
-
ovC.save()
|
|
5637
|
-
ovC.globalAlpha = olA * ol.box.o
|
|
5638
|
-
ovC.fillStyle = ol.box.c
|
|
5639
|
-
rr(-rbW / 2, -rbH / 2, rbW, rbH, Math.min(ol.box.r * olMS * s, rbH / 2), ovC)
|
|
5640
|
-
ovC.fill()
|
|
5641
|
-
ovC.restore()
|
|
5642
|
-
}
|
|
5643
|
-
// Highlights sit behind the words and take no legibility shadow. Under
|
|
5644
|
-
// a per-unit entrance each is drawn with its unit instead (below), so
|
|
5645
|
-
// it arrives with its word.
|
|
5646
|
-
for (var rhi = 0; !rtFx && rhi < rtN; rhi++) {
|
|
5647
|
-
var rhLine = rtL.lines[rhi]
|
|
5648
|
-
for (var rhj = 0; rhj < rhLine.frags.length; rhj++) {
|
|
5649
|
-
var rhF = rhLine.frags[rhj]
|
|
5650
|
-
if (!rhF.h) continue
|
|
5651
|
-
var rhR = TXL.decorationRect('h', rtLeft(rhLine.w) + rhF.x, rhF.w, rtY0 + rhi * rtLH, olPx)
|
|
5652
|
-
ovC.fillStyle = rhF.h
|
|
5653
|
-
ovC.fillRect(rhR.x, rhR.y, rhR.w, rhR.h)
|
|
5654
|
-
}
|
|
5655
|
-
}
|
|
5656
|
-
if (ol.shadow > 0) {
|
|
5657
|
-
ovC.shadowColor = 'rgba(0,0,0,' + ol.shadow + ')'
|
|
5658
|
-
ovC.shadowBlur = olPx * 0.25
|
|
5659
|
-
ovC.shadowOffsetY = olPx * 0.04
|
|
5660
|
-
}
|
|
5661
|
-
ovC.textAlign = 'left'
|
|
5662
|
-
// One fragment (or the part of one a unit holds): the underline under
|
|
5663
|
-
// the glyphs, stroke under fill, the strikethrough over them.
|
|
5664
|
-
var rtPart = function (p, bx, y, withH) {
|
|
5665
|
-
if (withH && p.h) {
|
|
5666
|
-
var rhU = TXL.decorationRect('h', bx + p.x, p.w, y, olPx)
|
|
5667
|
-
var rhS = ovC.shadowColor
|
|
5668
|
-
ovC.shadowColor = 'rgba(0,0,0,0)'
|
|
5669
|
-
ovC.fillStyle = p.h
|
|
5670
|
-
ovC.fillRect(rhU.x, rhU.y, rhU.w, rhU.h)
|
|
5671
|
-
ovC.shadowColor = rhS
|
|
5672
|
-
}
|
|
5673
|
-
ovC.font = rtFonts[p.f || 0]
|
|
5674
|
-
ovC.fillStyle = p.c || ol.color
|
|
5675
|
-
if (p.u) {
|
|
5676
|
-
var ru = TXL.decorationRect('u', bx + p.x, p.w, y, olPx)
|
|
5677
|
-
ovC.fillRect(ru.x, ru.y, ru.w, ru.h)
|
|
5678
|
-
}
|
|
5679
|
-
if (ol.stroke) {
|
|
5680
|
-
ovC.strokeStyle = ol.stroke.c
|
|
5681
|
-
ovC.lineWidth = ol.stroke.w * olMS * s
|
|
5682
|
-
ovC.lineJoin = 'round'
|
|
5683
|
-
ovC.strokeText(p.t, bx + p.x, y)
|
|
5684
|
-
}
|
|
5685
|
-
ovC.fillText(p.t, bx + p.x, y)
|
|
5686
|
-
if (p.s) {
|
|
5687
|
-
var rs = TXL.decorationRect('s', bx + p.x, p.w, y, olPx)
|
|
5688
|
-
ovC.fillRect(rs.x, rs.y, rs.w, rs.h)
|
|
5689
|
-
}
|
|
5690
|
-
}
|
|
5691
|
-
if (!rtFx) {
|
|
5692
|
-
for (var rli = 0; rli < rtN; rli++) {
|
|
5693
|
-
var rLine = rtL.lines[rli]
|
|
5694
|
-
var rBX = rtLeft(rLine.w)
|
|
5695
|
-
for (var rfk = 0; rfk < rLine.frags.length; rfk++) rtPart(rLine.frags[rfk], rBX, rtY0 + rli * rtLH)
|
|
5696
|
-
}
|
|
5697
|
-
} else {
|
|
5698
|
-
// Per-unit entrance, the plain layer's own arithmetic over the
|
|
5699
|
-
// layout's units: delay = order(index) x st, eased over dur.
|
|
5700
|
-
var rtCount = 0
|
|
5701
|
-
for (var rci = 0; rci < rtN; rci++) rtCount += rtL.lines[rci].units.length
|
|
5702
|
-
var rtIdx = 0
|
|
5703
|
-
for (var rui = 0; rui < rtN; rui++) {
|
|
5704
|
-
var rULine = rtL.lines[rui]
|
|
5705
|
-
var rUBX = rtLeft(rULine.w)
|
|
5706
|
-
var rUY = rtY0 + rui * rtLH
|
|
5707
|
-
for (var ruj = 0; ruj < rULine.units.length; ruj++, rtIdx++) {
|
|
5708
|
-
var rU = rULine.units[ruj]
|
|
5709
|
-
var rOrd = rtFx.d === 1 ? (rtCount - 1 - rtIdx) : rtFx.d === 2 ? Math.abs(rtIdx - (rtCount - 1) / 2) : rtIdx
|
|
5710
|
-
var rT2 = olT - rOrd * rtFx.st
|
|
5711
|
-
var rUA = 1, rUu = 1
|
|
5712
|
-
if (rtFx.k === 'typewriter') {
|
|
5713
|
-
rUA = rT2 >= 0 ? 1 : 0
|
|
5714
|
-
} else {
|
|
5715
|
-
rUu = Math.max(0, Math.min(1, rT2 / rtFx.dur))
|
|
5716
|
-
var rUE = 1 - Math.pow(1 - rUu, 3)
|
|
5717
|
-
rUA = rtFx.k === 'pop' ? Math.min(1, rUu * 2) : rUE
|
|
5718
|
-
}
|
|
5719
|
-
if (rUA <= 0.004) continue
|
|
5720
|
-
ovC.save()
|
|
5721
|
-
ovC.globalAlpha = olA * rUA
|
|
5722
|
-
if (rUu < 1) {
|
|
5723
|
-
if (rtFx.k === 'rise') {
|
|
5724
|
-
ovC.translate(0, (1 - (1 - Math.pow(1 - rUu, 3))) * 24 * s)
|
|
5725
|
-
} else if (rtFx.k === 'pop') {
|
|
5726
|
-
var rPS = 1 + 2.70158 * Math.pow(rUu - 1, 3) + 1.70158 * Math.pow(rUu - 1, 2)
|
|
5727
|
-
var rCX = rUBX + rU.x + rU.w / 2
|
|
5728
|
-
ovC.translate(rCX, rUY)
|
|
5729
|
-
ovC.scale(rPS, rPS)
|
|
5730
|
-
ovC.translate(-rCX, -rUY)
|
|
5731
|
-
} else if (rtFx.k === 'blur') {
|
|
5732
|
-
ovC.filter = 'blur(' + ((1 - rUu) * olPx * 0.12).toFixed(2) + 'px)'
|
|
5733
|
-
}
|
|
5734
|
-
}
|
|
5735
|
-
for (var rpk = 0; rpk < rU.parts.length; rpk++) rtPart(rU.parts[rpk], rUBX, rUY, true)
|
|
5736
|
-
ovC.restore()
|
|
5737
|
-
}
|
|
5738
|
-
}
|
|
5739
|
-
}
|
|
5740
|
-
ovC.restore()
|
|
5741
|
-
continue
|
|
5742
5559
|
}
|
|
5743
|
-
var
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
for (var olti = 0; olti < olToks.length; olti++) {
|
|
5761
|
-
if (!olCur) { olCur = olToks[olti]; continue }
|
|
5762
|
-
if (ovC.measureText(olCur + olToks[olti]).width <= olWMax) {
|
|
5763
|
-
olCur += olToks[olti]
|
|
5764
|
-
} else {
|
|
5765
|
-
olWrapped.push(olCur)
|
|
5766
|
-
olCur = olToks[olti]
|
|
5767
|
-
}
|
|
5768
|
-
}
|
|
5769
|
-
if (olCur) olWrapped.push(olCur)
|
|
5770
|
-
}
|
|
5771
|
-
olLines = olWrapped.length ? olWrapped : ['']
|
|
5772
|
-
}
|
|
5773
|
-
var olLH = olPx * (ol.lh || ${OVERLAY_LINE_HEIGHT})
|
|
5774
|
-
var olY0 = -((olLines.length - 1) * olLH) / 2
|
|
5775
|
-
// Per-line widths: needed by the pill, by left/right alignment (lines
|
|
5776
|
-
// draw centered; alignment is an x offset against the widest line), and
|
|
5777
|
-
// by per-unit fx (units place by prefix advance from the line's left edge).
|
|
5778
|
-
var olFx = ol.fx && ol.fx.units.length ? ol.fx : null
|
|
5779
|
-
// With wrap active, baked per-line unit arrays regroup onto the WRAPPED
|
|
5780
|
-
// lines. Wrapping never reorders: word/char units consume in flat order
|
|
5781
|
-
// by string length (wrapped lines are token concatenations); 'line'
|
|
5782
|
-
// units become one per wrapped line. Flat delay order is unchanged.
|
|
5783
|
-
if (olFx && ol.mw) {
|
|
5784
|
-
var olFlat = []
|
|
5785
|
-
for (var olfi = 0; olfi < olFx.units.length; olfi++) {
|
|
5786
|
-
for (var olfj = 0; olfj < olFx.units[olfi].length; olfj++) {
|
|
5787
|
-
olFlat.push(olFx.units[olfi][olfj])
|
|
5788
|
-
}
|
|
5789
|
-
}
|
|
5790
|
-
var olRe = []
|
|
5791
|
-
if (olFx.u === 'line') {
|
|
5792
|
-
for (var olri = 0; olri < olLines.length; olri++) olRe.push([olLines[olri]])
|
|
5793
|
-
} else {
|
|
5794
|
-
var olFk = 0
|
|
5795
|
-
for (var olri2 = 0; olri2 < olLines.length; olri2++) {
|
|
5796
|
-
var olNeed = olLines[olri2].length
|
|
5797
|
-
var olArr = []
|
|
5798
|
-
var olGot = 0
|
|
5799
|
-
while (olFk < olFlat.length && olGot < olNeed) {
|
|
5800
|
-
olArr.push(olFlat[olFk])
|
|
5801
|
-
olGot += olFlat[olFk].length
|
|
5802
|
-
olFk++
|
|
5803
|
-
}
|
|
5804
|
-
olRe.push(olArr)
|
|
5805
|
-
}
|
|
5806
|
-
}
|
|
5807
|
-
var olReN = 0
|
|
5808
|
-
for (var olrn = 0; olrn < olRe.length; olrn++) olReN += olRe[olrn].length
|
|
5809
|
-
olFx = { k: olFx.k, u: olFx.u, d: olFx.d, st: olFx.st, dur: olFx.dur, tt: olFx.tt, units: olRe, n: olReN }
|
|
5810
|
-
}
|
|
5811
|
-
var olLWs = null, olMaxW = 0
|
|
5812
|
-
if (ol.box || ol.align || olFx) {
|
|
5813
|
-
olLWs = []
|
|
5814
|
-
for (var olwi = 0; olwi < olLines.length; olwi++) {
|
|
5815
|
-
var olw = ovC.measureText(olLines[olwi]).width
|
|
5816
|
-
olLWs.push(olw)
|
|
5817
|
-
if (olw > olMaxW) olMaxW = olw
|
|
5560
|
+
var rtFx = ol.fx && ol.fx.u !== 'block' ? ol.fx : null
|
|
5561
|
+
var rtMax = ol.mw ? ol.mw * W : 0
|
|
5562
|
+
var rtKey = (ol.rt ? 'r' + ol.rt.h : 'p' + (ol.lines || ['']).join('\\n')) + '|' + rtFonts[0] + '|' + ((ol.ls || 0) * olMS * s) + '|' + rtMax + '|' + (rtFx ? rtFx.u : '') + '|' + (ns.fontEpoch || 0)
|
|
5563
|
+
var rtAll = ns.textLayouts || (ns.textLayouts = {})
|
|
5564
|
+
var rtHit = rtAll[ol.id]
|
|
5565
|
+
if (!rtHit || rtHit.k !== rtKey) {
|
|
5566
|
+
var rtIn = ol.rt ? ol.rt.l : []
|
|
5567
|
+
if (!ol.rt) {
|
|
5568
|
+
var rtPl = ol.lines || ['']
|
|
5569
|
+
for (var rpi = 0; rpi < rtPl.length; rpi++) rtIn.push(rtPl[rpi] ? [{ t: rtPl[rpi] }] : [])
|
|
5570
|
+
}
|
|
5571
|
+
rtHit = rtAll[ol.id] = {
|
|
5572
|
+
k: rtKey,
|
|
5573
|
+
L: TXL.layoutText(
|
|
5574
|
+
{ lines: rtIn, maxWidth: rtMax, unit: rtFx ? rtFx.u : undefined },
|
|
5575
|
+
function (mt, mf) { ovC.font = rtFonts[mf]; return ovC.measureText(mt).width }
|
|
5576
|
+
)
|
|
5818
5577
|
}
|
|
5578
|
+
ovC.font = rtFonts[0]
|
|
5579
|
+
}
|
|
5580
|
+
var rtL = rtHit.L
|
|
5581
|
+
var rtN = rtL.lines.length
|
|
5582
|
+
var rtLH = olPx * (ol.lh || ${OVERLAY_LINE_HEIGHT})
|
|
5583
|
+
var rtY0 = -((rtN - 1) * rtLH) / 2
|
|
5584
|
+
// A line's left edge: lines sit centred on the anchor and align
|
|
5585
|
+
// against the widest.
|
|
5586
|
+
var rtLeft = function (lw) {
|
|
5587
|
+
var xo = ol.align === 'left' ? (lw - rtL.width) / 2 : ol.align === 'right' ? (rtL.width - lw) / 2 : 0
|
|
5588
|
+
return xo - lw / 2
|
|
5819
5589
|
}
|
|
5820
|
-
// Background pill (ol.box, baked design px at fs): drawn BEFORE the text
|
|
5821
|
-
// and before the legibility shadow config, so the pill never inherits the
|
|
5822
|
-
// text shadow. Geometry mirrors overlayRect's inflation \u2014 change together.
|
|
5823
5590
|
if (ol.box) {
|
|
5824
|
-
var
|
|
5825
|
-
var
|
|
5826
|
-
var
|
|
5827
|
-
var
|
|
5828
|
-
var obR = Math.min(ol.box.r * olMS * s, obFullH / 2)
|
|
5591
|
+
var rbPX = ol.box.px * olMS * s
|
|
5592
|
+
var rbPY = ol.box.py * olMS * s
|
|
5593
|
+
var rbW = rtL.width + rbPX * 2
|
|
5594
|
+
var rbH = rtN * rtLH + rbPY * 2
|
|
5829
5595
|
ovC.save()
|
|
5830
5596
|
ovC.globalAlpha = olA * ol.box.o
|
|
5831
5597
|
ovC.fillStyle = ol.box.c
|
|
5832
|
-
rr(-
|
|
5598
|
+
rr(-rbW / 2, -rbH / 2, rbW, rbH, Math.min(ol.box.r * olMS * s, rbH / 2), ovC)
|
|
5833
5599
|
ovC.fill()
|
|
5834
5600
|
ovC.restore()
|
|
5835
5601
|
}
|
|
5602
|
+
// Highlights sit behind the words and take no legibility shadow. Under
|
|
5603
|
+
// a per-unit entrance each is drawn with its unit instead (below), so
|
|
5604
|
+
// it arrives with its word.
|
|
5605
|
+
for (var rhi = 0; !rtFx && rhi < rtN; rhi++) {
|
|
5606
|
+
var rhLine = rtL.lines[rhi]
|
|
5607
|
+
for (var rhj = 0; rhj < rhLine.frags.length; rhj++) {
|
|
5608
|
+
var rhF = rhLine.frags[rhj]
|
|
5609
|
+
if (!rhF.h) continue
|
|
5610
|
+
var rhR = TXL.decorationRect('h', rtLeft(rhLine.w) + rhF.x, rhF.w, rtY0 + rhi * rtLH, olPx)
|
|
5611
|
+
ovC.fillStyle = rhF.h
|
|
5612
|
+
ovC.fillRect(rhR.x, rhR.y, rhR.w, rhR.h)
|
|
5613
|
+
}
|
|
5614
|
+
}
|
|
5836
5615
|
if (ol.shadow > 0) {
|
|
5837
5616
|
ovC.shadowColor = 'rgba(0,0,0,' + ol.shadow + ')'
|
|
5838
5617
|
ovC.shadowBlur = olPx * 0.25
|
|
5839
5618
|
ovC.shadowOffsetY = olPx * 0.04
|
|
5840
5619
|
}
|
|
5841
|
-
ovC.
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
ovC.
|
|
5620
|
+
ovC.textAlign = 'left'
|
|
5621
|
+
// One fragment (or the part of one a unit holds): the underline under
|
|
5622
|
+
// the glyphs, stroke under fill, the strikethrough over them.
|
|
5623
|
+
var rtPart = function (p, bx, y, withH) {
|
|
5624
|
+
if (withH && p.h) {
|
|
5625
|
+
var rhU = TXL.decorationRect('h', bx + p.x, p.w, y, olPx)
|
|
5626
|
+
var rhS = ovC.shadowColor
|
|
5627
|
+
ovC.shadowColor = 'rgba(0,0,0,0)'
|
|
5628
|
+
ovC.fillStyle = p.h
|
|
5629
|
+
ovC.fillRect(rhU.x, rhU.y, rhU.w, rhU.h)
|
|
5630
|
+
ovC.shadowColor = rhS
|
|
5631
|
+
}
|
|
5632
|
+
ovC.font = rtFonts[p.f || 0]
|
|
5633
|
+
ovC.fillStyle = p.c || ol.color
|
|
5634
|
+
if (p.u) {
|
|
5635
|
+
var ru = TXL.decorationRect('u', bx + p.x, p.w, y, olPx)
|
|
5636
|
+
ovC.fillRect(ru.x, ru.y, ru.w, ru.h)
|
|
5637
|
+
}
|
|
5638
|
+
if (ol.stroke) {
|
|
5639
|
+
ovC.strokeStyle = ol.stroke.c
|
|
5640
|
+
ovC.lineWidth = ol.stroke.w * olMS * s
|
|
5641
|
+
ovC.lineJoin = 'round'
|
|
5642
|
+
ovC.strokeText(p.t, bx + p.x, y)
|
|
5643
|
+
}
|
|
5644
|
+
ovC.fillText(p.t, bx + p.x, y)
|
|
5645
|
+
if (p.s) {
|
|
5646
|
+
var rs = TXL.decorationRect('s', bx + p.x, p.w, y, olPx)
|
|
5647
|
+
ovC.fillRect(rs.x, rs.y, rs.w, rs.h)
|
|
5648
|
+
}
|
|
5649
|
+
}
|
|
5650
|
+
if (!rtFx) {
|
|
5651
|
+
for (var rli = 0; rli < rtN; rli++) {
|
|
5652
|
+
var rLine = rtL.lines[rli]
|
|
5653
|
+
var rBX = rtLeft(rLine.w)
|
|
5654
|
+
for (var rfk = 0; rfk < rLine.frags.length; rfk++) rtPart(rLine.frags[rfk], rBX, rtY0 + rli * rtLH)
|
|
5858
5655
|
}
|
|
5859
5656
|
} else {
|
|
5860
|
-
// Per-unit entrance
|
|
5861
|
-
//
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
var
|
|
5869
|
-
var
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
}
|
|
5877
|
-
var olXb = olXof2 - olLW2 / 2
|
|
5878
|
-
var olPref = '', olPW = 0
|
|
5879
|
-
for (var ou = 0; ou < olUs.length; ou++, olIdx++) {
|
|
5880
|
-
var olOrd = olFx.d === 1
|
|
5881
|
-
? (olFx.n - 1 - olIdx)
|
|
5882
|
-
: olFx.d === 2
|
|
5883
|
-
? Math.abs(olIdx - (olFx.n - 1) / 2)
|
|
5884
|
-
: olIdx
|
|
5885
|
-
var olT2 = olT - olOrd * olFx.st
|
|
5886
|
-
var olNext = olPref + olUs[ou]
|
|
5887
|
-
var olNW = ovC.measureText(olNext).width
|
|
5888
|
-
var olUW = olNW - olPW
|
|
5889
|
-
var olUX = olXb + olPW
|
|
5890
|
-
var olUA = 1, olUu = 1
|
|
5891
|
-
if (olFx.k === 'typewriter') {
|
|
5892
|
-
olUA = olT2 >= 0 ? 1 : 0
|
|
5657
|
+
// Per-unit entrance, the plain layer's own arithmetic over the
|
|
5658
|
+
// layout's units: delay = order(index) x st, eased over dur.
|
|
5659
|
+
var rtCount = 0
|
|
5660
|
+
for (var rci = 0; rci < rtN; rci++) rtCount += rtL.lines[rci].units.length
|
|
5661
|
+
var rtIdx = 0
|
|
5662
|
+
for (var rui = 0; rui < rtN; rui++) {
|
|
5663
|
+
var rULine = rtL.lines[rui]
|
|
5664
|
+
var rUBX = rtLeft(rULine.w)
|
|
5665
|
+
var rUY = rtY0 + rui * rtLH
|
|
5666
|
+
for (var ruj = 0; ruj < rULine.units.length; ruj++, rtIdx++) {
|
|
5667
|
+
var rU = rULine.units[ruj]
|
|
5668
|
+
var rOrd = rtFx.d === 1 ? (rtCount - 1 - rtIdx) : rtFx.d === 2 ? Math.abs(rtIdx - (rtCount - 1) / 2) : rtIdx
|
|
5669
|
+
var rT2 = olT - rOrd * rtFx.st
|
|
5670
|
+
var rUA = 1, rUu = 1
|
|
5671
|
+
if (rtFx.k === 'typewriter') {
|
|
5672
|
+
rUA = rT2 >= 0 ? 1 : 0
|
|
5893
5673
|
} else {
|
|
5894
|
-
|
|
5895
|
-
var
|
|
5896
|
-
|
|
5674
|
+
rUu = Math.max(0, Math.min(1, rT2 / rtFx.dur))
|
|
5675
|
+
var rUE = 1 - Math.pow(1 - rUu, 3)
|
|
5676
|
+
rUA = rtFx.k === 'pop' ? Math.min(1, rUu * 2) : rUE
|
|
5897
5677
|
}
|
|
5898
|
-
|
|
5899
|
-
olPref = olNext
|
|
5900
|
-
olPW = olNW
|
|
5901
|
-
if (olUA <= 0.004) continue
|
|
5678
|
+
if (rUA <= 0.004) continue
|
|
5902
5679
|
ovC.save()
|
|
5903
|
-
ovC.globalAlpha = olA *
|
|
5904
|
-
if (
|
|
5905
|
-
if (
|
|
5906
|
-
ovC.translate(0, (1 - (1 - Math.pow(1 -
|
|
5907
|
-
} else if (
|
|
5908
|
-
var
|
|
5909
|
-
|
|
5910
|
-
ovC.
|
|
5911
|
-
ovC.
|
|
5912
|
-
|
|
5913
|
-
|
|
5680
|
+
ovC.globalAlpha = olA * rUA
|
|
5681
|
+
if (rUu < 1) {
|
|
5682
|
+
if (rtFx.k === 'rise') {
|
|
5683
|
+
ovC.translate(0, (1 - (1 - Math.pow(1 - rUu, 3))) * 24 * s)
|
|
5684
|
+
} else if (rtFx.k === 'pop') {
|
|
5685
|
+
var rPS = 1 + 2.70158 * Math.pow(rUu - 1, 3) + 1.70158 * Math.pow(rUu - 1, 2)
|
|
5686
|
+
var rCX = rUBX + rU.x + rU.w / 2
|
|
5687
|
+
ovC.translate(rCX, rUY)
|
|
5688
|
+
ovC.scale(rPS, rPS)
|
|
5689
|
+
ovC.translate(-rCX, -rUY)
|
|
5690
|
+
} else if (rtFx.k === 'blur') {
|
|
5691
|
+
ovC.filter = 'blur(' + ((1 - rUu) * olPx * 0.12).toFixed(2) + 'px)'
|
|
5914
5692
|
}
|
|
5915
5693
|
}
|
|
5916
|
-
|
|
5917
|
-
ovC.strokeStyle = ol.stroke.c
|
|
5918
|
-
ovC.lineWidth = ol.stroke.w * olMS * s
|
|
5919
|
-
ovC.lineJoin = 'round'
|
|
5920
|
-
ovC.strokeText(olUnit, olUX, olLY2)
|
|
5921
|
-
}
|
|
5922
|
-
ovC.fillText(olUnit, olUX, olLY2)
|
|
5694
|
+
for (var rpk = 0; rpk < rU.parts.length; rpk++) rtPart(rU.parts[rpk], rUBX, rUY, true)
|
|
5923
5695
|
ovC.restore()
|
|
5924
5696
|
}
|
|
5925
5697
|
}
|
|
@@ -8885,11 +8657,12 @@ function studioLayerData(input, duration, pins) {
|
|
|
8885
8657
|
return {
|
|
8886
8658
|
...base,
|
|
8887
8659
|
text: overlayPlainText(o),
|
|
8888
|
-
// The lines a person reads
|
|
8660
|
+
// The lines a person reads: what a plain layer is laid out
|
|
8661
|
+
// from, one run a line. A styled layer (rt) is laid out from
|
|
8889
8662
|
// its runs; these are then its words, for the signature.
|
|
8890
8663
|
lines: overlayLines(overlayPlainText(o)),
|
|
8891
8664
|
// The styled payload, only when the layer is set in more than
|
|
8892
|
-
// one style
|
|
8665
|
+
// one style.
|
|
8893
8666
|
...rt ? { rt } : {},
|
|
8894
8667
|
fs: st.size,
|
|
8895
8668
|
weight: st.weight,
|
|
@@ -8922,9 +8695,10 @@ function studioLayerData(input, duration, pins) {
|
|
|
8922
8695
|
r: round8(bx.radius)
|
|
8923
8696
|
}
|
|
8924
8697
|
} : {},
|
|
8925
|
-
// Entrance animation:
|
|
8926
|
-
//
|
|
8927
|
-
// per-unit progress as pure f(t). Absent = data
|
|
8698
|
+
// Entrance animation: timing normalized HERE (deterministic
|
|
8699
|
+
// doc-derived data) — ON_FRAME cuts the units from the layout
|
|
8700
|
+
// and interprets per-unit progress as pure f(t). Absent = data
|
|
8701
|
+
// byte parity.
|
|
8928
8702
|
...(() => {
|
|
8929
8703
|
const olFx = resolveOverlayFx(
|
|
8930
8704
|
o,
|
|
@@ -12835,6 +12609,7 @@ export {
|
|
|
12835
12609
|
styleAt,
|
|
12836
12610
|
styleOf,
|
|
12837
12611
|
styledTextOf,
|
|
12612
|
+
textRunsOf,
|
|
12838
12613
|
tiltLane,
|
|
12839
12614
|
tiltTrackFromDoc,
|
|
12840
12615
|
toggleStyle,
|