@vosjs/studio-core 0.36.0 → 0.37.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 +158 -5
- package/dist/index.js +497 -130
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -3239,6 +3239,169 @@ function htmlLayerPayload(clip) {
|
|
|
3239
3239
|
};
|
|
3240
3240
|
}
|
|
3241
3241
|
|
|
3242
|
+
// src/richText/layout.ts
|
|
3243
|
+
var sameStyle = (a, b) => (a.f || 0) === (b.f || 0) && a.c === b.c && a.u === b.u && a.s === b.s && a.h === b.h;
|
|
3244
|
+
function graphemesOf(text) {
|
|
3245
|
+
if (typeof Intl !== "undefined" && typeof Intl.Segmenter === "function") {
|
|
3246
|
+
const seg = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
3247
|
+
const out = [];
|
|
3248
|
+
for (const s of seg.segment(text)) out.push(s.segment);
|
|
3249
|
+
return out;
|
|
3250
|
+
}
|
|
3251
|
+
return Array.from(text);
|
|
3252
|
+
}
|
|
3253
|
+
function tokenRanges(line) {
|
|
3254
|
+
const out = [];
|
|
3255
|
+
const re = /\S+\s*/g;
|
|
3256
|
+
let m;
|
|
3257
|
+
while ((m = re.exec(line)) !== null) {
|
|
3258
|
+
out.push([m.index, m.index + m[0].length]);
|
|
3259
|
+
}
|
|
3260
|
+
return out.length ? out : [[0, line.length]];
|
|
3261
|
+
}
|
|
3262
|
+
function layoutText(input, measure) {
|
|
3263
|
+
const memo = {};
|
|
3264
|
+
const adv = (t, f) => {
|
|
3265
|
+
if (!t) return 0;
|
|
3266
|
+
const key = f + "\0" + t;
|
|
3267
|
+
let w = memo[key];
|
|
3268
|
+
if (w === void 0) {
|
|
3269
|
+
w = measure(t, f);
|
|
3270
|
+
memo[key] = w;
|
|
3271
|
+
}
|
|
3272
|
+
return w;
|
|
3273
|
+
};
|
|
3274
|
+
const slice = (runs, a, b) => {
|
|
3275
|
+
const out = [];
|
|
3276
|
+
let at = 0;
|
|
3277
|
+
for (let i = 0; i < runs.length; i++) {
|
|
3278
|
+
const r = runs[i];
|
|
3279
|
+
const from = Math.max(a, at);
|
|
3280
|
+
const to = Math.min(b, at + r.t.length);
|
|
3281
|
+
if (to > from) {
|
|
3282
|
+
const t = r.t.slice(from - at, to - at);
|
|
3283
|
+
const last = out[out.length - 1];
|
|
3284
|
+
if (last && sameStyle(last, r)) last.t += t;
|
|
3285
|
+
else out.push({ ...r, t });
|
|
3286
|
+
}
|
|
3287
|
+
at += r.t.length;
|
|
3288
|
+
if (at >= b) break;
|
|
3289
|
+
}
|
|
3290
|
+
return out;
|
|
3291
|
+
};
|
|
3292
|
+
const widthOf = (runs) => {
|
|
3293
|
+
let w = 0;
|
|
3294
|
+
for (let i = 0; i < runs.length; i++) w += adv(runs[i].t, runs[i].f || 0);
|
|
3295
|
+
return w;
|
|
3296
|
+
};
|
|
3297
|
+
const partsIn = (frags, a, b) => {
|
|
3298
|
+
const out = [];
|
|
3299
|
+
for (let i = 0; i < frags.length; i++) {
|
|
3300
|
+
const fr = frags[i];
|
|
3301
|
+
const from = Math.max(a, fr.o);
|
|
3302
|
+
const to = Math.min(b, fr.o + fr.t.length);
|
|
3303
|
+
if (to <= from) continue;
|
|
3304
|
+
const f = fr.f || 0;
|
|
3305
|
+
const before = adv(fr.t.slice(0, from - fr.o), f);
|
|
3306
|
+
out.push({
|
|
3307
|
+
...fr,
|
|
3308
|
+
t: fr.t.slice(from - fr.o, to - fr.o),
|
|
3309
|
+
x: fr.x + before,
|
|
3310
|
+
w: adv(fr.t.slice(0, to - fr.o), f) - before,
|
|
3311
|
+
o: from
|
|
3312
|
+
});
|
|
3313
|
+
}
|
|
3314
|
+
return out;
|
|
3315
|
+
};
|
|
3316
|
+
const unitOf = (frags, a, b) => {
|
|
3317
|
+
const parts = partsIn(frags, a, b);
|
|
3318
|
+
if (!parts.length) return { x: 0, w: 0, parts };
|
|
3319
|
+
const last = parts[parts.length - 1];
|
|
3320
|
+
return { x: parts[0].x, w: last.x + last.w - parts[0].x, parts };
|
|
3321
|
+
};
|
|
3322
|
+
const lines = [];
|
|
3323
|
+
const max = input.maxWidth && input.maxWidth > 0 ? input.maxWidth : 0;
|
|
3324
|
+
let width = 0;
|
|
3325
|
+
let base = 0;
|
|
3326
|
+
const push2 = (runs, a, b) => {
|
|
3327
|
+
const cut = slice(runs, a, b);
|
|
3328
|
+
const frags = [];
|
|
3329
|
+
let x = 0;
|
|
3330
|
+
let o = 0;
|
|
3331
|
+
for (let i = 0; i < cut.length; i++) {
|
|
3332
|
+
const w = adv(cut[i].t, cut[i].f || 0);
|
|
3333
|
+
frags.push({ ...cut[i], x, w, o });
|
|
3334
|
+
x += w;
|
|
3335
|
+
o += cut[i].t.length;
|
|
3336
|
+
}
|
|
3337
|
+
const line = { w: x, frags, a: base + a, n: b - a };
|
|
3338
|
+
if (input.unit) {
|
|
3339
|
+
const text = cut.map((r) => r.t).join("");
|
|
3340
|
+
const units = [];
|
|
3341
|
+
if (input.unit === "line") units.push(unitOf(frags, 0, text.length));
|
|
3342
|
+
else if (input.unit === "word") {
|
|
3343
|
+
const toks = tokenRanges(text);
|
|
3344
|
+
for (let i = 0; i < toks.length; i++) {
|
|
3345
|
+
units.push(unitOf(frags, toks[i][0], toks[i][1]));
|
|
3346
|
+
}
|
|
3347
|
+
} else {
|
|
3348
|
+
let at = 0;
|
|
3349
|
+
const gs = graphemesOf(text);
|
|
3350
|
+
for (let i = 0; i < gs.length; i++) {
|
|
3351
|
+
units.push(unitOf(frags, at, at + gs[i].length));
|
|
3352
|
+
at += gs[i].length;
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
line.units = units;
|
|
3356
|
+
}
|
|
3357
|
+
if (x > width) width = x;
|
|
3358
|
+
lines.push(line);
|
|
3359
|
+
};
|
|
3360
|
+
for (let li = 0; li < input.lines.length; li++) {
|
|
3361
|
+
const runs = input.lines[li];
|
|
3362
|
+
let len = 0;
|
|
3363
|
+
for (let i = 0; i < runs.length; i++) len += runs[i].t.length;
|
|
3364
|
+
if (!max || !len || widthOf(slice(runs, 0, len)) <= max) {
|
|
3365
|
+
push2(runs, 0, len);
|
|
3366
|
+
} else {
|
|
3367
|
+
const text = runs.map((r) => r.t).join("");
|
|
3368
|
+
const toks = tokenRanges(text);
|
|
3369
|
+
let a = 0;
|
|
3370
|
+
let b = toks[0][1];
|
|
3371
|
+
for (let i = 1; i < toks.length; i++) {
|
|
3372
|
+
if (widthOf(slice(runs, a, toks[i][1])) <= max) b = toks[i][1];
|
|
3373
|
+
else {
|
|
3374
|
+
push2(runs, a, b);
|
|
3375
|
+
a = toks[i][0];
|
|
3376
|
+
b = toks[i][1];
|
|
3377
|
+
}
|
|
3378
|
+
}
|
|
3379
|
+
push2(runs, a, b);
|
|
3380
|
+
}
|
|
3381
|
+
base += len + 1;
|
|
3382
|
+
}
|
|
3383
|
+
if (!lines.length) lines.push({ w: 0, frags: [], a: 0, n: 0 });
|
|
3384
|
+
return { lines, width };
|
|
3385
|
+
}
|
|
3386
|
+
var UNDERLINE_OFFSET_EM = 0.42;
|
|
3387
|
+
var DECORATION_THICKNESS_EM = 0.065;
|
|
3388
|
+
var STRIKE_OFFSET_EM = 0.02;
|
|
3389
|
+
var HIGHLIGHT_HALF_EM = 0.58;
|
|
3390
|
+
function decorationRect(kind, x, w, y, px) {
|
|
3391
|
+
const x0 = Math.round(x);
|
|
3392
|
+
const x1 = Math.round(x + w);
|
|
3393
|
+
if (kind === "h") {
|
|
3394
|
+
const top2 = Math.round(y - HIGHLIGHT_HALF_EM * px);
|
|
3395
|
+
const bottom = Math.round(y + HIGHLIGHT_HALF_EM * px);
|
|
3396
|
+
return { x: x0, y: top2, w: x1 - x0, h: bottom - top2 };
|
|
3397
|
+
}
|
|
3398
|
+
const t = Math.max(1, Math.round(DECORATION_THICKNESS_EM * px));
|
|
3399
|
+
const top = Math.round(
|
|
3400
|
+
y + (kind === "u" ? UNDERLINE_OFFSET_EM : STRIKE_OFFSET_EM) * px
|
|
3401
|
+
);
|
|
3402
|
+
return { x: x0, y: top, w: x1 - x0, h: t };
|
|
3403
|
+
}
|
|
3404
|
+
|
|
3242
3405
|
// src/overlayText.ts
|
|
3243
3406
|
var OVERLAY_BOX_PAD_X = 0.6;
|
|
3244
3407
|
var OVERLAY_BOX_PAD_Y = 0.35;
|
|
@@ -3445,19 +3608,44 @@ function resolveEmphasis(clip) {
|
|
|
3445
3608
|
} : {}
|
|
3446
3609
|
};
|
|
3447
3610
|
}
|
|
3448
|
-
function
|
|
3449
|
-
let
|
|
3450
|
-
let
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
if (c === EM_OPEN || c === EM_CLOSE) {
|
|
3454
|
-
if (run) w += measure(run, b ? emFont : font);
|
|
3455
|
-
run = "";
|
|
3456
|
-
b = c === EM_OPEN;
|
|
3457
|
-
} else run += c;
|
|
3611
|
+
function hashOf(text) {
|
|
3612
|
+
let h = 2166136261;
|
|
3613
|
+
for (let i = 0; i < text.length; i++) {
|
|
3614
|
+
h ^= text.charCodeAt(i);
|
|
3615
|
+
h = Math.imul(h, 16777619);
|
|
3458
3616
|
}
|
|
3459
|
-
|
|
3460
|
-
|
|
3617
|
+
return (h >>> 0).toString(36);
|
|
3618
|
+
}
|
|
3619
|
+
function styledTextOf(clip) {
|
|
3620
|
+
const em = resolveEmphasis(clip);
|
|
3621
|
+
if (!em) return null;
|
|
3622
|
+
const l = overlayLines(overlayDisplayText(clip)).map((line) => {
|
|
3623
|
+
const runs = [];
|
|
3624
|
+
let run = "";
|
|
3625
|
+
let bold = false;
|
|
3626
|
+
const flush = () => {
|
|
3627
|
+
if (!run) return;
|
|
3628
|
+
runs.push(
|
|
3629
|
+
bold ? { t: run, f: 1, ...em.color ? { c: em.color } : {} } : { t: run }
|
|
3630
|
+
);
|
|
3631
|
+
run = "";
|
|
3632
|
+
};
|
|
3633
|
+
for (const c of line) {
|
|
3634
|
+
if (c === EM_OPEN || c === EM_CLOSE) {
|
|
3635
|
+
flush();
|
|
3636
|
+
bold = c === EM_OPEN;
|
|
3637
|
+
} else run += c;
|
|
3638
|
+
}
|
|
3639
|
+
flush();
|
|
3640
|
+
return runs;
|
|
3641
|
+
});
|
|
3642
|
+
const fs = [{ w: resolveOverlayStyle(clip).weight }, { w: em.weight }];
|
|
3643
|
+
return {
|
|
3644
|
+
l,
|
|
3645
|
+
fs,
|
|
3646
|
+
...em.face ? { faces: [{ f: em.face.family, w: em.face.weight, u: em.face.url }] } : {},
|
|
3647
|
+
h: hashOf(JSON.stringify([l, fs]))
|
|
3648
|
+
};
|
|
3461
3649
|
}
|
|
3462
3650
|
function overlayTokens(line) {
|
|
3463
3651
|
return line.match(/\S+\s*/g) ?? [line];
|
|
@@ -3487,7 +3675,7 @@ function wrapOverlayLines(lines, measure, maxPx) {
|
|
|
3487
3675
|
}
|
|
3488
3676
|
return out.length ? out : [""];
|
|
3489
3677
|
}
|
|
3490
|
-
function
|
|
3678
|
+
function graphemesOf2(line) {
|
|
3491
3679
|
if (typeof Intl !== "undefined" && typeof Intl.Segmenter === "function") {
|
|
3492
3680
|
return [
|
|
3493
3681
|
...new Intl.Segmenter(void 0, { granularity: "grapheme" }).segment(
|
|
@@ -3502,14 +3690,14 @@ function overlaySegments(text, unit) {
|
|
|
3502
3690
|
if (unit === "block") return [];
|
|
3503
3691
|
if (unit === "line") return lines.map((l) => [l]);
|
|
3504
3692
|
if (unit === "word") return lines.map(overlayTokens);
|
|
3505
|
-
return lines.map(
|
|
3693
|
+
return lines.map(graphemesOf2);
|
|
3506
3694
|
}
|
|
3507
3695
|
var FX_DIR = { forward: 0, reverse: 1, center: 2 };
|
|
3508
3696
|
function resolveOverlayFx(clip, clipDuration) {
|
|
3509
3697
|
const spec = overlayFxSpec(clip) ?? clip.fx ?? null;
|
|
3510
3698
|
if (!spec) return null;
|
|
3511
3699
|
const unit = spec.unit ?? "block";
|
|
3512
|
-
const text = overlayDisplayText(clip);
|
|
3700
|
+
const text = stripEmphasis(overlayDisplayText(clip));
|
|
3513
3701
|
const units = overlaySegments(text, unit);
|
|
3514
3702
|
const n = unit === "block" ? 1 : units.reduce((sum, line) => sum + line.length, 0);
|
|
3515
3703
|
const upperN = unit === "line" && clip.maxWidth ? overlayLines(text).reduce(
|
|
@@ -3559,13 +3747,25 @@ function overlayRect(clip, measure, frameW, frameH = 1080, mediaAspect) {
|
|
|
3559
3747
|
const style = resolveOverlayStyle(clip);
|
|
3560
3748
|
const font = overlayFontString(style, scale, 1);
|
|
3561
3749
|
const ls = style.letterSpacing * scale;
|
|
3562
|
-
const
|
|
3563
|
-
const emFont = em ? overlayFontString({ ...style, weight: em.weight }, scale, 1) : "";
|
|
3564
|
-
const width = (t) => em ? measureEmphasized(t, (run, f) => measure(run, f, ls), font, emFont) : measure(t, font, ls);
|
|
3565
|
-
const text = overlayDisplayText(clip);
|
|
3566
|
-
const lines = clip.maxWidth ? wrapOverlayLines(overlayLines(text), width, clip.maxWidth * frameW) : overlayLines(text);
|
|
3750
|
+
const styled = styledTextOf(clip);
|
|
3567
3751
|
let w = 0;
|
|
3568
|
-
|
|
3752
|
+
let lineCount = 0;
|
|
3753
|
+
if (styled) {
|
|
3754
|
+
const fonts = styled.fs.map(
|
|
3755
|
+
(f) => overlayFontString({ ...style, weight: f.w }, scale, 1)
|
|
3756
|
+
);
|
|
3757
|
+
const laid = layoutText(
|
|
3758
|
+
{ lines: styled.l, maxWidth: clip.maxWidth ? clip.maxWidth * frameW : 0 },
|
|
3759
|
+
(t, f) => measure(t, fonts[f], ls)
|
|
3760
|
+
);
|
|
3761
|
+
w = laid.width;
|
|
3762
|
+
lineCount = laid.lines.length;
|
|
3763
|
+
} else {
|
|
3764
|
+
const width = (t) => measure(t, font, ls);
|
|
3765
|
+
const lines = clip.maxWidth ? wrapOverlayLines(overlayLines(clip.text), width, clip.maxWidth * frameW) : overlayLines(clip.text);
|
|
3766
|
+
for (const line of lines) w = Math.max(w, width(line));
|
|
3767
|
+
lineCount = lines.length;
|
|
3768
|
+
}
|
|
3569
3769
|
const lineH = style.size * scale * style.lineHeight;
|
|
3570
3770
|
const box = resolveOverlayBox(clip);
|
|
3571
3771
|
const padX = box ? box.padX * scale : 0;
|
|
@@ -3574,7 +3774,7 @@ function overlayRect(clip, measure, frameW, frameH = 1080, mediaAspect) {
|
|
|
3574
3774
|
...base,
|
|
3575
3775
|
w: Math.max(w, style.size * scale * 0.6) + padX * 2,
|
|
3576
3776
|
// empty text still selectable
|
|
3577
|
-
h:
|
|
3777
|
+
h: lineCount * lineH + padY * 2
|
|
3578
3778
|
};
|
|
3579
3779
|
}
|
|
3580
3780
|
function overlayHit(rect, px, py, padPx = 8) {
|
|
@@ -4317,6 +4517,11 @@ function push(keys, t, a) {
|
|
|
4317
4517
|
|
|
4318
4518
|
// src/lower/studioEntry.ts
|
|
4319
4519
|
import { timelineRuntimeCode } from "@vosjs/timeline/bundle";
|
|
4520
|
+
|
|
4521
|
+
// src/richText/layoutCode.ts
|
|
4522
|
+
var textLayoutCode = '"use strict";var __vosTextLayout=(()=>{var E=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var N=Object.prototype.hasOwnProperty;var W=(n,r)=>{for(var h in r)E(n,h,{get:r[h],enumerable:!0})},j=(n,r,h,l)=>{if(r&&typeof r=="object"||typeof r=="function")for(let f of A(r))!N.call(n,f)&&f!==h&&E(n,f,{get:()=>r[f],enumerable:!(l=k(r,f))||l.enumerable});return n};var C=n=>j(E({},"__esModule",{value:!0}),n);var v={};W(v,{DECORATION_THICKNESS_EM:()=>U,HIGHLIGHT_HALF_EM:()=>I,STRIKE_OFFSET_EM:()=>H,UNDERLINE_OFFSET_EM:()=>O,decorationRect:()=>K,graphemesOf:()=>_,layoutText:()=>G,tokenRanges:()=>F});var D=(n,r)=>(n.f||0)===(r.f||0)&&n.c===r.c&&n.u===r.u&&n.s===r.s&&n.h===r.h;function _(n){if(typeof Intl<"u"&&typeof Intl.Segmenter=="function"){let r=new Intl.Segmenter(void 0,{granularity:"grapheme"}),h=[];for(let l of r.segment(n))h.push(l.segment);return h}return Array.from(n)}function F(n){let r=[],h=/\\S+\\s*/g,l;for(;(l=h.exec(n))!==null;)r.push([l.index,l.index+l[0].length]);return r.length?r:[[0,n.length]]}function G(n,r){let h={},l=(i,u)=>{if(!i)return 0;let s=u+"\\0"+i,t=h[s];return t===void 0&&(t=r(i,u),h[s]=t),t},f=(i,u,s)=>{let t=[],o=0;for(let e=0;e<i.length;e++){let c=i[e],a=Math.max(u,o),m=Math.min(s,o+c.t.length);if(m>a){let g=c.t.slice(a-o,m-o),x=t[t.length-1];x&&D(x,c)?x.t+=g:t.push({...c,t:g})}if(o+=c.t.length,o>=s)break}return t},p=i=>{let u=0;for(let s=0;s<i.length;s++)u+=l(i[s].t,i[s].f||0);return u},R=(i,u,s)=>{let t=[];for(let o=0;o<i.length;o++){let e=i[o],c=Math.max(u,e.o),a=Math.min(s,e.o+e.t.length);if(a<=c)continue;let m=e.f||0,g=l(e.t.slice(0,c-e.o),m);t.push({...e,t:e.t.slice(c-e.o,a-e.o),x:e.x+g,w:l(e.t.slice(0,a-e.o),m)-g,o:c})}return t},L=(i,u,s)=>{let t=R(i,u,s);if(!t.length)return{x:0,w:0,parts:t};let o=t[t.length-1];return{x:t[0].x,w:o.x+o.w-t[0].x,parts:t}},y=[],d=n.maxWidth&&n.maxWidth>0?n.maxWidth:0,w=0,T=0,S=(i,u,s)=>{let t=f(i,u,s),o=[],e=0,c=0;for(let m=0;m<t.length;m++){let g=l(t[m].t,t[m].f||0);o.push({...t[m],x:e,w:g,o:c}),e+=g,c+=t[m].t.length}let a={w:e,frags:o,a:T+u,n:s-u};if(n.unit){let m=t.map(x=>x.t).join(""),g=[];if(n.unit==="line")g.push(L(o,0,m.length));else if(n.unit==="word"){let x=F(m);for(let b=0;b<x.length;b++)g.push(L(o,x[b][0],x[b][1]))}else{let x=0,b=_(m);for(let M=0;M<b.length;M++)g.push(L(o,x,x+b[M].length)),x+=b[M].length}a.units=g}e>w&&(w=e),y.push(a)};for(let i=0;i<n.lines.length;i++){let u=n.lines[i],s=0;for(let t=0;t<u.length;t++)s+=u[t].t.length;if(!d||!s||p(f(u,0,s))<=d)S(u,0,s);else{let t=u.map(a=>a.t).join(""),o=F(t),e=0,c=o[0][1];for(let a=1;a<o.length;a++)p(f(u,e,o[a][1]))<=d||(S(u,e,c),e=o[a][0]),c=o[a][1];S(u,e,c)}T+=s+1}return y.length||y.push({w:0,frags:[],a:0,n:0}),{lines:y,width:w}}var O=.42,U=.065,H=.02,I=.58;function K(n,r,h,l,f){let p=Math.round(r),R=Math.round(r+h);if(n==="h"){let d=Math.round(l-I*f),w=Math.round(l+I*f);return{x:p,y:d,w:R-p,h:w-d}}let L=Math.max(1,Math.round(U*f)),y=Math.round(l+(n==="u"?O:H)*f);return{x:p,y,w:R-p,h:L}}return C(v);})();';
|
|
4523
|
+
|
|
4524
|
+
// src/lower/studioEntry.ts
|
|
4320
4525
|
var STUDIO_ENTRY_ID = "vosso.studio";
|
|
4321
4526
|
function studioEntry(data) {
|
|
4322
4527
|
return {
|
|
@@ -4713,6 +4918,18 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
|
|
|
4713
4918
|
var s = H / 1080 // scale design-px controls to comp px
|
|
4714
4919
|
var ns = window.__vos__ || {}
|
|
4715
4920
|
var playing = ns.isPaused === false
|
|
4921
|
+
// The styled-text layout (richText/layout.ts, generated), installed once:
|
|
4922
|
+
// the page lays a text layer out with the code the host picks with.
|
|
4923
|
+
if (!ns.textLayout) { ${textLayoutCode}; ns.textLayout = __vosTextLayout }
|
|
4924
|
+
var TXL = ns.textLayout
|
|
4925
|
+
// The font epoch counts faces landing. A face changes what text measures
|
|
4926
|
+
// and what it paints, so the epoch is part of every layout's key and of
|
|
4927
|
+
// the layer's signature: a late face repaints a held layer once.
|
|
4928
|
+
var ofBump = function () { ns.fontEpoch = (ns.fontEpoch || 0) + 1 }
|
|
4929
|
+
if (!ns.fontWatch && typeof document !== 'undefined' && document.fonts && document.fonts.addEventListener) {
|
|
4930
|
+
ns.fontWatch = 1
|
|
4931
|
+
document.fonts.addEventListener('loadingdone', ofBump)
|
|
4932
|
+
}
|
|
4716
4933
|
|
|
4717
4934
|
// --- audio clips (music/SFX): Web Audio scheduler against the transport ---
|
|
4718
4935
|
// Buffer sources are one-shot: (re)schedule everything on play / clip-data change
|
|
@@ -4840,7 +5057,19 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
|
|
|
4840
5057
|
if (t < ol0.start || t > ol0.start + ol0.dur) continue
|
|
4841
5058
|
// A page that taints on foreignObject draws no HTML layer (setup's probe).
|
|
4842
5059
|
if (ol0.html && ns.htmlSafe === false) continue
|
|
4843
|
-
olVisSig += ol0.id + ':' + (ol0.text || ol0.key) + ':' + ol0.x + ',' + ol0.y + ',' + ol0.scale + ',' + ol0.rot + ',' + (ol0.fs || ol0.w) + ',' + (ol0.color || ol0.radius) + ',' + (ol0.opacity == null ? 1 : ol0.opacity) + (ol0.fx ? ',' + ol0.fx.k + ol0.fx.u + ol0.fx.d + ol0.fx.st : '') + (ol0.mw ? ',w' + ol0.mw : '')
|
|
5060
|
+
olVisSig += ol0.id + ':' + (ol0.text || ol0.key) + ':' + ol0.x + ',' + ol0.y + ',' + ol0.scale + ',' + ol0.rot + ',' + (ol0.fs || ol0.w) + ',' + (ol0.color || ol0.radius) + ',' + (ol0.opacity == null ? 1 : ol0.opacity) + (ol0.fx ? ',' + ol0.fx.k + ol0.fx.u + ol0.fx.d + ol0.fx.st : '') + (ol0.mw ? ',w' + ol0.mw : '')
|
|
5061
|
+
// Everything else a held layer's pixels depend on. The signature is the
|
|
5062
|
+
// ONLY thing that repaints a hold, so a field missing here is an edit
|
|
5063
|
+
// that does not show until something else moves.
|
|
5064
|
+
if (ol0.lines) {
|
|
5065
|
+
olVisSig += '|' + ol0.lines.join('\\n') + '|' + ol0.weight + '|' + ol0.stack + '|' + (ol0.sty || '') + '|' + (ol0.ls || 0) + '|' + (ol0.lh || 0) + '|' + (ol0.align || '') + '|' + ol0.shadow
|
|
5066
|
+
+ (ol0.stroke ? '|s' + ol0.stroke.c + ol0.stroke.w : '')
|
|
5067
|
+
+ (ol0.box ? '|b' + ol0.box.c + ol0.box.o + ',' + ol0.box.px + ',' + ol0.box.py + ',' + ol0.box.r : '')
|
|
5068
|
+
+ (ol0.rt ? '|r' + ol0.rt.h : '')
|
|
5069
|
+
} else {
|
|
5070
|
+
olVisSig += '|' + (ol0.shadow || '') + (ol0.border ? '|' + ol0.border.width + ol0.border.color : '') + (ol0.crop ? '|c' + ol0.crop.x + ',' + ol0.crop.y + ',' + ol0.crop.w + ',' + ol0.crop.h : '')
|
|
5071
|
+
}
|
|
5072
|
+
olVisSig += ';'
|
|
4844
5073
|
// fx widens the entrance window to the whole staggered span (tt);
|
|
4845
5074
|
// without fx it is the legacy enter transition window.
|
|
4846
5075
|
var olEW = ol0.fx ? ol0.fx.tt : olTD
|
|
@@ -4878,8 +5107,20 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
|
|
|
4878
5107
|
if (ns.htmlErrors) delete ns.htmlErrors[hlK]
|
|
4879
5108
|
}
|
|
4880
5109
|
}
|
|
4881
|
-
|
|
4882
|
-
|
|
5110
|
+
// A styled layer's cached layout leaves with its clip.
|
|
5111
|
+
if (ns.textLayouts) {
|
|
5112
|
+
for (var tlK in ns.textLayouts) {
|
|
5113
|
+
var tlSeen = false
|
|
5114
|
+
for (var tlI = 0; tlI < ols.length; tlI++) if (ols[tlI].id === tlK) { tlSeen = true; break }
|
|
5115
|
+
if (!tlSeen) delete ns.textLayouts[tlK]
|
|
5116
|
+
}
|
|
5117
|
+
}
|
|
5118
|
+
var ovSig = W + 'x' + H + '|' + (ns.fontEpoch || 0) + '|' + (ns.htmlSafe === false ? 0 : 1) + '|' + olVisSig
|
|
5119
|
+
// The layer repaints when what it shows changed (the signature), while
|
|
5120
|
+
// something on it animates, and ONCE more after an animation's last frame:
|
|
5121
|
+
// that frame was drawn a moment short of settled, and a picture that
|
|
5122
|
+
// landed between two frames is drawn by it too. A hold costs nothing.
|
|
5123
|
+
var ovDirty = ov.sig !== ovSig || olAnim || ov.wasAnim
|
|
4883
5124
|
// The layer cards visible this frame, with their pose, for the card
|
|
4884
5125
|
// planes below (the overlay loop collects them instead of painting).
|
|
4885
5126
|
var lcList = []
|
|
@@ -5108,7 +5349,7 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
|
|
|
5108
5349
|
try {
|
|
5109
5350
|
var ofBF = new FontFace(ofB.family, 'url(' + ofB.url + ')', { weight: String(ofB.weight) })
|
|
5110
5351
|
document.fonts.add(ofBF)
|
|
5111
|
-
ofBF.load().
|
|
5352
|
+
ofBF.load().then(ofBump, function () {})
|
|
5112
5353
|
} catch (e) {}
|
|
5113
5354
|
}
|
|
5114
5355
|
if (ol.face) {
|
|
@@ -5118,20 +5359,22 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
|
|
|
5118
5359
|
try {
|
|
5119
5360
|
var ofFace = new FontFace(ol.face.f, 'url(' + ol.face.u + ')', { weight: String(ol.face.w) })
|
|
5120
5361
|
document.fonts.add(ofFace)
|
|
5121
|
-
ofFace.load().
|
|
5362
|
+
ofFace.load().then(ofBump, function () {})
|
|
5122
5363
|
} catch (e) {}
|
|
5123
5364
|
}
|
|
5124
5365
|
}
|
|
5125
|
-
//
|
|
5126
|
-
// first
|
|
5127
|
-
if (ol.
|
|
5128
|
-
var
|
|
5129
|
-
|
|
5130
|
-
|
|
5366
|
+
// A styled layer's other faces, the same way (a live edit that styles
|
|
5367
|
+
// its first run paints without a LOAD).
|
|
5368
|
+
if (ol.rt && ol.rt.faces) {
|
|
5369
|
+
for (var rfj = 0; rfj < ol.rt.faces.length; rfj++) {
|
|
5370
|
+
var rtF = ol.rt.faces[rfj]
|
|
5371
|
+
var rtFK = rtF.f + '|' + rtF.w
|
|
5372
|
+
if (ofSet[rtFK]) continue
|
|
5373
|
+
ofSet[rtFK] = 1
|
|
5131
5374
|
try {
|
|
5132
|
-
var
|
|
5133
|
-
document.fonts.add(
|
|
5134
|
-
|
|
5375
|
+
var rtFace = new FontFace(rtF.f, 'url(' + rtF.u + ')', { weight: String(rtF.w) })
|
|
5376
|
+
document.fonts.add(rtFace)
|
|
5377
|
+
rtFace.load().then(ofBump, function () {})
|
|
5135
5378
|
} catch (e) {}
|
|
5136
5379
|
}
|
|
5137
5380
|
}
|
|
@@ -5150,68 +5393,143 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
|
|
|
5150
5393
|
ovC.textAlign = 'center'
|
|
5151
5394
|
ovC.textBaseline = 'middle'
|
|
5152
5395
|
ovC.letterSpacing = ((ol.ls || 0) * olMS * s) + 'px'
|
|
5153
|
-
//
|
|
5154
|
-
//
|
|
5155
|
-
//
|
|
5156
|
-
//
|
|
5157
|
-
//
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
var
|
|
5194
|
-
|
|
5396
|
+
// A STYLED layer (ol.rt: lines of runs, each set its own way) is laid
|
|
5397
|
+
// out by the layout module, ONCE: the layout is kept per clip under a
|
|
5398
|
+
// key of everything it was measured with, so a frame that only moves,
|
|
5399
|
+
// fades or reveals the layer measures nothing. Fragments draw left to
|
|
5400
|
+
// right from each line's left edge; a per-unit entrance animates the
|
|
5401
|
+
// layout's units, each a few parts of fragments.
|
|
5402
|
+
if (ol.rt) {
|
|
5403
|
+
var rtFonts = [ovC.font]
|
|
5404
|
+
for (var rfi = 1; rfi < ol.rt.fs.length; rfi++) {
|
|
5405
|
+
rtFonts.push((ol.sty ? ol.sty + ' ' : '') + ol.rt.fs[rfi].w + ' ' + olPx + 'px ' + ol.stack)
|
|
5406
|
+
}
|
|
5407
|
+
var rtFx = ol.fx && ol.fx.units.length ? ol.fx : null
|
|
5408
|
+
var rtMax = ol.mw ? ol.mw * W : 0
|
|
5409
|
+
var rtKey = ol.rt.h + '|' + rtFonts[0] + '|' + ((ol.ls || 0) * olMS * s) + '|' + rtMax + '|' + (rtFx ? rtFx.u : '') + '|' + (ns.fontEpoch || 0)
|
|
5410
|
+
var rtAll = ns.textLayouts || (ns.textLayouts = {})
|
|
5411
|
+
var rtHit = rtAll[ol.id]
|
|
5412
|
+
if (!rtHit || rtHit.k !== rtKey) {
|
|
5413
|
+
rtHit = rtAll[ol.id] = {
|
|
5414
|
+
k: rtKey,
|
|
5415
|
+
L: TXL.layoutText(
|
|
5416
|
+
{ lines: ol.rt.l, maxWidth: rtMax, unit: rtFx ? rtFx.u : undefined },
|
|
5417
|
+
function (mt, mf) { ovC.font = rtFonts[mf]; return ovC.measureText(mt).width }
|
|
5418
|
+
)
|
|
5419
|
+
}
|
|
5420
|
+
ovC.font = rtFonts[0]
|
|
5421
|
+
}
|
|
5422
|
+
var rtL = rtHit.L
|
|
5423
|
+
var rtN = rtL.lines.length
|
|
5424
|
+
var rtLH = olPx * (ol.lh || ${OVERLAY_LINE_HEIGHT})
|
|
5425
|
+
var rtY0 = -((rtN - 1) * rtLH) / 2
|
|
5426
|
+
// A line's left edge: lines sit centred on the anchor and align
|
|
5427
|
+
// against the widest, as the plain layer's do.
|
|
5428
|
+
var rtLeft = function (lw) {
|
|
5429
|
+
var xo = ol.align === 'left' ? (lw - rtL.width) / 2 : ol.align === 'right' ? (rtL.width - lw) / 2 : 0
|
|
5430
|
+
return xo - lw / 2
|
|
5431
|
+
}
|
|
5432
|
+
if (ol.box) {
|
|
5433
|
+
var rbPX = ol.box.px * olMS * s
|
|
5434
|
+
var rbPY = ol.box.py * olMS * s
|
|
5435
|
+
var rbW = rtL.width + rbPX * 2
|
|
5436
|
+
var rbH = rtN * rtLH + rbPY * 2
|
|
5437
|
+
ovC.save()
|
|
5438
|
+
ovC.globalAlpha = olA * ol.box.o
|
|
5439
|
+
ovC.fillStyle = ol.box.c
|
|
5440
|
+
rr(-rbW / 2, -rbH / 2, rbW, rbH, Math.min(ol.box.r * olMS * s, rbH / 2), ovC)
|
|
5441
|
+
ovC.fill()
|
|
5442
|
+
ovC.restore()
|
|
5443
|
+
}
|
|
5444
|
+
// Highlights sit behind the words and take no legibility shadow.
|
|
5445
|
+
for (var rhi = 0; rhi < rtN; rhi++) {
|
|
5446
|
+
var rhLine = rtL.lines[rhi]
|
|
5447
|
+
for (var rhj = 0; rhj < rhLine.frags.length; rhj++) {
|
|
5448
|
+
var rhF = rhLine.frags[rhj]
|
|
5449
|
+
if (!rhF.h) continue
|
|
5450
|
+
var rhR = TXL.decorationRect('h', rtLeft(rhLine.w) + rhF.x, rhF.w, rtY0 + rhi * rtLH, olPx)
|
|
5451
|
+
ovC.fillStyle = rhF.h
|
|
5452
|
+
ovC.fillRect(rhR.x, rhR.y, rhR.w, rhR.h)
|
|
5453
|
+
}
|
|
5454
|
+
}
|
|
5455
|
+
if (ol.shadow > 0) {
|
|
5456
|
+
ovC.shadowColor = 'rgba(0,0,0,' + ol.shadow + ')'
|
|
5457
|
+
ovC.shadowBlur = olPx * 0.25
|
|
5458
|
+
ovC.shadowOffsetY = olPx * 0.04
|
|
5459
|
+
}
|
|
5460
|
+
ovC.textAlign = 'left'
|
|
5461
|
+
// One fragment (or the part of one a unit holds): the underline under
|
|
5462
|
+
// the glyphs, stroke under fill, the strikethrough over them.
|
|
5463
|
+
var rtPart = function (p, bx, y) {
|
|
5464
|
+
ovC.font = rtFonts[p.f || 0]
|
|
5465
|
+
ovC.fillStyle = p.c || ol.color
|
|
5466
|
+
if (p.u) {
|
|
5467
|
+
var ru = TXL.decorationRect('u', bx + p.x, p.w, y, olPx)
|
|
5468
|
+
ovC.fillRect(ru.x, ru.y, ru.w, ru.h)
|
|
5469
|
+
}
|
|
5195
5470
|
if (ol.stroke) {
|
|
5196
5471
|
ovC.strokeStyle = ol.stroke.c
|
|
5197
5472
|
ovC.lineWidth = ol.stroke.w * olMS * s
|
|
5198
5473
|
ovC.lineJoin = 'round'
|
|
5199
|
-
ovC.strokeText(
|
|
5474
|
+
ovC.strokeText(p.t, bx + p.x, y)
|
|
5475
|
+
}
|
|
5476
|
+
ovC.fillText(p.t, bx + p.x, y)
|
|
5477
|
+
if (p.s) {
|
|
5478
|
+
var rs = TXL.decorationRect('s', bx + p.x, p.w, y, olPx)
|
|
5479
|
+
ovC.fillRect(rs.x, rs.y, rs.w, rs.h)
|
|
5200
5480
|
}
|
|
5201
|
-
ovC.fillText(drun, dx, y)
|
|
5202
|
-
dx += ovC.measureText(drun).width
|
|
5203
|
-
ovC.fillStyle = dfs
|
|
5204
|
-
drun = ''
|
|
5205
5481
|
}
|
|
5206
|
-
|
|
5207
|
-
var
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
}
|
|
5482
|
+
if (!rtFx) {
|
|
5483
|
+
for (var rli = 0; rli < rtN; rli++) {
|
|
5484
|
+
var rLine = rtL.lines[rli]
|
|
5485
|
+
var rBX = rtLeft(rLine.w)
|
|
5486
|
+
for (var rfk = 0; rfk < rLine.frags.length; rfk++) rtPart(rLine.frags[rfk], rBX, rtY0 + rli * rtLH)
|
|
5487
|
+
}
|
|
5488
|
+
} else {
|
|
5489
|
+
// Per-unit entrance, the plain layer's own arithmetic over the
|
|
5490
|
+
// layout's units: delay = order(index) x st, eased over dur.
|
|
5491
|
+
var rtCount = 0
|
|
5492
|
+
for (var rci = 0; rci < rtN; rci++) rtCount += rtL.lines[rci].units.length
|
|
5493
|
+
var rtIdx = 0
|
|
5494
|
+
for (var rui = 0; rui < rtN; rui++) {
|
|
5495
|
+
var rULine = rtL.lines[rui]
|
|
5496
|
+
var rUBX = rtLeft(rULine.w)
|
|
5497
|
+
var rUY = rtY0 + rui * rtLH
|
|
5498
|
+
for (var ruj = 0; ruj < rULine.units.length; ruj++, rtIdx++) {
|
|
5499
|
+
var rU = rULine.units[ruj]
|
|
5500
|
+
var rOrd = rtFx.d === 1 ? (rtCount - 1 - rtIdx) : rtFx.d === 2 ? Math.abs(rtIdx - (rtCount - 1) / 2) : rtIdx
|
|
5501
|
+
var rT2 = olT - rOrd * rtFx.st
|
|
5502
|
+
var rUA = 1, rUu = 1
|
|
5503
|
+
if (rtFx.k === 'typewriter') {
|
|
5504
|
+
rUA = rT2 >= 0 ? 1 : 0
|
|
5505
|
+
} else {
|
|
5506
|
+
rUu = Math.max(0, Math.min(1, rT2 / rtFx.dur))
|
|
5507
|
+
var rUE = 1 - Math.pow(1 - rUu, 3)
|
|
5508
|
+
rUA = rtFx.k === 'pop' ? Math.min(1, rUu * 2) : rUE
|
|
5509
|
+
}
|
|
5510
|
+
if (rUA <= 0.004) continue
|
|
5511
|
+
ovC.save()
|
|
5512
|
+
ovC.globalAlpha = olA * rUA
|
|
5513
|
+
if (rUu < 1) {
|
|
5514
|
+
if (rtFx.k === 'rise') {
|
|
5515
|
+
ovC.translate(0, (1 - (1 - Math.pow(1 - rUu, 3))) * 24 * s)
|
|
5516
|
+
} else if (rtFx.k === 'pop') {
|
|
5517
|
+
var rPS = 1 + 2.70158 * Math.pow(rUu - 1, 3) + 1.70158 * Math.pow(rUu - 1, 2)
|
|
5518
|
+
var rCX = rUBX + rU.x + rU.w / 2
|
|
5519
|
+
ovC.translate(rCX, rUY)
|
|
5520
|
+
ovC.scale(rPS, rPS)
|
|
5521
|
+
ovC.translate(-rCX, -rUY)
|
|
5522
|
+
} else if (rtFx.k === 'blur') {
|
|
5523
|
+
ovC.filter = 'blur(' + ((1 - rUu) * olPx * 0.12).toFixed(2) + 'px)'
|
|
5524
|
+
}
|
|
5525
|
+
}
|
|
5526
|
+
for (var rpk = 0; rpk < rU.parts.length; rpk++) rtPart(rU.parts[rpk], rUBX, rUY)
|
|
5527
|
+
ovC.restore()
|
|
5528
|
+
}
|
|
5529
|
+
}
|
|
5212
5530
|
}
|
|
5213
|
-
|
|
5214
|
-
|
|
5531
|
+
ovC.restore()
|
|
5532
|
+
continue
|
|
5215
5533
|
}
|
|
5216
5534
|
var olLines = ol.lines || ['']
|
|
5217
5535
|
// maxWidth wrap (ol.mw = frame-width fraction): greedy over word tokens
|
|
@@ -5224,7 +5542,7 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
|
|
|
5224
5542
|
var olWrapped = []
|
|
5225
5543
|
for (var olwl = 0; olwl < olLines.length; olwl++) {
|
|
5226
5544
|
var olWLine = olLines[olwl]
|
|
5227
|
-
if (!olWLine ||
|
|
5545
|
+
if (!olWLine || ovC.measureText(olWLine).width <= olWMax) {
|
|
5228
5546
|
olWrapped.push(olWLine)
|
|
5229
5547
|
continue
|
|
5230
5548
|
}
|
|
@@ -5232,7 +5550,7 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
|
|
|
5232
5550
|
var olCur = ''
|
|
5233
5551
|
for (var olti = 0; olti < olToks.length; olti++) {
|
|
5234
5552
|
if (!olCur) { olCur = olToks[olti]; continue }
|
|
5235
|
-
if (
|
|
5553
|
+
if (ovC.measureText(olCur + olToks[olti]).width <= olWMax) {
|
|
5236
5554
|
olCur += olToks[olti]
|
|
5237
5555
|
} else {
|
|
5238
5556
|
olWrapped.push(olCur)
|
|
@@ -5282,10 +5600,10 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
|
|
|
5282
5600
|
olFx = { k: olFx.k, u: olFx.u, d: olFx.d, st: olFx.st, dur: olFx.dur, tt: olFx.tt, units: olRe, n: olReN }
|
|
5283
5601
|
}
|
|
5284
5602
|
var olLWs = null, olMaxW = 0
|
|
5285
|
-
if (ol.box || ol.align || olFx
|
|
5603
|
+
if (ol.box || ol.align || olFx) {
|
|
5286
5604
|
olLWs = []
|
|
5287
5605
|
for (var olwi = 0; olwi < olLines.length; olwi++) {
|
|
5288
|
-
var olw =
|
|
5606
|
+
var olw = ovC.measureText(olLines[olwi]).width
|
|
5289
5607
|
olLWs.push(olw)
|
|
5290
5608
|
if (olw > olMaxW) olMaxW = olw
|
|
5291
5609
|
}
|
|
@@ -5321,12 +5639,6 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
|
|
|
5321
5639
|
: (olMaxW - olLWs[ok]) / 2
|
|
5322
5640
|
}
|
|
5323
5641
|
var olLY = olY0 + ok * olLH
|
|
5324
|
-
if (olEm) {
|
|
5325
|
-
// Runs draw LEFT-aligned from the centred line's left edge.
|
|
5326
|
-
ovC.textAlign = 'left'
|
|
5327
|
-
olDraw(olLines[ok], olXof - olLWs[ok] / 2, olLY, false)
|
|
5328
|
-
continue
|
|
5329
|
-
}
|
|
5330
5642
|
if (ol.stroke) {
|
|
5331
5643
|
ovC.strokeStyle = ol.stroke.c
|
|
5332
5644
|
ovC.lineWidth = ol.stroke.w * olMS * s
|
|
@@ -5363,10 +5675,7 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
|
|
|
5363
5675
|
: olIdx
|
|
5364
5676
|
var olT2 = olT - olOrd * olFx.st
|
|
5365
5677
|
var olNext = olPref + olUs[ou]
|
|
5366
|
-
var olNW =
|
|
5367
|
-
// The emphasis state this unit starts in (a char unit inside a
|
|
5368
|
-
// marked word carries no mark of its own).
|
|
5369
|
-
var olUB = olEm ? olStateAfter(olPref) : false
|
|
5678
|
+
var olNW = ovC.measureText(olNext).width
|
|
5370
5679
|
var olUW = olNW - olPW
|
|
5371
5680
|
var olUX = olXb + olPW
|
|
5372
5681
|
var olUA = 1, olUu = 1
|
|
@@ -5395,11 +5704,6 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
|
|
|
5395
5704
|
ovC.filter = 'blur(' + ((1 - olUu) * olPx * 0.12).toFixed(2) + 'px)'
|
|
5396
5705
|
}
|
|
5397
5706
|
}
|
|
5398
|
-
if (olEm) {
|
|
5399
|
-
olDraw(olUnit, olUX, olLY2, olUB)
|
|
5400
|
-
ovC.restore()
|
|
5401
|
-
continue
|
|
5402
|
-
}
|
|
5403
5707
|
if (ol.stroke) {
|
|
5404
5708
|
ovC.strokeStyle = ol.stroke.c
|
|
5405
5709
|
ovC.lineWidth = ol.stroke.w * olMS * s
|
|
@@ -5414,7 +5718,7 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
|
|
|
5414
5718
|
ovC.restore()
|
|
5415
5719
|
}
|
|
5416
5720
|
ov.sig = ovSig
|
|
5417
|
-
ov.
|
|
5721
|
+
ov.wasAnim = olAnim
|
|
5418
5722
|
if (ov.texture) ov.texture.needsUpdate = true
|
|
5419
5723
|
}
|
|
5420
5724
|
|
|
@@ -8367,27 +8671,16 @@ function studioLayerData(layers, duration, pins) {
|
|
|
8367
8671
|
}
|
|
8368
8672
|
const st = resolveOverlayStyle(o);
|
|
8369
8673
|
const bx = resolveOverlayBox(o);
|
|
8370
|
-
const
|
|
8674
|
+
const rt = styledTextOf(o);
|
|
8371
8675
|
return {
|
|
8372
8676
|
...base,
|
|
8373
8677
|
text: o.text,
|
|
8374
|
-
// The
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
//
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
w: em.weight,
|
|
8381
|
-
...em.color ? { c: em.color } : {},
|
|
8382
|
-
...em.face ? {
|
|
8383
|
-
face: {
|
|
8384
|
-
f: em.face.family,
|
|
8385
|
-
w: em.face.weight,
|
|
8386
|
-
u: em.face.url
|
|
8387
|
-
}
|
|
8388
|
-
} : {}
|
|
8389
|
-
}
|
|
8390
|
-
} : {},
|
|
8678
|
+
// The lines a person reads. A styled layer (rt) is painted from
|
|
8679
|
+
// its runs; these are then its words, for the signature.
|
|
8680
|
+
lines: overlayLines(stripEmphasis(overlayDisplayText(o))),
|
|
8681
|
+
// The styled payload, only when the layer is set in more than
|
|
8682
|
+
// one style: a plain clip's data is unchanged.
|
|
8683
|
+
...rt ? { rt } : {},
|
|
8391
8684
|
fs: st.size,
|
|
8392
8685
|
weight: st.weight,
|
|
8393
8686
|
stack: st.stack,
|
|
@@ -10520,6 +10813,68 @@ function applyLook(frame, look, size, video, placement) {
|
|
|
10520
10813
|
return out;
|
|
10521
10814
|
}
|
|
10522
10815
|
|
|
10816
|
+
// src/richText/caret.ts
|
|
10817
|
+
function caretStops(line, measure) {
|
|
10818
|
+
const stops = [{ o: line.a, x: 0 }];
|
|
10819
|
+
for (const fr of line.frags) {
|
|
10820
|
+
let at = 0;
|
|
10821
|
+
for (const g of graphemesOf(fr.t)) {
|
|
10822
|
+
at += g.length;
|
|
10823
|
+
stops.push({
|
|
10824
|
+
o: line.a + fr.o + at,
|
|
10825
|
+
x: fr.x + measure(fr.t.slice(0, at), fr.f || 0)
|
|
10826
|
+
});
|
|
10827
|
+
}
|
|
10828
|
+
}
|
|
10829
|
+
return stops;
|
|
10830
|
+
}
|
|
10831
|
+
function lineOfOffset(layout, offset) {
|
|
10832
|
+
const lines = layout.lines;
|
|
10833
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
10834
|
+
if (offset >= lines[i].a) return i;
|
|
10835
|
+
}
|
|
10836
|
+
return 0;
|
|
10837
|
+
}
|
|
10838
|
+
function caretAt(layout, offset, measure) {
|
|
10839
|
+
const li = lineOfOffset(layout, offset);
|
|
10840
|
+
const stops = caretStops(layout.lines[li], measure);
|
|
10841
|
+
let x = stops[stops.length - 1].x;
|
|
10842
|
+
for (const s of stops) {
|
|
10843
|
+
if (s.o >= offset) {
|
|
10844
|
+
x = s.x;
|
|
10845
|
+
break;
|
|
10846
|
+
}
|
|
10847
|
+
}
|
|
10848
|
+
return { line: li, x };
|
|
10849
|
+
}
|
|
10850
|
+
function offsetAtX(line, x, measure) {
|
|
10851
|
+
const stops = caretStops(line, measure);
|
|
10852
|
+
let best = stops[0];
|
|
10853
|
+
for (const s of stops) {
|
|
10854
|
+
if (Math.abs(s.x - x) < Math.abs(best.x - x)) best = s;
|
|
10855
|
+
}
|
|
10856
|
+
return best.o;
|
|
10857
|
+
}
|
|
10858
|
+
function rangeRects(layout, start, end, measure, breakTail = 0) {
|
|
10859
|
+
const out = [];
|
|
10860
|
+
if (end <= start) return out;
|
|
10861
|
+
layout.lines.forEach((line, i) => {
|
|
10862
|
+
const lineEnd = line.a + line.n;
|
|
10863
|
+
if (end <= line.a || start > lineEnd) return;
|
|
10864
|
+
const stops = caretStops(line, measure);
|
|
10865
|
+
const xOf = (o) => {
|
|
10866
|
+
for (const s of stops) if (s.o >= o) return s.x;
|
|
10867
|
+
return stops[stops.length - 1].x;
|
|
10868
|
+
};
|
|
10869
|
+
const x0 = xOf(Math.max(start, line.a));
|
|
10870
|
+
const x1 = xOf(Math.min(end, lineEnd));
|
|
10871
|
+
const next = layout.lines[i + 1];
|
|
10872
|
+
const tail = next && next.a > lineEnd && end > lineEnd ? breakTail : 0;
|
|
10873
|
+
if (x1 + tail > x0) out.push({ line: i, x: x0, w: x1 - x0 + tail });
|
|
10874
|
+
});
|
|
10875
|
+
return out;
|
|
10876
|
+
}
|
|
10877
|
+
|
|
10523
10878
|
// src/timeline/lanes.ts
|
|
10524
10879
|
import {
|
|
10525
10880
|
mapTime as mapTime3,
|
|
@@ -11900,6 +12255,7 @@ export {
|
|
|
11900
12255
|
CURSOR_IDLE_FADE_OUT,
|
|
11901
12256
|
CURSOR_IDLE_HOLD,
|
|
11902
12257
|
DARK_GROUND,
|
|
12258
|
+
DECORATION_THICKNESS_EM,
|
|
11903
12259
|
DEFAULT_BROWSER_BAR,
|
|
11904
12260
|
DEFAULT_CAM_POSE,
|
|
11905
12261
|
DEFAULT_CAM_STYLE,
|
|
@@ -11937,6 +12293,7 @@ export {
|
|
|
11937
12293
|
FREEZE_DEFAULT_SECONDS,
|
|
11938
12294
|
FREEZE_SECONDS_MAX,
|
|
11939
12295
|
FREEZE_SECONDS_MIN,
|
|
12296
|
+
HIGHLIGHT_HALF_EM,
|
|
11940
12297
|
HOLD_DRIFT_MAX,
|
|
11941
12298
|
HOUSE_GRADIENT,
|
|
11942
12299
|
HOUSE_REGISTER,
|
|
@@ -11986,6 +12343,7 @@ export {
|
|
|
11986
12343
|
SPEED_SPAN_MIN,
|
|
11987
12344
|
STAGE_CLIP_PREFIX,
|
|
11988
12345
|
STILL_DEFAULT,
|
|
12346
|
+
STRIKE_OFFSET_EM,
|
|
11989
12347
|
STUDIO_ENTRY_ID,
|
|
11990
12348
|
STYLE_FIELDS,
|
|
11991
12349
|
TEXT3D_DEPTH_DEFAULT,
|
|
@@ -12010,6 +12368,7 @@ export {
|
|
|
12010
12368
|
TRANSITION_SECONDS_MAX,
|
|
12011
12369
|
TRANSITION_SECONDS_MIN,
|
|
12012
12370
|
TRANSITION_SPEED_MULT,
|
|
12371
|
+
UNDERLINE_OFFSET_EM,
|
|
12013
12372
|
WINDOW_FOCUS_MIN,
|
|
12014
12373
|
ZOOM_CHAIN_GAP,
|
|
12015
12374
|
ZOOM_EASE,
|
|
@@ -12053,6 +12412,8 @@ export {
|
|
|
12053
12412
|
cardInset,
|
|
12054
12413
|
cardPointToScreen,
|
|
12055
12414
|
cardPoseTrack,
|
|
12415
|
+
caretAt,
|
|
12416
|
+
caretStops,
|
|
12056
12417
|
clampCamFrac,
|
|
12057
12418
|
clampCamSize,
|
|
12058
12419
|
clampFocus,
|
|
@@ -12076,6 +12437,7 @@ export {
|
|
|
12076
12437
|
cursorFromRecords,
|
|
12077
12438
|
cursorFromTrace,
|
|
12078
12439
|
cursorIdleFade,
|
|
12440
|
+
decorationRect,
|
|
12079
12441
|
deltaE,
|
|
12080
12442
|
deriveViewportCrop,
|
|
12081
12443
|
destinationById,
|
|
@@ -12146,14 +12508,15 @@ export {
|
|
|
12146
12508
|
lastLayerEnd,
|
|
12147
12509
|
layerMedia,
|
|
12148
12510
|
layoutOf,
|
|
12511
|
+
layoutText,
|
|
12149
12512
|
levelForFocusFraction,
|
|
12513
|
+
lineOfOffset,
|
|
12150
12514
|
liveZoomStyleName,
|
|
12151
12515
|
lookFromBrand,
|
|
12152
12516
|
lookKindForGround,
|
|
12153
12517
|
lowerProgramDoc,
|
|
12154
12518
|
lowerStudioDoc,
|
|
12155
12519
|
lowerToComposition,
|
|
12156
|
-
measureEmphasized,
|
|
12157
12520
|
mediaAtOutput,
|
|
12158
12521
|
mediaDuration,
|
|
12159
12522
|
mediaFrame,
|
|
@@ -12173,6 +12536,7 @@ export {
|
|
|
12173
12536
|
objectMotionBase,
|
|
12174
12537
|
objectMotionPoseAt,
|
|
12175
12538
|
objectsLane,
|
|
12539
|
+
offsetAtX,
|
|
12176
12540
|
outputDurationOf,
|
|
12177
12541
|
outputEnd,
|
|
12178
12542
|
outputRangeToSource,
|
|
@@ -12213,6 +12577,7 @@ export {
|
|
|
12213
12577
|
programStillTime,
|
|
12214
12578
|
projectFromArtifact,
|
|
12215
12579
|
pumpFreeChainGap,
|
|
12580
|
+
rangeRects,
|
|
12216
12581
|
ratedSegments,
|
|
12217
12582
|
recommendedExportResolution,
|
|
12218
12583
|
refillAudioBeds,
|
|
@@ -12245,8 +12610,10 @@ export {
|
|
|
12245
12610
|
studioAudioPlan,
|
|
12246
12611
|
studioEntry,
|
|
12247
12612
|
studioLayerData,
|
|
12613
|
+
styledTextOf,
|
|
12248
12614
|
tiltLane,
|
|
12249
12615
|
tiltTrackFromDoc,
|
|
12616
|
+
tokenRanges,
|
|
12250
12617
|
traceKindOf,
|
|
12251
12618
|
transitionMult,
|
|
12252
12619
|
transitionSeconds,
|