pixi-effects 0.8.0 → 0.9.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.cts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as AudioInspectOptions, a as AudioReport, b as AudioSourceReport, C as ContactSheetOptions, F as FrameEvent, I as InspectOptions, c as InspectReport, L as LayerInfo, M as Movie, d as MovieErrorEvent, e as MovieOptions, P as ProgressEvent, R as RenderOptions, S as SnapshotOptions, f as SoundMeasure, T as TimelineData, g as TimelineHtmlOptions, h as TimelineRow, i as TimelineSvgOptions, j as TimelineTransition, V as VolumeEvent } from './Movie-CQOhUmko.cjs';
1
+ export { A as AudioInspectOptions, a as AudioReport, b as AudioSourceReport, C as ContactSheetOptions, F as FrameEvent, I as InspectOptions, c as InspectReport, L as LayerInfo, M as Movie, d as MovieErrorEvent, e as MovieOptions, P as ProgressEvent, R as RenderOptions, S as SnapshotOptions, f as SoundMeasure, T as TimelineData, g as TimelineHtmlOptions, h as TimelineRow, i as TimelineSvgOptions, j as TimelineTransition, V as VolumeEvent } from './Movie-qGHp15c_.cjs';
2
2
  import { S as Sequence } from './Base-CSIulyIq.cjs';
3
3
  import { S as SequenceSpec, C as CompositionShape, I as ImageSequenceSpec, a as CameraSequenceSpec, b as SequenceCommon } from './types-oJijbn-K.cjs';
4
4
  export { A as ArcShapeSpec, c as AssetSpec, d as AudioAssetSpec, e as AudioSequenceSpec, f as AudioSfxSpec, g as ChromaKeyFilterSpec, h as CircleShapeSpec, i as CompositionSequenceSpec, j as CompositionSpec, k as CrossfadeTransition, l as CustomFilterSpec, D as DipTransition, m as DissolveTransition, E as EllipseShapeSpec, n as Expr, F as FilterSpec, G as GradientSpec, o as IrisTransition, K as Keyframe, L as LineShapeSpec, P as PathShapeSpec, p as PolygonShapeSpec, q as PropValue, r as Props, R as RectShapeSpec, s as SfxKnobs, t as SfxOptions, u as SfxPreset, v as SfxVoice, w as ShapeSequenceSpec, x as SlideTransition, T as TextSequenceSpec, y as TransitionCommon, z as TransitionSpec, V as VideoSequenceSpec, W as WipeTransition, Z as ZoomTransition } from './types-oJijbn-K.cjs';
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as AudioInspectOptions, a as AudioReport, b as AudioSourceReport, C as ContactSheetOptions, F as FrameEvent, I as InspectOptions, c as InspectReport, L as LayerInfo, M as Movie, d as MovieErrorEvent, e as MovieOptions, P as ProgressEvent, R as RenderOptions, S as SnapshotOptions, f as SoundMeasure, T as TimelineData, g as TimelineHtmlOptions, h as TimelineRow, i as TimelineSvgOptions, j as TimelineTransition, V as VolumeEvent } from './Movie-HF3pSGjQ.js';
1
+ export { A as AudioInspectOptions, a as AudioReport, b as AudioSourceReport, C as ContactSheetOptions, F as FrameEvent, I as InspectOptions, c as InspectReport, L as LayerInfo, M as Movie, d as MovieErrorEvent, e as MovieOptions, P as ProgressEvent, R as RenderOptions, S as SnapshotOptions, f as SoundMeasure, T as TimelineData, g as TimelineHtmlOptions, h as TimelineRow, i as TimelineSvgOptions, j as TimelineTransition, V as VolumeEvent } from './Movie-QMlFyHkf.js';
2
2
  import { S as Sequence } from './Base-DVgwyIUj.js';
3
3
  import { S as SequenceSpec, C as CompositionShape, I as ImageSequenceSpec, a as CameraSequenceSpec, b as SequenceCommon } from './types-oJijbn-K.js';
