pixi-effects 0.47.5 → 0.48.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/CHANGELOG.md +8 -0
- package/README.md +8 -6
- package/ai/chat-template.html +3 -3
- package/dist/Controller.cjs +3 -0
- package/dist/Controller.cjs.map +1 -1
- package/dist/Controller.js +3 -0
- package/dist/Controller.js.map +1 -1
- package/dist/{chunk-LHUIEFMH.js → chunk-GX2WQV4A.js} +43 -33
- package/dist/chunk-GX2WQV4A.js.map +1 -0
- package/dist/chunk-K3XOEC3C.js +53 -0
- package/dist/chunk-K3XOEC3C.js.map +1 -0
- package/dist/{chunk-2AT5WSSV.cjs → chunk-NGK4E536.cjs} +47 -37
- package/dist/chunk-NGK4E536.cjs.map +1 -0
- package/dist/chunk-VQXZ2NOI.cjs +56 -0
- package/dist/chunk-VQXZ2NOI.cjs.map +1 -0
- package/dist/index.cjs +30 -25
- package/dist/index.d.cts +18 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +2 -1
- package/dist/loader.css +1 -1
- package/dist/present.cjs +2 -1
- package/dist/present.cjs.map +1 -1
- package/dist/present.js +2 -1
- package/dist/present.js.map +1 -1
- package/docs/api.md +15 -0
- package/llms-full.txt +16 -1
- package/package.json +1 -1
- package/skills/pixi-effects/SKILL.md +1 -1
- package/skills/pixi-effects/template.html +6 -6
- package/dist/chunk-2AT5WSSV.cjs.map +0 -1
- package/dist/chunk-LHUIEFMH.js.map +0 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { CompositionSequence, maskSourceOf } from './chunk-UI7CEUTP.js';
|
|
2
|
+
import { loadMediabunny } from './chunk-K3XOEC3C.js';
|
|
2
3
|
import { EXPRESSION_NAMES, createTimeline, lengthen, ensureFilterLibrary, checkEase, parseEase, homeDistance, DEFAULT_FOV, random, noise, flattenSvgPath, trimPolylines, rand, DEG, timeRemapOf, contentLength, resolveAt, parseSpring, springDuration, spansMeta } from './chunk-4PYVHLIK.js';
|
|
3
4
|
import { analyzeAudio, fft, resampleThrough, playSpan, measureLoudness } from './chunk-G4PXCV2B.js';
|
|
4
5
|
import { usesAdvancedBlend, enableAdvancedBlend } from './chunk-JBDBICS2.js';
|
|
5
6
|
import { describeLayer } from './chunk-BFRWSV3R.js';
|
|
6
7
|
import { warnUnknownOptions, suggestName } from './chunk-WGRWFQOB.js';
|
|
7
8
|
import { extensions, CullerPlugin, Application, Container, Rectangle, Culler, CanvasTextMetrics, TextStyle, Assets, ExtensionType, Filter, Texture, UniformGroup, GpuProgram, GlProgram, defaultFilterVert, Text, CanvasTextGenerator, CanvasPool } from 'pixi.js';
|
|
8
|
-
import { Output, BufferTarget, CanvasSource, AudioBufferSource, Input, ALL_FORMATS, BlobSource, WavOutputFormat, Conversion, VideoSampleSink, OggOutputFormat, QUALITY_VERY_HIGH, QUALITY_HIGH, QUALITY_MEDIUM, QUALITY_LOW, QUALITY_VERY_LOW, MkvOutputFormat, WebMOutputFormat, MovOutputFormat, Mp4OutputFormat, canEncodeVideo, getFirstEncodableAudioCodec } from 'mediabunny';
|
|
9
9
|
|
|
10
10
|
// src/core/gpuShare.ts
|
|
11
11
|
function sharedGpuOf(renderer) {
|
|
@@ -41,7 +41,8 @@ function ensureLoadersRegistered(audioContext) {
|
|
|
41
41
|
extension: { type: ExtensionType.LoadParser, name: "pixi-effects-video", priority: 1 },
|
|
42
42
|
test: (url) => /\.(mp4|webm|mov|mkv)$/i.test(url),
|
|
43
43
|
async load(url) {
|
|
44
|
-
const blob = await fetch(url).then((r) => r.blob());
|
|
44
|
+
const [M, blob] = await Promise.all([loadMediabunny(), fetch(url).then((r) => r.blob())]);
|
|
45
|
+
const { Input, BlobSource, ALL_FORMATS, Output, WavOutputFormat, BufferTarget, Conversion, VideoSampleSink } = M;
|
|
45
46
|
const input = new Input({ source: new BlobSource(blob), formats: ALL_FORMATS });
|
|
46
47
|
const videoTrack = await input.getPrimaryVideoTrack();
|
|
47
48
|
if (!videoTrack || !await videoTrack.canDecode()) {
|
|
@@ -598,10 +599,10 @@ var AUDIO_PREFERENCE = {
|
|
|
598
599
|
mkv: ["opus", "vorbis", "aac", "flac", "mp3"],
|
|
599
600
|
ogg: ["opus", "vorbis", "flac"]
|
|
600
601
|
};
|
|
601
|
-
async function chooseAudioCodec(fmt, requested, container, audio, bitrate) {
|
|
602
|
+
async function chooseAudioCodec(M, fmt, requested, container, audio, bitrate) {
|
|
602
603
|
const supported = container.getSupportedAudioCodecs?.();
|
|
603
604
|
const preferred = AUDIO_PREFERENCE[fmt].filter((c) => !supported || supported.includes(c));
|
|
604
|
-
const canEncode = (list) => getFirstEncodableAudioCodec(list, { numberOfChannels: audio.numberOfChannels ?? 2, sampleRate: audio.sampleRate, bitrate });
|
|
605
|
+
const canEncode = (list) => M.getFirstEncodableAudioCodec(list, { numberOfChannels: audio.numberOfChannels ?? 2, sampleRate: audio.sampleRate, bitrate });
|
|
605
606
|
if (requested) {
|
|
606
607
|
if (await canEncode([requested])) return requested;
|
|
607
608
|
const alt = await canEncode(preferred.filter((c) => c !== requested));
|
|
@@ -614,27 +615,34 @@ async function chooseAudioCodec(fmt, requested, container, audio, bitrate) {
|
|
|
614
615
|
}
|
|
615
616
|
return chosen;
|
|
616
617
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
618
|
+
function qualityOf(M, name) {
|
|
619
|
+
switch (name) {
|
|
620
|
+
case "very-low":
|
|
621
|
+
return M.QUALITY_VERY_LOW;
|
|
622
|
+
case "low":
|
|
623
|
+
return M.QUALITY_LOW;
|
|
624
|
+
case "medium":
|
|
625
|
+
return M.QUALITY_MEDIUM;
|
|
626
|
+
case "very-high":
|
|
627
|
+
return M.QUALITY_VERY_HIGH;
|
|
628
|
+
default:
|
|
629
|
+
return M.QUALITY_HIGH;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
function bitrateOf(M, v) {
|
|
625
633
|
const b = parseBitrate(v);
|
|
626
|
-
return b.bps ?? (
|
|
634
|
+
return b.bps ?? qualityOf(M, b.quality ?? "high");
|
|
627
635
|
}
|
|
628
|
-
function makeOutputFormat(name) {
|
|
636
|
+
function makeOutputFormat(M, name) {
|
|
629
637
|
switch (name) {
|
|
630
638
|
case "mp4":
|
|
631
|
-
return new Mp4OutputFormat({ fastStart: "in-memory" });
|
|
639
|
+
return new M.Mp4OutputFormat({ fastStart: "in-memory" });
|
|
632
640
|
case "mov":
|
|
633
|
-
return new MovOutputFormat({ fastStart: "in-memory" });
|
|
641
|
+
return new M.MovOutputFormat({ fastStart: "in-memory" });
|
|
634
642
|
case "webm":
|
|
635
|
-
return new WebMOutputFormat();
|
|
643
|
+
return new M.WebMOutputFormat();
|
|
636
644
|
case "mkv":
|
|
637
|
-
return new MkvOutputFormat();
|
|
645
|
+
return new M.MkvOutputFormat();
|
|
638
646
|
}
|
|
639
647
|
}
|
|
640
648
|
function sliceAudio(buffer, fromSec, toSec, fadeIn, fadeOut) {
|
|
@@ -649,18 +657,19 @@ async function exportAudioOnly(movie, options, fmt, range2) {
|
|
|
649
657
|
throw new Error(`pixi-effects: render({ format: '${fmt}' }): this movie has no sound to export (add an audio layer, an sfx or a music score); for the picture use mp4, webm, mov or mkv`);
|
|
650
658
|
}
|
|
651
659
|
if (options.video) console.warn(`pixi-effects: render({ format: '${fmt}' }): video options are ignored, only the sound is written`);
|
|
660
|
+
const M = await loadMediabunny();
|
|
652
661
|
const audio = range2.partial ? sliceAudio(movie.audioBuffer, range2.fromSec, range2.toSec, range2.fromFrame > 0, range2.toFrame < movie.totalFrames) : movie.audioBuffer;
|
|
653
|
-
const container = fmt === "wav" ? new WavOutputFormat() : new OggOutputFormat();
|
|
662
|
+
const container = fmt === "wav" ? new M.WavOutputFormat() : new M.OggOutputFormat();
|
|
654
663
|
let codec;
|
|
655
664
|
if (fmt === "wav") {
|
|
656
665
|
codec = options.audio?.codec ?? "pcm-s16";
|
|
657
666
|
const held = container.getSupportedAudioCodecs();
|
|
658
667
|
if (!held.includes(codec)) throw new Error(`pixi-effects: render({ format: 'wav', audio: { codec: "${codec}" } }): wav holds ${held.join(", ")} (the usual is pcm-s16)`);
|
|
659
668
|
} else {
|
|
660
|
-
codec = await chooseAudioCodec("ogg", options.audio?.codec, container, audio, bitrateOf(options.audio?.bitrate
|
|
669
|
+
codec = await chooseAudioCodec(M, "ogg", options.audio?.codec, container, audio, bitrateOf(M, options.audio?.bitrate));
|
|
661
670
|
}
|
|
662
|
-
const output = new Output({ format: container, target: new BufferTarget() });
|
|
663
|
-
const source = new AudioBufferSource({ codec, ...fmt === "wav" ? {} : { bitrate: bitrateOf(options.audio?.bitrate
|
|
671
|
+
const output = new M.Output({ format: container, target: new M.BufferTarget() });
|
|
672
|
+
const source = new M.AudioBufferSource({ codec, ...fmt === "wav" ? {} : { bitrate: bitrateOf(M, options.audio?.bitrate) } });
|
|
664
673
|
output.addAudioTrack(source);
|
|
665
674
|
movie.emit("progress", { progress: 0, frame: range2.fromFrame, totalFrames: movie.totalFrames });
|
|
666
675
|
await output.start();
|
|
@@ -678,21 +687,22 @@ async function exportFrames(movie, options = {}) {
|
|
|
678
687
|
if (!["mp4", "mov", "webm", "mkv"].includes(fmt)) throw new Error(`pixi-effects: render({ format: "${String(fmt)}" }): use mp4, mov, webm, mkv (a picture) or wav, ogg (only the sound)`);
|
|
679
688
|
warnUnknownOptions("movie.render({ video })", options.video, ["codec", "bitrate", "hardware", "keyFrameInterval"]);
|
|
680
689
|
warnUnknownOptions("movie.render({ audio })", options.audio, ["codec", "bitrate"]);
|
|
681
|
-
const
|
|
690
|
+
const M = await loadMediabunny();
|
|
691
|
+
const videoBitrate = bitrateOf(M, eff.bitrate ?? "high");
|
|
682
692
|
const opts = {
|
|
683
693
|
format: fmt,
|
|
684
694
|
video: { codec: "", bitrate: videoBitrate },
|
|
685
695
|
audio: {
|
|
686
696
|
codec: options.audio?.codec ?? (fmt === "mp4" || fmt === "mov" ? "aac" : "opus"),
|
|
687
|
-
bitrate: bitrateOf(options.audio?.bitrate
|
|
697
|
+
bitrate: bitrateOf(M, options.audio?.bitrate)
|
|
688
698
|
}
|
|
689
699
|
};
|
|
690
|
-
const container = makeOutputFormat(opts.format);
|
|
700
|
+
const container = makeOutputFormat(M, opts.format);
|
|
691
701
|
const audio = movie.audioBuffer && range2.partial ? sliceAudio(movie.audioBuffer, range2.fromSec, range2.toSec, range2.fromFrame > 0, range2.toFrame < movie.totalFrames) : movie.audioBuffer;
|
|
692
|
-
if (audio) opts.audio.codec = await chooseAudioCodec(fmt, options.audio?.codec, container, audio, opts.audio.bitrate);
|
|
693
|
-
const output = new Output({
|
|
702
|
+
if (audio) opts.audio.codec = await chooseAudioCodec(M, fmt, options.audio?.codec, container, audio, opts.audio.bitrate);
|
|
703
|
+
const output = new M.Output({
|
|
694
704
|
format: container,
|
|
695
|
-
target: new BufferTarget()
|
|
705
|
+
target: new M.BufferTarget()
|
|
696
706
|
});
|
|
697
707
|
const mb = eff.motionBlur !== void 0 ? resolveMotionBlur(eff.motionBlur, "movie.render()") : movie.motionBlur ?? null;
|
|
698
708
|
const stage = movie.app.canvas;
|
|
@@ -704,7 +714,7 @@ async function exportFrames(movie, options = {}) {
|
|
|
704
714
|
fmt,
|
|
705
715
|
requested: options.video?.codec,
|
|
706
716
|
supported: container.getSupportedVideoCodecs(),
|
|
707
|
-
canEncode: (c) => canEncodeVideo(c, { width: picture.width, height: picture.height, bitrate: opts.video.bitrate })
|
|
717
|
+
canEncode: (c) => M.canEncodeVideo(c, { width: picture.width, height: picture.height, bitrate: opts.video.bitrate })
|
|
708
718
|
});
|
|
709
719
|
if (chosen.fellBackFrom) console.warn(`pixi-effects: this browser cannot encode ${chosen.fellBackFrom.toUpperCase()} video, so the ${fmt} carries ${chosen.codec.toUpperCase()} instead (name a codec with render({ video: { codec } }) to choose yourself).`);
|
|
710
720
|
opts.video.codec = chosen.codec;
|
|
@@ -712,14 +722,14 @@ async function exportFrames(movie, options = {}) {
|
|
|
712
722
|
if (hardware !== void 0 && !["no-preference", "prefer-hardware", "prefer-software"].includes(hardware)) {
|
|
713
723
|
throw new Error(`pixi-effects: render({ video: { hardware: "${String(hardware)}" } }): use 'prefer-hardware', 'prefer-software' or 'no-preference'`);
|
|
714
724
|
}
|
|
715
|
-
const canvasSource = new CanvasSource(picture, {
|
|
725
|
+
const canvasSource = new M.CanvasSource(picture, {
|
|
716
726
|
codec: opts.video.codec,
|
|
717
727
|
bitrate: opts.video.bitrate,
|
|
718
728
|
...hardware ? { hardwareAcceleration: hardware } : {}
|
|
719
729
|
});
|
|
720
730
|
output.addVideoTrack(canvasSource, { frameRate: movie.frameRate });
|
|
721
731
|
if (audio) {
|
|
722
|
-
const audioSource = new AudioBufferSource({
|
|
732
|
+
const audioSource = new M.AudioBufferSource({
|
|
723
733
|
codec: opts.audio.codec,
|
|
724
734
|
bitrate: opts.audio.bitrate
|
|
725
735
|
}, { startTimestamp: opts.audio.codec === "aac" ? -2112 / audio.sampleRate : 0 });
|
|
@@ -5013,5 +5023,5 @@ function withFade(spec, opts) {
|
|
|
5013
5023
|
}
|
|
5014
5024
|
|
|
5015
5025
|
export { Movie, animateText, audioEnvelope, bpmEnvelope, cameraPath, computeEnvelope, dismissLoader, failLoader, followPath, kenBurns, measureText, musicBuffer, musicEnvelope, musicEvents, orbit, parseEase2 as parseEase, particles, react, resolveLoader, samplePath, splitText, stagger, wiggle, withFade };
|
|
5016
|
-
//# sourceMappingURL=chunk-
|
|
5017
|
-
//# sourceMappingURL=chunk-
|
|
5026
|
+
//# sourceMappingURL=chunk-GX2WQV4A.js.map
|
|
5027
|
+
//# sourceMappingURL=chunk-GX2WQV4A.js.map
|