visualfries 0.1.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/LICENSE +21 -0
- package/README.md +213 -0
- package/dist/DIContainer.d.ts +4 -0
- package/dist/DIContainer.js +145 -0
- package/dist/SceneBuilder.svelte.d.ts +8574 -0
- package/dist/SceneBuilder.svelte.js +409 -0
- package/dist/adapters/subtitleHelpers.d.ts +2 -0
- package/dist/adapters/subtitleHelpers.js +187 -0
- package/dist/animations/AnimationContext.d.ts +17 -0
- package/dist/animations/AnimationContext.js +72 -0
- package/dist/animations/AnimationPresetsRegister.d.ts +362 -0
- package/dist/animations/AnimationPresetsRegister.js +20 -0
- package/dist/animations/AnimationSetup.d.ts +8 -0
- package/dist/animations/AnimationSetup.js +30 -0
- package/dist/animations/SplitTextCache.d.ts +28 -0
- package/dist/animations/SplitTextCache.js +68 -0
- package/dist/animations/animationBuilder.d.ts +31 -0
- package/dist/animations/animationBuilder.js +255 -0
- package/dist/animations/animationPreset.d.ts +7 -0
- package/dist/animations/animationPreset.js +31 -0
- package/dist/animations/builders/AnimationPresetFactory.d.ts +43 -0
- package/dist/animations/builders/AnimationPresetFactory.js +139 -0
- package/dist/animations/builders/LineHighlighterAnimationBuilder.d.ts +16 -0
- package/dist/animations/builders/LineHighlighterAnimationBuilder.js +183 -0
- package/dist/animations/builders/WordHighlighterAnimationBuilder.d.ts +15 -0
- package/dist/animations/builders/WordHighlighterAnimationBuilder.js +180 -0
- package/dist/animations/engines/AnimationEngineAdaptor.d.ts +107 -0
- package/dist/animations/engines/AnimationEngineAdaptor.js +1 -0
- package/dist/animations/engines/GSAPEngineAdaptor.d.ts +21 -0
- package/dist/animations/engines/GSAPEngineAdaptor.js +145 -0
- package/dist/animations/presets/index.d.ts +2 -0
- package/dist/animations/presets/index.js +3 -0
- package/dist/animations/presets/lines.d.ts +52 -0
- package/dist/animations/presets/lines.js +547 -0
- package/dist/animations/presets/words.d.ts +31 -0
- package/dist/animations/presets/words.js +268 -0
- package/dist/animations/transformers/AnimationReferenceTransformer.d.ts +9 -0
- package/dist/animations/transformers/AnimationReferenceTransformer.js +114 -0
- package/dist/builders/PixiComponentBuilder.d.ts +63 -0
- package/dist/builders/PixiComponentBuilder.js +112 -0
- package/dist/builders/_ComponentState.svelte.d.ts +795 -0
- package/dist/builders/_ComponentState.svelte.js +203 -0
- package/dist/builders/html/HtmlBuilder.d.ts +66 -0
- package/dist/builders/html/HtmlBuilder.js +171 -0
- package/dist/builders/html/HtmlBuilderFactory.d.ts +27 -0
- package/dist/builders/html/HtmlBuilderFactory.js +30 -0
- package/dist/builders/html/StyleBuilder.d.ts +13 -0
- package/dist/builders/html/StyleBuilder.js +133 -0
- package/dist/builders/html/StyleProcessor.d.ts +9 -0
- package/dist/builders/html/StyleProcessor.js +1 -0
- package/dist/builders/html/TextComponentHtmlBuilder.d.ts +16 -0
- package/dist/builders/html/TextComponentHtmlBuilder.js +93 -0
- package/dist/builders/html/TextShadowBuilder.d.ts +60 -0
- package/dist/builders/html/TextShadowBuilder.js +227 -0
- package/dist/builders/html/processors/AppearanceStyleProcessor.d.ts +5 -0
- package/dist/builders/html/processors/AppearanceStyleProcessor.js +57 -0
- package/dist/builders/html/processors/TextAppearanceStyleProcessor.d.ts +5 -0
- package/dist/builders/html/processors/TextAppearanceStyleProcessor.js +37 -0
- package/dist/builders/html/processors/TextEffectsStyleProcessor.d.ts +6 -0
- package/dist/builders/html/processors/TextEffectsStyleProcessor.js +68 -0
- package/dist/commands/Command.d.ts +6 -0
- package/dist/commands/Command.js +1 -0
- package/dist/commands/CommandRunner.d.ts +28 -0
- package/dist/commands/CommandRunner.js +81 -0
- package/dist/commands/CommandTypes.d.ts +11 -0
- package/dist/commands/CommandTypes.js +13 -0
- package/dist/commands/PauseCommand.d.ts +4 -0
- package/dist/commands/PauseCommand.js +5 -0
- package/dist/commands/PlayCommand.d.ts +4 -0
- package/dist/commands/PlayCommand.js +6 -0
- package/dist/commands/RenderCommand.d.ts +15 -0
- package/dist/commands/RenderCommand.js +18 -0
- package/dist/commands/RenderFrameCommand.d.ts +17 -0
- package/dist/commands/RenderFrameCommand.js +93 -0
- package/dist/commands/ReplaceSourceOnTimeCommand.d.ts +4 -0
- package/dist/commands/ReplaceSourceOnTimeCommand.js +22 -0
- package/dist/commands/SeekCommand.d.ts +15 -0
- package/dist/commands/SeekCommand.js +39 -0
- package/dist/commands/UpdateComponentCommand.d.ts +4 -0
- package/dist/commands/UpdateComponentCommand.js +17 -0
- package/dist/components/AnimatedGIF.d.ts +201 -0
- package/dist/components/AnimatedGIF.js +391 -0
- package/dist/components/Component.svelte.d.ts +33 -0
- package/dist/components/Component.svelte.js +152 -0
- package/dist/components/ComponentContext.svelte.d.ts +33 -0
- package/dist/components/ComponentContext.svelte.js +105 -0
- package/dist/components/hooks/AnimationHook.d.ts +25 -0
- package/dist/components/hooks/AnimationHook.js +180 -0
- package/dist/components/hooks/CanvasShapeHook.d.ts +12 -0
- package/dist/components/hooks/CanvasShapeHook.js +229 -0
- package/dist/components/hooks/HtmlAnimationHook.d.ts +8 -0
- package/dist/components/hooks/HtmlAnimationHook.js +70 -0
- package/dist/components/hooks/HtmlTextHook.d.ts +16 -0
- package/dist/components/hooks/HtmlTextHook.js +102 -0
- package/dist/components/hooks/HtmlToCanvasHook.d.ts +16 -0
- package/dist/components/hooks/HtmlToCanvasHook.js +148 -0
- package/dist/components/hooks/ImageHook.d.ts +10 -0
- package/dist/components/hooks/ImageHook.js +45 -0
- package/dist/components/hooks/MediaHook.d.ts +15 -0
- package/dist/components/hooks/MediaHook.js +252 -0
- package/dist/components/hooks/MediaSeekingHook.d.ts +12 -0
- package/dist/components/hooks/MediaSeekingHook.js +204 -0
- package/dist/components/hooks/PixiDisplayObjectHook.d.ts +15 -0
- package/dist/components/hooks/PixiDisplayObjectHook.js +77 -0
- package/dist/components/hooks/PixiGifHook.d.ts +15 -0
- package/dist/components/hooks/PixiGifHook.js +97 -0
- package/dist/components/hooks/PixiProgressShapeHook.d.ts +12 -0
- package/dist/components/hooks/PixiProgressShapeHook.js +128 -0
- package/dist/components/hooks/PixiSplitScreenDisplayObjectHook.d.ts +21 -0
- package/dist/components/hooks/PixiSplitScreenDisplayObjectHook.js +210 -0
- package/dist/components/hooks/PixiTextureHook.d.ts +7 -0
- package/dist/components/hooks/PixiTextureHook.js +29 -0
- package/dist/components/hooks/PixiVideoTextureHook.d.ts +10 -0
- package/dist/components/hooks/PixiVideoTextureHook.js +35 -0
- package/dist/components/hooks/SubtitlesHook.d.ts +88 -0
- package/dist/components/hooks/SubtitlesHook.js +199 -0
- package/dist/components/hooks/VerifyGifHook.d.ts +7 -0
- package/dist/components/hooks/VerifyGifHook.js +27 -0
- package/dist/components/hooks/VerifyImageHook.d.ts +7 -0
- package/dist/components/hooks/VerifyImageHook.js +27 -0
- package/dist/components/hooks/VerifyMediaHook.d.ts +7 -0
- package/dist/components/hooks/VerifyMediaHook.js +21 -0
- package/dist/components/hooks/shapes/progress/CustomProgressRenderer.d.ts +8 -0
- package/dist/components/hooks/shapes/progress/CustomProgressRenderer.js +53 -0
- package/dist/components/hooks/shapes/progress/DoubleProgressRenderer.d.ts +8 -0
- package/dist/components/hooks/shapes/progress/DoubleProgressRenderer.js +69 -0
- package/dist/components/hooks/shapes/progress/LinearProgressRenderer.d.ts +8 -0
- package/dist/components/hooks/shapes/progress/LinearProgressRenderer.js +60 -0
- package/dist/components/hooks/shapes/progress/PerimeterProgressRenderer.d.ts +9 -0
- package/dist/components/hooks/shapes/progress/PerimeterProgressRenderer.js +213 -0
- package/dist/components/hooks/shapes/progress/ProgressRenderer.d.ts +17 -0
- package/dist/components/hooks/shapes/progress/ProgressRenderer.js +75 -0
- package/dist/components/hooks/shapes/progress/RadialProgressRenderer.d.ts +8 -0
- package/dist/components/hooks/shapes/progress/RadialProgressRenderer.js +50 -0
- package/dist/components/hooks/shapes/progress/index.d.ts +6 -0
- package/dist/components/hooks/shapes/progress/index.js +6 -0
- package/dist/composers/componentComposer.d.ts +55 -0
- package/dist/composers/componentComposer.js +118 -0
- package/dist/composers/layerComposer.d.ts +46 -0
- package/dist/composers/layerComposer.js +79 -0
- package/dist/composers/sceneComposer.d.ts +48 -0
- package/dist/composers/sceneComposer.js +92 -0
- package/dist/constants.d.ts +12 -0
- package/dist/constants.js +14 -0
- package/dist/directors/ComponentDirector.d.ts +20 -0
- package/dist/directors/ComponentDirector.js +86 -0
- package/dist/factories/SceneBuilderFactory.d.ts +15 -0
- package/dist/factories/SceneBuilderFactory.js +51 -0
- package/dist/fonts/GoogleFontsProvider.d.ts +12 -0
- package/dist/fonts/GoogleFontsProvider.js +125 -0
- package/dist/fonts/fontLoader.d.ts +15 -0
- package/dist/fonts/fontLoader.js +41 -0
- package/dist/fonts/types.d.ts +1 -0
- package/dist/fonts/types.js +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +14 -0
- package/dist/layers/Layer.svelte.d.ts +8492 -0
- package/dist/layers/Layer.svelte.js +125 -0
- package/dist/managers/AppManager.svelte.d.ts +23 -0
- package/dist/managers/AppManager.svelte.js +89 -0
- package/dist/managers/ComponentsManager.svelte.d.ts +49 -0
- package/dist/managers/ComponentsManager.svelte.js +247 -0
- package/dist/managers/DomManager.d.ts +18 -0
- package/dist/managers/DomManager.js +73 -0
- package/dist/managers/EventManager.d.ts +7 -0
- package/dist/managers/EventManager.js +22 -0
- package/dist/managers/LayersManager.svelte.d.ts +8499 -0
- package/dist/managers/LayersManager.svelte.js +176 -0
- package/dist/managers/MediaManager.d.ts +32 -0
- package/dist/managers/MediaManager.js +243 -0
- package/dist/managers/RenderManager.d.ts +23 -0
- package/dist/managers/RenderManager.js +59 -0
- package/dist/managers/StateManager.svelte.d.ts +8746 -0
- package/dist/managers/StateManager.svelte.js +272 -0
- package/dist/managers/SubtitlesManager.svelte.d.ts +261 -0
- package/dist/managers/SubtitlesManager.svelte.js +1385 -0
- package/dist/managers/TimeManager.svelte.d.ts +6 -0
- package/dist/managers/TimeManager.svelte.js +18 -0
- package/dist/managers/TimelineManager.svelte.d.ts +25 -0
- package/dist/managers/TimelineManager.svelte.js +152 -0
- package/dist/registers.d.ts +12 -0
- package/dist/registers.js +29 -0
- package/dist/schemas/runtime/index.d.ts +3 -0
- package/dist/schemas/runtime/index.js +4 -0
- package/dist/schemas/runtime/types.d.ts +323 -0
- package/dist/schemas/runtime/types.js +12 -0
- package/dist/schemas/scene/animations.d.ts +89738 -0
- package/dist/schemas/scene/animations.js +211 -0
- package/dist/schemas/scene/components.js +515 -0
- package/dist/schemas/scene/core.js +160 -0
- package/dist/schemas/scene/index.d.ts +22 -0
- package/dist/schemas/scene/index.js +10 -0
- package/dist/schemas/scene/properties.d.ts +914 -0
- package/dist/schemas/scene/properties.js +398 -0
- package/dist/schemas/scene/subtitles.d.ts +1141 -0
- package/dist/schemas/scene/subtitles.js +111 -0
- package/dist/schemas/scene/utils.d.ts +1 -0
- package/dist/schemas/scene/utils.js +5 -0
- package/dist/seeds/SeedFactory.d.ts +59 -0
- package/dist/seeds/SeedFactory.js +99 -0
- package/dist/seeds/index.d.ts +8 -0
- package/dist/seeds/index.js +8 -0
- package/dist/transformers/ColorTransformer.d.ts +5 -0
- package/dist/transformers/ColorTransformer.js +67 -0
- package/dist/transformers/PixiColorTransformer.d.ts +22 -0
- package/dist/transformers/PixiColorTransformer.js +104 -0
- package/dist/utils/canvas.d.ts +6 -0
- package/dist/utils/canvas.js +18 -0
- package/dist/utils/document.d.ts +2 -0
- package/dist/utils/document.js +36 -0
- package/dist/utils/emoji.d.ts +10 -0
- package/dist/utils/emoji.js +51 -0
- package/dist/utils/html.d.ts +4 -0
- package/dist/utils/html.js +45 -0
- package/dist/utils/svgGenerator.d.ts +20 -0
- package/dist/utils/svgGenerator.js +103 -0
- package/dist/utils/utils.d.ts +5 -0
- package/dist/utils/utils.js +125 -0
- package/package.json +96 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
import { Sprite } from "pixi.js-legacy";
|
|
2
|
+
import { Texture, Renderer, settings, SCALE_MODES, Ticker, UPDATE_PRIORITY, } from "pixi.js-legacy";
|
|
3
|
+
import { parseGIF, decompressFrames } from "gifuct-js";
|
|
4
|
+
/**
|
|
5
|
+
* Runtime object to play animated GIFs. This object is similar to an AnimatedSprite.
|
|
6
|
+
* It support playback (seek, play, stop) as well as animation speed and looping.
|
|
7
|
+
* @see Thanks to {@link https://github.com/matt-way/gifuct-js/ gifuct-js}
|
|
8
|
+
*/
|
|
9
|
+
class AnimatedGIF extends Sprite {
|
|
10
|
+
/**
|
|
11
|
+
* Default options for all AnimatedGIF objects.
|
|
12
|
+
* @property {PIXI.SCALE_MODES} [scaleMode=PIXI.SCALE_MODES.LINEAR] - Scale mode to use for the texture.
|
|
13
|
+
* @property {boolean} [loop=true] - To enable looping.
|
|
14
|
+
* @property {number} [animationSpeed=1] - Speed of the animation.
|
|
15
|
+
* @property {boolean} [autoUpdate=true] - Set to `false` to manage updates yourself.
|
|
16
|
+
* @property {boolean} [autoPlay=true] - To start playing right away.
|
|
17
|
+
* @property {Function} [onComplete=null] - The completed callback, optional.
|
|
18
|
+
* @property {Function} [onLoop=null] - The loop callback, optional.
|
|
19
|
+
* @property {Function} [onFrameChange=null] - The frame callback, optional.
|
|
20
|
+
* @property {number} [fps=30] - Fallback FPS if GIF contains no time information.
|
|
21
|
+
*/
|
|
22
|
+
static defaultOptions = {
|
|
23
|
+
scaleMode: SCALE_MODES.LINEAR,
|
|
24
|
+
fps: 30,
|
|
25
|
+
loop: true,
|
|
26
|
+
animationSpeed: 1,
|
|
27
|
+
autoPlay: true,
|
|
28
|
+
autoUpdate: true,
|
|
29
|
+
onComplete: null,
|
|
30
|
+
onFrameChange: null,
|
|
31
|
+
onLoop: null,
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* The speed that the animation will play at. Higher is faster, lower is slower.
|
|
35
|
+
* @default 1
|
|
36
|
+
*/
|
|
37
|
+
animationSpeed = 1;
|
|
38
|
+
/**
|
|
39
|
+
* Whether or not the animate sprite repeats after playing.
|
|
40
|
+
* @default true
|
|
41
|
+
*/
|
|
42
|
+
loop = true;
|
|
43
|
+
/**
|
|
44
|
+
* User-assigned function to call when animation finishes playing. This only happens
|
|
45
|
+
* if loop is set to `false`.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* animation.onComplete = () => {
|
|
49
|
+
* // finished!
|
|
50
|
+
* };
|
|
51
|
+
*/
|
|
52
|
+
onComplete;
|
|
53
|
+
/**
|
|
54
|
+
* User-assigned function to call when animation changes which texture is being rendered.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* animation.onFrameChange = () => {
|
|
58
|
+
* // updated!
|
|
59
|
+
* };
|
|
60
|
+
*/
|
|
61
|
+
onFrameChange;
|
|
62
|
+
/**
|
|
63
|
+
* User-assigned function to call when `loop` is true, and animation is played and
|
|
64
|
+
* loops around to start again. This only happens if loop is set to `true`.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* animation.onLoop = () => {
|
|
68
|
+
* // looped!
|
|
69
|
+
* };
|
|
70
|
+
*/
|
|
71
|
+
onLoop;
|
|
72
|
+
/** The total duration of animation in milliseconds. */
|
|
73
|
+
duration = 0;
|
|
74
|
+
/** Whether to play the animation after constructing. */
|
|
75
|
+
autoPlay = true;
|
|
76
|
+
/** Collection of frame to render. */
|
|
77
|
+
_frames;
|
|
78
|
+
/** Drawing context reference. */
|
|
79
|
+
_context;
|
|
80
|
+
/** Dirty means the image needs to be redrawn. Set to `true` to force redraw. */
|
|
81
|
+
dirty = false;
|
|
82
|
+
/** The current frame number (zero-based index). */
|
|
83
|
+
_currentFrame = 0;
|
|
84
|
+
/** `true` uses PIXI.Ticker.shared to auto update animation time.*/
|
|
85
|
+
_autoUpdate = false;
|
|
86
|
+
/** `true` if the instance is currently connected to PIXI.Ticker.shared to auto update animation time. */
|
|
87
|
+
_isConnectedToTicker = false;
|
|
88
|
+
/** If animation is currently playing. */
|
|
89
|
+
_playing = false;
|
|
90
|
+
/** Current playback position in milliseconds. */
|
|
91
|
+
_currentTime = 0;
|
|
92
|
+
/**
|
|
93
|
+
* Create an animated GIF animation from a GIF image's ArrayBuffer. The easiest way to get
|
|
94
|
+
* the buffer is to use Assets.
|
|
95
|
+
* @example
|
|
96
|
+
* import { Assets } from 'pixi.js';
|
|
97
|
+
* import '@pixi/gif';
|
|
98
|
+
*
|
|
99
|
+
* const gif = await Assets.load('file.gif');
|
|
100
|
+
* @param buffer - GIF image arraybuffer from Assets.
|
|
101
|
+
* @param options - Options to use.
|
|
102
|
+
* @returns
|
|
103
|
+
*/
|
|
104
|
+
static fromBuffer(buffer, options) {
|
|
105
|
+
if (!buffer || buffer.byteLength === 0) {
|
|
106
|
+
throw new Error("Invalid buffer");
|
|
107
|
+
}
|
|
108
|
+
// fix https://github.com/matt-way/gifuct-js/issues/30
|
|
109
|
+
const validateAndFix = (gif) => {
|
|
110
|
+
let currentGce = null;
|
|
111
|
+
for (const frame of gif.frames) {
|
|
112
|
+
currentGce = frame.gce ?? currentGce;
|
|
113
|
+
// fix loosing graphic control extension for same frames
|
|
114
|
+
if ("image" in frame && !("gce" in frame)) {
|
|
115
|
+
frame.gce = currentGce;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
const gif = parseGIF(buffer);
|
|
120
|
+
validateAndFix(gif);
|
|
121
|
+
const gifFrames = decompressFrames(gif, true);
|
|
122
|
+
const frames = [];
|
|
123
|
+
// Temporary canvases required for compositing frames
|
|
124
|
+
const canvas = document.createElement("canvas");
|
|
125
|
+
const context = canvas.getContext("2d", {
|
|
126
|
+
willReadFrequently: true,
|
|
127
|
+
});
|
|
128
|
+
const patchCanvas = document.createElement("canvas");
|
|
129
|
+
const patchContext = patchCanvas.getContext("2d");
|
|
130
|
+
canvas.width = gif.lsd.width;
|
|
131
|
+
canvas.height = gif.lsd.height;
|
|
132
|
+
let time = 0;
|
|
133
|
+
let previousFrame = null;
|
|
134
|
+
// Some GIFs have a non-zero frame delay, so we need to calculate the fallback
|
|
135
|
+
const { fps } = Object.assign({}, AnimatedGIF.defaultOptions, options);
|
|
136
|
+
const defaultDelay = 1000 / fps;
|
|
137
|
+
// Precompute each frame and store as ImageData
|
|
138
|
+
for (let i = 0; i < gifFrames.length; i++) {
|
|
139
|
+
// Some GIF's omit the disposalType, so let's assume clear if missing
|
|
140
|
+
const { disposalType = 2, delay = defaultDelay, patch, dims: { width, height, left, top }, } = gifFrames[i];
|
|
141
|
+
patchCanvas.width = width;
|
|
142
|
+
patchCanvas.height = height;
|
|
143
|
+
patchContext.clearRect(0, 0, width, height);
|
|
144
|
+
const patchData = patchContext.createImageData(width, height);
|
|
145
|
+
patchData.data.set(patch);
|
|
146
|
+
patchContext.putImageData(patchData, 0, 0);
|
|
147
|
+
if (disposalType === 3) {
|
|
148
|
+
previousFrame = context.getImageData(0, 0, canvas.width, canvas.height);
|
|
149
|
+
}
|
|
150
|
+
context.drawImage(patchCanvas, left, top);
|
|
151
|
+
const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
|
|
152
|
+
if (disposalType === 2) {
|
|
153
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
154
|
+
}
|
|
155
|
+
else if (disposalType === 3) {
|
|
156
|
+
context.putImageData(previousFrame, 0, 0);
|
|
157
|
+
}
|
|
158
|
+
frames.push({
|
|
159
|
+
start: time,
|
|
160
|
+
end: time + delay,
|
|
161
|
+
imageData,
|
|
162
|
+
});
|
|
163
|
+
time += delay;
|
|
164
|
+
}
|
|
165
|
+
// clear the canvases
|
|
166
|
+
canvas.width = canvas.height = 0;
|
|
167
|
+
patchCanvas.width = patchCanvas.height = 0;
|
|
168
|
+
const { width, height } = gif.lsd;
|
|
169
|
+
return new AnimatedGIF(frames, { width, height, ...options });
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* @param frames - Data of the GIF image.
|
|
173
|
+
* @param options - Options for the AnimatedGIF
|
|
174
|
+
*/
|
|
175
|
+
constructor(frames, options) {
|
|
176
|
+
super(Texture.EMPTY);
|
|
177
|
+
// Get the options, apply defaults
|
|
178
|
+
const { scaleMode, width, height, ...rest } = Object.assign({}, AnimatedGIF.defaultOptions, options);
|
|
179
|
+
// Create the texture
|
|
180
|
+
const canvas = document.createElement("canvas");
|
|
181
|
+
const context = canvas.getContext("2d");
|
|
182
|
+
canvas.width = width;
|
|
183
|
+
canvas.height = height;
|
|
184
|
+
this.texture = Texture.from(canvas, { scaleMode });
|
|
185
|
+
this.duration = frames[frames.length - 1].end;
|
|
186
|
+
this._frames = frames;
|
|
187
|
+
this._context = context;
|
|
188
|
+
this._playing = false;
|
|
189
|
+
this._currentTime = 0;
|
|
190
|
+
this._isConnectedToTicker = false;
|
|
191
|
+
Object.assign(this, rest);
|
|
192
|
+
// Draw the first frame
|
|
193
|
+
this.currentFrame = 0;
|
|
194
|
+
if (rest.autoPlay) {
|
|
195
|
+
this.play();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/** Stops the animation. */
|
|
199
|
+
stop() {
|
|
200
|
+
if (!this._playing) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
this._playing = false;
|
|
204
|
+
if (this._autoUpdate && this._isConnectedToTicker) {
|
|
205
|
+
Ticker.shared.remove(this.update, this);
|
|
206
|
+
this._isConnectedToTicker = false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/** Plays the animation. */
|
|
210
|
+
play() {
|
|
211
|
+
if (this._playing) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
this._playing = true;
|
|
215
|
+
if (this._autoUpdate && !this._isConnectedToTicker) {
|
|
216
|
+
Ticker.shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
|
|
217
|
+
this._isConnectedToTicker = true;
|
|
218
|
+
}
|
|
219
|
+
// If were on the last frame and stopped, play should resume from beginning
|
|
220
|
+
if (!this.loop && this.currentFrame === this._frames.length - 1) {
|
|
221
|
+
this._currentTime = 0;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Get the current progress of the animation from 0 to 1.
|
|
226
|
+
* @readonly
|
|
227
|
+
*/
|
|
228
|
+
get progress() {
|
|
229
|
+
return this._currentTime / this.duration;
|
|
230
|
+
}
|
|
231
|
+
/** `true` if the current animation is playing */
|
|
232
|
+
get playing() {
|
|
233
|
+
return this._playing;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Updates the object transform for rendering. You only need to call this
|
|
237
|
+
* if the `autoUpdate` property is set to `false`.
|
|
238
|
+
*
|
|
239
|
+
* @param deltaTime - Time since last tick.
|
|
240
|
+
*/
|
|
241
|
+
update(deltaTime) {
|
|
242
|
+
if (!this._playing) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const elapsed = (this.animationSpeed * deltaTime) /
|
|
246
|
+
settings.TARGET_FPMS;
|
|
247
|
+
const currentTime = this._currentTime + elapsed;
|
|
248
|
+
const localTime = currentTime % this.duration;
|
|
249
|
+
const localFrame = this._frames.findIndex((frame) => frame.start <= localTime && frame.end > localTime);
|
|
250
|
+
if (currentTime >= this.duration) {
|
|
251
|
+
if (this.loop) {
|
|
252
|
+
this._currentTime = localTime;
|
|
253
|
+
this.updateFrameIndex(localFrame);
|
|
254
|
+
this.onLoop?.();
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
this._currentTime = this.duration;
|
|
258
|
+
this.updateFrameIndex(this._frames.length - 1);
|
|
259
|
+
this.onComplete?.();
|
|
260
|
+
this.stop();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
this._currentTime = localTime;
|
|
265
|
+
this.updateFrameIndex(localFrame);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Redraw the current frame, is necessary for the animation to work when
|
|
270
|
+
*/
|
|
271
|
+
updateFrame() {
|
|
272
|
+
if (!this.dirty) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
// Update the current frame
|
|
276
|
+
const { imageData } = this._frames[this._currentFrame];
|
|
277
|
+
this._context.putImageData(imageData, 0, 0);
|
|
278
|
+
// Workaround hack for Safari & iOS
|
|
279
|
+
// which fails to upload canvas after putImageData
|
|
280
|
+
// See: https://bugs.webkit.org/show_bug.cgi?id=229986
|
|
281
|
+
this._context.fillStyle = "transparent";
|
|
282
|
+
this._context.fillRect(0, 0, 0, 1);
|
|
283
|
+
this.texture.update();
|
|
284
|
+
// Mark as clean
|
|
285
|
+
this.dirty = false;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Renders the object using the WebGL renderer
|
|
289
|
+
*
|
|
290
|
+
* @param {PIXI.Renderer} renderer - The renderer
|
|
291
|
+
* @private
|
|
292
|
+
*/
|
|
293
|
+
_render(renderer) {
|
|
294
|
+
this.updateFrame();
|
|
295
|
+
super._render(renderer);
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Renders the object using the WebGL renderer
|
|
299
|
+
*
|
|
300
|
+
* @param {PIXI.CanvasRenderer} renderer - The renderer
|
|
301
|
+
* @private
|
|
302
|
+
*/
|
|
303
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
304
|
+
_renderCanvas(renderer) {
|
|
305
|
+
this.updateFrame();
|
|
306
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
307
|
+
// @ts-ignore
|
|
308
|
+
super._renderCanvas(renderer);
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Whether to use PIXI.Ticker.shared to auto update animation time.
|
|
312
|
+
* @default true
|
|
313
|
+
*/
|
|
314
|
+
get autoUpdate() {
|
|
315
|
+
return this._autoUpdate;
|
|
316
|
+
}
|
|
317
|
+
set autoUpdate(value) {
|
|
318
|
+
if (value !== this._autoUpdate) {
|
|
319
|
+
this._autoUpdate = value;
|
|
320
|
+
if (!this._autoUpdate && this._isConnectedToTicker) {
|
|
321
|
+
Ticker.shared.remove(this.update, this);
|
|
322
|
+
this._isConnectedToTicker = false;
|
|
323
|
+
}
|
|
324
|
+
else if (this._autoUpdate &&
|
|
325
|
+
!this._isConnectedToTicker &&
|
|
326
|
+
this._playing) {
|
|
327
|
+
Ticker.shared.add(this.update, this);
|
|
328
|
+
this._isConnectedToTicker = true;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/** Set the current frame number */
|
|
333
|
+
get currentFrame() {
|
|
334
|
+
return this._currentFrame;
|
|
335
|
+
}
|
|
336
|
+
set currentFrame(value) {
|
|
337
|
+
this.updateFrameIndex(value);
|
|
338
|
+
this._currentTime = this._frames[value].start;
|
|
339
|
+
}
|
|
340
|
+
/** Internally handle updating the frame index */
|
|
341
|
+
updateFrameIndex(value) {
|
|
342
|
+
if (value < 0 || value >= this._frames.length) {
|
|
343
|
+
throw new Error(`Frame index out of range, expecting 0 to ${this.totalFrames}, got ${value}`);
|
|
344
|
+
}
|
|
345
|
+
if (this._currentFrame !== value) {
|
|
346
|
+
this._currentFrame = value;
|
|
347
|
+
this.dirty = true;
|
|
348
|
+
this.onFrameChange?.(value);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Get the total number of frame in the GIF.
|
|
353
|
+
*/
|
|
354
|
+
get totalFrames() {
|
|
355
|
+
return this._frames.length;
|
|
356
|
+
}
|
|
357
|
+
/** Destroy and don't use after this. */
|
|
358
|
+
destroy() {
|
|
359
|
+
this.stop();
|
|
360
|
+
super.destroy(true);
|
|
361
|
+
const forceClear = null;
|
|
362
|
+
this._context = forceClear;
|
|
363
|
+
this._frames = forceClear;
|
|
364
|
+
this.onComplete = forceClear;
|
|
365
|
+
this.onFrameChange = forceClear;
|
|
366
|
+
this.onLoop = forceClear;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Cloning the animation is a useful way to create a duplicate animation.
|
|
370
|
+
* This maintains all the properties of the original animation but allows
|
|
371
|
+
* you to control playback independent of the original animation.
|
|
372
|
+
* If you want to create a simple copy, and not control independently,
|
|
373
|
+
* then you can simply create a new Sprite, e.g. `const sprite = new Sprite(animation.texture)`.
|
|
374
|
+
*/
|
|
375
|
+
clone() {
|
|
376
|
+
return new AnimatedGIF([...this._frames], {
|
|
377
|
+
autoUpdate: this._autoUpdate,
|
|
378
|
+
loop: this.loop,
|
|
379
|
+
autoPlay: this.autoPlay,
|
|
380
|
+
scaleMode: this.texture.baseTexture.scaleMode,
|
|
381
|
+
animationSpeed: this.animationSpeed,
|
|
382
|
+
width: this._context.canvas.width,
|
|
383
|
+
height: this._context.canvas.height,
|
|
384
|
+
onComplete: this.onComplete,
|
|
385
|
+
onFrameChange: this.onFrameChange,
|
|
386
|
+
onLoop: this.onLoop,
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
export { AnimatedGIF };
|
|
391
|
+
;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { IComponent, IComponentContext, ComponentProps, IComponentHook, ComponentRefreshType, ComponentData } from '..';
|
|
2
|
+
import type { AppearanceInput } from '..';
|
|
3
|
+
import { ComponentContext } from './ComponentContext.svelte.js';
|
|
4
|
+
export declare class Component implements IComponent {
|
|
5
|
+
#private;
|
|
6
|
+
constructor(cradle: {
|
|
7
|
+
componentState: ComponentProps;
|
|
8
|
+
componentContext: ComponentContext;
|
|
9
|
+
});
|
|
10
|
+
get id(): string;
|
|
11
|
+
get type(): "IMAGE" | "GIF" | "VIDEO" | "TEXT" | "SHAPE" | "AUDIO" | "COLOR" | "GRADIENT" | "SUBTITLES";
|
|
12
|
+
get props(): ComponentProps;
|
|
13
|
+
get displayObject(): import("pixi.js-legacy").Container<import("pixi.js-legacy").DisplayObject> | undefined;
|
|
14
|
+
get context(): IComponentContext;
|
|
15
|
+
get checksum(): string;
|
|
16
|
+
get autoRefresh(): boolean;
|
|
17
|
+
setAutoRefresh(enabled: boolean): Component;
|
|
18
|
+
private maybeRefresh;
|
|
19
|
+
addHook(hook: IComponentHook, priority?: number): void;
|
|
20
|
+
setup(): Promise<void>;
|
|
21
|
+
update(): Promise<void>;
|
|
22
|
+
refresh(type?: ComponentRefreshType): Promise<void>;
|
|
23
|
+
destroy(): Promise<void>;
|
|
24
|
+
updateAppearance(appearance: Partial<AppearanceInput>): Promise<Component>;
|
|
25
|
+
setStart(start: number): Component;
|
|
26
|
+
setEnd(end: number): Component;
|
|
27
|
+
updateText(text: string): Promise<Component>;
|
|
28
|
+
setText(text: string): Promise<Component>;
|
|
29
|
+
setVisible(visible: boolean): Promise<Component>;
|
|
30
|
+
setOrder(order: number): Promise<Component>;
|
|
31
|
+
onChange(callback: (changes: ComponentData) => void): () => void;
|
|
32
|
+
onTimelineChange(callback: (time: number) => void): () => void;
|
|
33
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { ComponentContext } from './ComponentContext.svelte.js';
|
|
2
|
+
export class Component {
|
|
3
|
+
#properties = $state({});
|
|
4
|
+
#context;
|
|
5
|
+
#hooks = [];
|
|
6
|
+
#autoRefresh = false;
|
|
7
|
+
#eventUnsubscribers = [];
|
|
8
|
+
constructor(cradle) {
|
|
9
|
+
this.#properties = cradle.componentState;
|
|
10
|
+
this.#context = cradle.componentContext;
|
|
11
|
+
this.#context.setComponentProps(this.#properties);
|
|
12
|
+
// Set up auto-refresh callback if ComponentState supports it
|
|
13
|
+
if ('setRefreshCallback' in this.#properties &&
|
|
14
|
+
typeof this.#properties.setRefreshCallback === 'function') {
|
|
15
|
+
this.#properties.setRefreshCallback(() => this.maybeRefresh());
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
get id() {
|
|
19
|
+
return this.#properties.id;
|
|
20
|
+
}
|
|
21
|
+
get type() {
|
|
22
|
+
return this.#properties.type;
|
|
23
|
+
}
|
|
24
|
+
get props() {
|
|
25
|
+
return this.#properties;
|
|
26
|
+
}
|
|
27
|
+
get displayObject() {
|
|
28
|
+
return this.#context.getResource('pixiRenderObject');
|
|
29
|
+
}
|
|
30
|
+
get context() {
|
|
31
|
+
return this.#context;
|
|
32
|
+
}
|
|
33
|
+
get checksum() {
|
|
34
|
+
return this.#properties.checksum;
|
|
35
|
+
}
|
|
36
|
+
get autoRefresh() {
|
|
37
|
+
return this.#autoRefresh;
|
|
38
|
+
}
|
|
39
|
+
setAutoRefresh(enabled) {
|
|
40
|
+
this.#autoRefresh = enabled;
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
async maybeRefresh() {
|
|
44
|
+
if (this.#autoRefresh) {
|
|
45
|
+
await this.refresh();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
addHook(hook, priority) {
|
|
49
|
+
const maxPriority = this.#hooks.length > 0 ? Math.max(...this.#hooks.map((h) => h.priority ?? 0)) : 0;
|
|
50
|
+
hook.priority = priority ? priority : maxPriority + 1;
|
|
51
|
+
this.#hooks.push(hook);
|
|
52
|
+
}
|
|
53
|
+
async #handle(type) {
|
|
54
|
+
const hooks = this.#hooks.filter((hook) => hook.types.includes(type));
|
|
55
|
+
await this.#context.runHooks(hooks, type);
|
|
56
|
+
}
|
|
57
|
+
async setup() {
|
|
58
|
+
this.#context.setComponentProps(this.#properties);
|
|
59
|
+
await this.#handle('setup');
|
|
60
|
+
}
|
|
61
|
+
async update() {
|
|
62
|
+
await this.#handle('update');
|
|
63
|
+
}
|
|
64
|
+
async refresh(type = 'refresh') {
|
|
65
|
+
this.#context.setComponentProps(this.#properties);
|
|
66
|
+
await this.#handle(type);
|
|
67
|
+
await this.update(); // also auto update to fix timing bug
|
|
68
|
+
}
|
|
69
|
+
async destroy() {
|
|
70
|
+
// Clean up all event listeners automatically
|
|
71
|
+
// Create a copy of the array to avoid issues with modification during iteration
|
|
72
|
+
const unsubscribers = [...this.#eventUnsubscribers];
|
|
73
|
+
this.#eventUnsubscribers = [];
|
|
74
|
+
unsubscribers.forEach((unsubscribe) => unsubscribe());
|
|
75
|
+
await this.#handle('destroy');
|
|
76
|
+
if (this.displayObject) {
|
|
77
|
+
this.displayObject.destroy();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Fluent method chaining - modify existing methods to return Component instance
|
|
81
|
+
async updateAppearance(appearance) {
|
|
82
|
+
await this.#properties.updateAppearance(appearance);
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
setStart(start) {
|
|
86
|
+
this.#properties.setStart(start);
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
setEnd(end) {
|
|
90
|
+
this.#properties.setEnd(end);
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
async updateText(text) {
|
|
94
|
+
await this.#properties.updateText(text);
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
// Simple fluent wrapper methods
|
|
98
|
+
async setText(text) {
|
|
99
|
+
return this.updateText(text);
|
|
100
|
+
}
|
|
101
|
+
async setVisible(visible) {
|
|
102
|
+
await this.#properties.setVisible(visible);
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
async setOrder(order) {
|
|
106
|
+
await this.#properties.setOrder(order);
|
|
107
|
+
return this;
|
|
108
|
+
}
|
|
109
|
+
// Component-scoped event filtering methods
|
|
110
|
+
onChange(callback) {
|
|
111
|
+
const wrappedCallback = (e) => {
|
|
112
|
+
const customEvent = e;
|
|
113
|
+
if (customEvent.detail.id === this.id) {
|
|
114
|
+
callback(customEvent.detail);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
// Use addEventListener directly to maintain reference for removal
|
|
118
|
+
this.#context.eventManager.addEventListener('componentchange', wrappedCallback);
|
|
119
|
+
// Create unsubscribe function
|
|
120
|
+
const unsubscribe = () => {
|
|
121
|
+
this.#context.eventManager.removeEventListener('componentchange', wrappedCallback);
|
|
122
|
+
// Remove from tracked unsubscribers
|
|
123
|
+
const index = this.#eventUnsubscribers.indexOf(unsubscribe);
|
|
124
|
+
if (index > -1) {
|
|
125
|
+
this.#eventUnsubscribers.splice(index, 1);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
// Track unsubscribe function for automatic cleanup
|
|
129
|
+
this.#eventUnsubscribers.push(unsubscribe);
|
|
130
|
+
return unsubscribe;
|
|
131
|
+
}
|
|
132
|
+
onTimelineChange(callback) {
|
|
133
|
+
const wrappedCallback = (e) => {
|
|
134
|
+
const customEvent = e;
|
|
135
|
+
callback(customEvent.detail);
|
|
136
|
+
};
|
|
137
|
+
// Use addEventListener directly to maintain reference for removal
|
|
138
|
+
this.#context.eventManager.addEventListener('timeupdate', wrappedCallback);
|
|
139
|
+
// Create unsubscribe function
|
|
140
|
+
const unsubscribe = () => {
|
|
141
|
+
this.#context.eventManager.removeEventListener('timeupdate', wrappedCallback);
|
|
142
|
+
// Remove from tracked unsubscribers
|
|
143
|
+
const index = this.#eventUnsubscribers.indexOf(unsubscribe);
|
|
144
|
+
if (index > -1) {
|
|
145
|
+
this.#eventUnsubscribers.splice(index, 1);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
// Track unsubscribe function for automatic cleanup
|
|
149
|
+
this.#eventUnsubscribers.push(unsubscribe);
|
|
150
|
+
return unsubscribe;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { StateManager } from '../managers/StateManager.svelte.js';
|
|
2
|
+
import { EventManager } from '../managers/EventManager.js';
|
|
3
|
+
import type { IComponentContext, ComponentData, ResourceTypes, IComponentHook, HookType, ComponentProps } from '..';
|
|
4
|
+
export declare class ComponentContext implements IComponentContext {
|
|
5
|
+
#private;
|
|
6
|
+
disabled: boolean;
|
|
7
|
+
resources: Map<keyof ResourceTypes, ResourceTypes[keyof ResourceTypes]>;
|
|
8
|
+
private state;
|
|
9
|
+
eventManager: EventManager;
|
|
10
|
+
constructor(cradle: {
|
|
11
|
+
stateManager: StateManager;
|
|
12
|
+
eventManager: EventManager;
|
|
13
|
+
});
|
|
14
|
+
setComponentProps(props: ComponentProps): void;
|
|
15
|
+
get duration(): number;
|
|
16
|
+
get contextData(): ComponentData;
|
|
17
|
+
get data(): ComponentData;
|
|
18
|
+
get id(): string;
|
|
19
|
+
get type(): "IMAGE" | "GIF" | "VIDEO" | "TEXT" | "SHAPE" | "AUDIO" | "COLOR" | "GRADIENT" | "SUBTITLES";
|
|
20
|
+
get isActive(): boolean;
|
|
21
|
+
get progress(): number;
|
|
22
|
+
get currentComponentTime(): number;
|
|
23
|
+
get componentTimelineTime(): number | undefined;
|
|
24
|
+
get currentTime(): number;
|
|
25
|
+
get sceneState(): StateManager;
|
|
26
|
+
updateContextData(data: ComponentData): void;
|
|
27
|
+
resetContextData(): void;
|
|
28
|
+
getResource<K extends keyof ResourceTypes>(type: K): ResourceTypes[K] | undefined;
|
|
29
|
+
setResource<K extends keyof ResourceTypes>(type: K, resource: ResourceTypes[K]): void;
|
|
30
|
+
removeResource<K extends keyof ResourceTypes>(type: K): void;
|
|
31
|
+
runHooks(hooks: IComponentHook[], type: HookType): Promise<void>;
|
|
32
|
+
destroy(): void;
|
|
33
|
+
}
|