4
4
  export { A as ArcShapeSpec, c as AssetSpec, d as AudioAssetSpec, e as AudioSequenceSpec, f as AudioSfxSpec, g as ChromaKeyFilterSpec, h as CircleShapeSpec, i as CompositionSequenceSpec, j as CompositionSpec, k as CrossfadeTransition, l as CustomFilterSpec, D as DipTransition, m as DissolveTransition, E as EllipseShapeSpec, n as Expr, F as FilterSpec, G as GradientSpec, o as IrisTransition, K as Keyframe, L as LineShapeSpec, P as PathShapeSpec, p as PolygonShapeSpec, q as PropValue, r as Props, R as RectShapeSpec, s as SfxKnobs, t as SfxOptions, u as SfxPreset, v as SfxVoice, w as ShapeSequenceSpec, x as SlideTransition, T as TextSequenceSpec, y as TransitionCommon, z as TransitionSpec, V as VideoSequenceSpec, W as WipeTransition, Z as ZoomTransition } from './types-oJijbn-K.js';
package/dist/index.js CHANGED
@@ -1429,6 +1429,21 @@ function startWhenRunning(ctx, start, gesture) {
1429
1429
  }
1430
1430
  var GESTURES = ["pointerdown", "mousedown", "touchend", "keydown"];
1431
1431
 
1432
+ // src/core/poster.ts
1433
+ function normalizePoster(poster, duration, frameRate) {
1434
+ if (poster === void 0 || poster === null) return { seconds: null, frame: null };
1435
+ if (typeof poster !== "number" || !Number.isFinite(poster)) {
1436
+ console.warn(`pixi-effects: movie.init({ poster }): ${JSON.stringify(poster)} is not a time in seconds; ignored`);
1437
+ return { seconds: null, frame: null };
1438
+ }
1439
+ let seconds = poster < 0 ? Math.max(0, duration + poster) : poster;
1440
+ if (seconds > duration) {
1441
+ console.warn(`pixi-effects: movie.init({ poster }): the poster time ${poster} s is past the end of the movie (${duration} s); using the last frame`);
1442
+ seconds = duration;
1443
+ }
1444
+ return { seconds, frame: Math.round(seconds * frameRate) };
1445
+ }
1446
+
1432
1447
  // src/core/Movie.ts
1433
1448
  extensions.add(CullerPlugin);
1434
1449
  gsap.registerPlugin(PixiPlugin);
