reframe-video 0.6.33 → 0.6.39

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/frame.js CHANGED
@@ -278,11 +278,68 @@ function compileScene(ir) {
278
278
  const grouping = { kind: tl.parallel ? "par" : "seq", children: tl.children };
279
279
  const natural = durationOf(grouping, 0);
280
280
  const k = tl.scale ?? (tl.duration !== void 0 ? tl.duration / Math.max(1e-9, natural) : 1);
281
- const beatStart = tl.at ?? start + (tl.gap ?? 0);
281
+ const at = typeof tl.at === "number" ? tl.at : void 0;
282
+ const beatStart = at ?? start + (tl.gap ?? 0);
282
283
  return beatStart + k * natural;
283
284
  }
284
285
  }
285
286
  };
287
+ let labelClock;
288
+ const anyAnchor = (tl) => tl.kind === "beat" && typeof tl.at === "string" || "children" in tl && tl.children.some(anyAnchor);
289
+ if (ir.timeline && anyAnchor(ir.timeline)) {
290
+ const clock = /* @__PURE__ */ new Map();
291
+ const clockWalk = (tl, start) => {
292
+ let end = start;
293
+ switch (tl.kind) {
294
+ case "seq": {
295
+ let t = start;
296
+ for (const c of orderBeats(tl.children)) t = clockWalk(c, t);
297
+ end = t;
298
+ break;
299
+ }
300
+ case "par": {
301
+ for (const c of tl.children) end = Math.max(end, clockWalk(c, start));
302
+ break;
303
+ }
304
+ case "stagger": {
305
+ tl.children.forEach((c, i) => {
306
+ end = Math.max(end, clockWalk(c, start + i * tl.interval));
307
+ });
308
+ break;
309
+ }
310
+ case "wait":
311
+ end = start + tl.duration;
312
+ break;
313
+ case "tween":
314
+ end = start + (tl.duration ?? DEFAULT_TWEEN_DURATION);
315
+ break;
316
+ case "motionPath":
317
+ end = start + (tl.duration ?? DEFAULT_MOTIONPATH_DURATION);
318
+ break;
319
+ case "to": {
320
+ const override = ir.states?.[tl.state] ?? {};
321
+ const si = tl.stagger ?? 0;
322
+ const targets = nodeOrder.filter((id) => id in override && (tl.filter === void 0 || tl.filter.includes(id)));
323
+ end = start + (tl.duration ?? DEFAULT_TO_DURATION) + Math.max(0, targets.length - 1) * si;
324
+ break;
325
+ }
326
+ case "beat": {
327
+ const grouping = { kind: tl.parallel ? "par" : "seq", children: tl.children };
328
+ const k = tl.scale ?? (tl.duration !== void 0 ? tl.duration / Math.max(1e-9, durationOf(grouping, 0)) : 1);
329
+ const inner = k === 1 ? grouping : scaleTimeline(grouping, k);
330
+ const at = typeof tl.at === "number" ? tl.at : void 0;
331
+ const beatStart = at ?? start + (tl.gap ?? 0);
332
+ end = clockWalk(inner, beatStart);
333
+ clock.set(tl.name, { t0: beatStart, t1: end });
334
+ break;
335
+ }
336
+ }
337
+ if ("label" in tl && tl.label !== void 0) clock.set(tl.label, { t0: start, t1: end });
338
+ return end;
339
+ };
340
+ clockWalk(ir.timeline, 0);
341
+ labelClock = clock;
342
+ }
286
343
  const walk = (tl, start) => {
287
344
  const end = walkInner(tl, start);
288
345
  if ("label" in tl && tl.label !== void 0) labelTimes.set(tl.label, { t0: start, t1: end });
@@ -299,7 +356,8 @@ function compileScene(ir) {
299
356
  const grouping = { kind: tl.parallel ? "par" : "seq", children: tl.children };
300
357
  const k = tl.scale ?? (tl.duration !== void 0 ? tl.duration / Math.max(1e-9, durationOf(grouping, 0)) : 1);
301
358
  const inner = k === 1 ? grouping : scaleTimeline(grouping, k);
302
- const beatStart = tl.at ?? start + (tl.gap ?? 0);
359
+ const anchored = typeof tl.at === "string" ? labelClock?.get(tl.at)?.t0 : tl.at;
360
+ const beatStart = anchored !== void 0 ? anchored + (typeof tl.at === "string" ? tl.gap ?? 0 : 0) : start + (tl.gap ?? 0);
303
361
  const end = walk(inner, beatStart);
304
362
  beatTimes.set(tl.name, { t0: beatStart, t1: end });
305
363
  labelTimes.set(tl.name, { t0: beatStart, t1: end });
@@ -500,6 +558,7 @@ ${problems.map((p) => ` - ${p}`).join("\n")}`);
500
558
  function validateScene(ir) {
501
559
  const problems = [];
502
560
  const nodeById = /* @__PURE__ */ new Map();
561
+ const startAnchors = [];
503
562
  const checkPaint = (where, value) => {
504
563
  if (typeof value !== "object" || value === null) return;
505
564
  const g = value;
@@ -532,6 +591,7 @@ function validateScene(ir) {
532
591
  if (typeof props.shadowBlur === "number" && props.shadowBlur < 0) problems.push(`node "${node.id}": shadowBlur must be >= 0`);
533
592
  if (typeof props.blend === "string" && !BLEND_MODES.has(props.blend)) problems.push(`node "${node.id}": unknown blend "${props.blend}" \u2014 use ${[...BLEND_MODES].join(", ")}`);
534
593
  if (typeof props.fit === "string" && !IMAGE_FITS.has(props.fit)) problems.push(`node "${node.id}": unknown fit "${props.fit}" \u2014 use ${[...IMAGE_FITS].join(", ")}`);
594
+ if (node.type === "video" && typeof node.props.start === "string") startAnchors.push({ id: node.id, at: node.props.start });
535
595
  if (node.type === "group") {
536
596
  const clip = node.props.clip;
537
597
  if (clip) {
@@ -592,6 +652,7 @@ function validateScene(ir) {
592
652
  );
593
653
  }
594
654
  const labels = /* @__PURE__ */ new Set();
655
+ const beatAnchors = [];
595
656
  const checkEase = (path2, ease) => {
596
657
  if (ease === void 0) return;
597
658
  if (typeof ease === "string") {
@@ -683,6 +744,7 @@ function validateScene(ir) {
683
744
  );
684
745
  }
685
746
  labels.add(tl.name);
747
+ if (typeof tl.at === "string") beatAnchors.push({ name: tl.name, at: tl.at, path: path2 });
686
748
  if (tl.duration !== void 0 && tl.duration <= 0) {
687
749
  problems.push(`${path2}: beat "${tl.name}" duration must be > 0`);
688
750
  }
@@ -701,6 +763,22 @@ function validateScene(ir) {
701
763
  }
702
764
  };
703
765
  if (ir.timeline) checkTimeline(ir.timeline, "timeline");
766
+ for (const a of beatAnchors) {
767
+ if (a.at === a.name) {
768
+ problems.push(`${a.path}: beat "${a.name}" at: "${a.at}" cannot anchor to itself`);
769
+ } else if (!labels.has(a.at)) {
770
+ problems.push(
771
+ `${a.path}: beat "${a.name}" at: "${a.at}" \u2014 unknown timeline label \u2014 known labels: ${[...labels].join(", ") || "(none)"}`
772
+ );
773
+ }
774
+ }
775
+ for (const a of startAnchors) {
776
+ if (!labels.has(a.at)) {
777
+ problems.push(
778
+ `video "${a.id}" start: "${a.at}" \u2014 unknown timeline label \u2014 known labels: ${[...labels].join(", ") || "(none)"}`
779
+ );
780
+ }
781
+ }
704
782
  for (const [i, b] of (ir.behaviors ?? []).entries()) {
705
783
  checkProps(`behaviors[${i}]`, b.target, { [b.prop]: 0 });
706
784
  }
@@ -891,7 +969,7 @@ ${stderr.slice(-2e3)}`))
891
969
  });
892
970
  }
893
971
  function neededSeconds(node, duration) {
894
- const start = node.props.start ?? 0;
972
+ const start = typeof node.props.start === "string" ? 0 : node.props.start ?? 0;
895
973
  const rate = node.props.rate ?? 1;
896
974
  const clipStart = node.props.clipStart ?? 0;
897
975
  return clipStart + Math.max(0, duration - start) * Math.max(0, rate) + 1 / 30;