@@ -1442,6 +1457,11 @@ var Movie = class {
1442
1457
  audioSource = null;
1443
1458
  gainNode = null;
1444
1459
  _cancelAudioStart = null;
1460
+ /** The poster time in seconds (`movie.init({ poster })`), or null. */
1461
+ poster = null;
1462
+ _posterFrame = null;
1463
+ /** The canvas shows the poster picture while the playhead is still at frame 0 (like `<video poster>`): the first seek or play replaces it. */
1464
+ _atPoster = false;
1445
1465
  /** > 0 while the movie moves its own playhead (playback, render, snapshot, contactSheet): those are not the seeks `seeking` / `seeked` report. */
1446
1466
  _quiet = 0;
1447
1467
  _volume = 1;
@@ -1485,6 +1505,36 @@ var Movie = class {
1485
1505
  get isReady() {
1486
1506
  return this._initState === "ready";
1487
1507
  }
1508
+ /** The poster time as a frame number, or null. */
1509
+ get posterFrame() {
1510
+ return this._posterFrame;
1511
+ }
1512
+ /** Draw the poster frame on the canvas and leave the playhead where it is (frame 0): the picture before the movie plays. */
1513
+ async _showPoster() {
1514
+ if (this._posterFrame === null || !this.timeline) return;
1515
+ const back = this.currentFrame;
1516
+ this.currentFrame = this._posterFrame;
1517
+ try {
1518
+ this.timeline.time(this._posterFrame / this.frameRate);
1519
+ await this._awaitVideoFrames();
1520
+ this._updateSpace();
1521
+ this._renderNow();
1522
+ } finally {
1523
+ this.currentFrame = back;
1524
+ }
1525
+ this._atPoster = true;
1526
+ }
1527
+ async posterImage(opts = {}) {
1528
+ this._requireReady("posterImage");
1529
+ const back = this.currentFrame, wasAtPoster = this._atPoster;
1530
+ try {
1531
+ return await this.snapshot(this._posterFrame ?? 0, opts);
1532
+ } finally {
1533
+ this.currentFrame = back;
1534
+ if (wasAtPoster) await this._showPoster();
1535
+ else await this._quietly(() => this.gotoFrame(back, true));
1536
+ }
1537
+ }
1488
1538
  _ensureAudioContext() {
1489
1539
  if (!this._audioContext) {
1490
1540
  const Ctx = window.AudioContext ?? window.webkitAudioContext;
@@ -1493,7 +1543,7 @@ var Movie = class {
1493
1543
  return this._audioContext;
1494
1544
  }
1495
1545
  async init(options = {}) {
1496
- warnUnknownOptions("movie.init()", options, ["width", "height", "duration", "frameRate", "background", "canvas", "assets", "composition"]);
1546
+ warnUnknownOptions("movie.init()", options, ["width", "height", "duration", "frameRate", "background", "canvas", "assets", "composition", "poster"]);
1497
1547
  this._initState = "pending";
1498
1548
  try {
1499
1549
  this.width = options.width ?? 1920;
@@ -1501,6 +1551,9 @@ var Movie = class {
1501
1551
  this.duration = options.duration ?? 10;
1502
1552
  this.frameRate = options.frameRate ?? 30;
1503
1553
  this.totalFrames = Math.round(this.duration * this.frameRate);
1554
+ const poster = normalizePoster(options.poster, this.duration, this.frameRate);
1555
+ this.poster = poster.seconds;
1556
+ this._posterFrame = poster.frame;
1504
1557
  this.background = options.background ?? "#000000";
1505
1558
  this.timeline = gsap.timeline({ paused: true, defaults: { ease: "none" } });
1506
1559
  this.timeline.add(gsap.to({}, { duration: this.duration }));
@@ -1564,6 +1617,7 @@ var Movie = class {
1564
1617
  this._updateSpace();
1565
1618
  this._renderNow();
1566
1619
  this._initState = "ready";
1620
+ if (this._posterFrame !== null) await this._showPoster();
1567
1621
  this.emit("ready");
1568
1622
  } catch (err) {
1569
1623
  try {
@@ -1577,7 +1631,7 @@ var Movie = class {
1577
1631
  }
1578
1632
  async gotoFrame(frame, force = false) {
1579
1633
  if (this._initState !== "ready") return;
1580
- if (!force && this.currentFrame === frame) return;
1634
+ if (!force && !this._atPoster && this.currentFrame === frame) return;
1581
1635
  if (this._quiet > 0) return this._goto(frame);
1582
1636
  const target = Math.max(0, Math.min(frame, this.totalFrames));
1583
1637
  this.emit("seeking", { frame: target, totalFrames: this.totalFrames });
@@ -1597,6 +1651,7 @@ var Movie = class {
1597
1651
  this.emit("error", { where, message: error instanceof Error ? error.message : String(error), error });
1598
1652
  }
1599
1653
  async _goto(frame) {
1654
+ this._atPoster = false;
1600
1655
  this.currentFrame = Math.max(0, Math.min(frame, this.totalFrames));
1601
1656
  this.timeline.time(this.currentFrame / this.frameRate);
1602
1657
  await this._awaitVideoFrames();
@@ -1638,7 +1693,7 @@ var Movie = class {
1638
1693
  const g = sheet.getContext("2d");
1639
1694
  g.fillStyle = "#10131c";
1640
1695
  g.fillRect(0, 0, L.width, L.height);
1641
- const back = this.currentFrame;
1696
+ const back = this.currentFrame, wasAtPoster = this._atPoster;
1642
1697
  try {
1643
1698
  for (let i = 0; i < frames.length; i++) {
1644
1699
  const f = frames[i];
@@ -1651,7 +1706,8 @@ var Movie = class {
1651
1706
  g.fillText(`frame ${f} \xB7 ${(f / this.frameRate).toFixed(2)}s`, x + 8, y + LABEL_H / 2);
1652
1707
  }
1653
1708
  } finally {
1654
- await this._quietly(() => this.gotoFrame(back, true));
1709
+ if (wasAtPoster) await this._showPoster();
1710
+ else await this._quietly(() => this.gotoFrame(back, true));
1655
1711
  }
1656
1712
  return encodeCanvas(sheet, "image/png", opts.as ?? "blob");
1657
1713
  }