animot-presenter 0.1.2 → 0.2.1
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/README.md +12 -23
- package/dist/AnimotPresenter.svelte +204 -12
- package/dist/cdn/animot-presenter.css +1 -1
- package/dist/cdn/animot-presenter.esm.js +4741 -4511
- package/dist/cdn/animot-presenter.min.js +10 -9
- package/dist/element.svelte.d.ts +33 -4
- package/dist/element.svelte.js +71 -34
- package/dist/engine/utils.d.ts +5 -0
- package/dist/engine/utils.js +18 -0
- package/dist/index.d.ts +1 -1
- package/dist/types.d.ts +42 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -95,37 +95,26 @@ npm install animot-presenter
|
|
|
95
95
|
|
|
96
96
|
```svelte
|
|
97
97
|
<script>
|
|
98
|
+
import { browser } from '$app/environment';
|
|
98
99
|
import { AnimotPresenter } from 'animot-presenter';
|
|
99
|
-
|
|
100
|
-
let animationData = $state(null);
|
|
101
|
-
|
|
102
|
-
async function load() {
|
|
103
|
-
const res = await fetch('/animations/hero.json');
|
|
104
|
-
animationData = await res.json();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
load();
|
|
108
100
|
</script>
|
|
109
101
|
|
|
110
|
-
<!--
|
|
102
|
+
<!-- Wrap with {#if browser} in SvelteKit to skip SSR -->
|
|
111
103
|
<div style="width: 100%; height: 500px;">
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
<!-- Option B: Pass data directly -->
|
|
122
|
-
<div style="width: 800px; height: 450px;">
|
|
123
|
-
{#if animationData}
|
|
124
|
-
<AnimotPresenter data={animationData} controls arrows />
|
|
104
|
+
{#if browser}
|
|
105
|
+
<AnimotPresenter
|
|
106
|
+
src="/animations/hero.json"
|
|
107
|
+
autoplay
|
|
108
|
+
loop
|
|
109
|
+
controls
|
|
110
|
+
onslidechange={(index, total) => console.log(`${index + 1}/${total}`)}
|
|
111
|
+
/>
|
|
125
112
|
{/if}
|
|
126
113
|
</div>
|
|
127
114
|
```
|
|
128
115
|
|
|
116
|
+
> **SvelteKit SSR:** The component uses browser APIs (canvas, ResizeObserver) and cannot be server-rendered. Always wrap with `{#if browser}` in SvelteKit, or use `ssr: false` in your `+page.ts`.
|
|
117
|
+
|
|
129
118
|
### React
|
|
130
119
|
|
|
131
120
|
```bash
|
|
@@ -8,10 +8,11 @@
|
|
|
8
8
|
import CounterRenderer from './renderers/CounterRenderer.svelte';
|
|
9
9
|
import ChartRenderer from './renderers/ChartRenderer.svelte';
|
|
10
10
|
import IconRenderer from './renderers/IconRenderer.svelte';
|
|
11
|
-
import { easeInOutCubic, getBackgroundStyle, hashFraction, getFloatAnimName, computeFloatAmp, computeFloatSpeed } from './engine/utils';
|
|
11
|
+
import { easeInOutCubic, getEasingFn, getBackgroundStyle, hashFraction, getFloatAnimName, computeFloatAmp, computeFloatSpeed } from './engine/utils';
|
|
12
12
|
import type {
|
|
13
13
|
AnimotProject, AnimotPresenterProps, CanvasElement, CodeElement, TextElement,
|
|
14
14
|
ArrowElement, ImageElement, ShapeElement, CounterElement, ChartElement, IconElement,
|
|
15
|
+
SvgElement, MotionPathElement, PathPoint,
|
|
15
16
|
Slide, CodeAnimationMode, AnimatableProperty
|
|
16
17
|
} from './types';
|
|
17
18
|
import './styles/presenter.css';
|
|
@@ -21,16 +22,90 @@
|
|
|
21
22
|
interface AnimatedElement {
|
|
22
23
|
x: TweenValue; y: TweenValue; width: TweenValue; height: TweenValue;
|
|
23
24
|
rotation: TweenValue; skewX: TweenValue; skewY: TweenValue;
|
|
24
|
-
tiltX: TweenValue; tiltY: TweenValue;
|
|
25
|
+
tiltX: TweenValue; tiltY: TweenValue; perspective: TweenValue;
|
|
26
|
+
opacity: TweenValue; borderRadius: TweenValue;
|
|
25
27
|
fontSize: TweenValue | null;
|
|
26
28
|
fillColor: ReturnType<typeof tween<string>> | null;
|
|
27
29
|
strokeColor: ReturnType<typeof tween<string>> | null;
|
|
28
30
|
strokeWidth: TweenValue | null;
|
|
29
31
|
shapeMorph: TweenValue | null;
|
|
32
|
+
motionPathProgress: TweenValue | null;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
interface ShapeMorphState { fromType: string; toType: string; }
|
|
33
36
|
|
|
37
|
+
// Active motion path loop cancellation tokens
|
|
38
|
+
let motionPathLoopAbort: AbortController | null = null;
|
|
39
|
+
function cancelMotionPathLoops() {
|
|
40
|
+
if (motionPathLoopAbort) { motionPathLoopAbort.abort(); motionPathLoopAbort = null; }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// --- Motion Path Utilities ---
|
|
44
|
+
function buildPresenterPathD(points: PathPoint[], closed: boolean): string {
|
|
45
|
+
if (points.length < 2) return '';
|
|
46
|
+
let d = `M ${points[0].x} ${points[0].y}`;
|
|
47
|
+
for (let i = 1; i < points.length; i++) {
|
|
48
|
+
const prev = points[i - 1], curr = points[i];
|
|
49
|
+
const cp1x = prev.x + (prev.handleOut?.x ?? 0), cp1y = prev.y + (prev.handleOut?.y ?? 0);
|
|
50
|
+
const cp2x = curr.x + (curr.handleIn?.x ?? 0), cp2y = curr.y + (curr.handleIn?.y ?? 0);
|
|
51
|
+
if (prev.handleOut || curr.handleIn) d += ` C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${curr.x} ${curr.y}`;
|
|
52
|
+
else d += ` L ${curr.x} ${curr.y}`;
|
|
53
|
+
}
|
|
54
|
+
if (closed && points.length > 2) {
|
|
55
|
+
const last = points[points.length - 1], first = points[0];
|
|
56
|
+
const cp1x = last.x + (last.handleOut?.x ?? 0), cp1y = last.y + (last.handleOut?.y ?? 0);
|
|
57
|
+
const cp2x = first.x + (first.handleIn?.x ?? 0), cp2y = first.y + (first.handleIn?.y ?? 0);
|
|
58
|
+
if (last.handleOut || first.handleIn) d += ` C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${first.x} ${first.y}`;
|
|
59
|
+
else d += ` Z`;
|
|
60
|
+
}
|
|
61
|
+
return d;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function cubicBez(p0: number, p1: number, p2: number, p3: number, t: number): number {
|
|
65
|
+
const mt = 1 - t;
|
|
66
|
+
return mt * mt * mt * p0 + 3 * mt * mt * t * p1 + 3 * mt * t * t * p2 + t * t * t * p3;
|
|
67
|
+
}
|
|
68
|
+
function cubicBezDeriv(p0: number, p1: number, p2: number, p3: number, t: number): number {
|
|
69
|
+
const mt = 1 - t;
|
|
70
|
+
return 3 * mt * mt * (p1 - p0) + 6 * mt * t * (p2 - p1) + 3 * t * t * (p3 - p2);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function getPresenterPointOnPath(points: PathPoint[], closed: boolean, progress: number): { x: number; y: number; angle: number } {
|
|
74
|
+
if (points.length < 2) return { x: points[0]?.x ?? 0, y: points[0]?.y ?? 0, angle: 0 };
|
|
75
|
+
const segs: { p0x: number; p0y: number; p1x: number; p1y: number; p2x: number; p2y: number; p3x: number; p3y: number; length: number }[] = [];
|
|
76
|
+
const segCount = closed ? points.length : points.length - 1;
|
|
77
|
+
for (let i = 0; i < segCount; i++) {
|
|
78
|
+
const curr = points[i], next = points[(i + 1) % points.length];
|
|
79
|
+
const p0x = curr.x, p0y = curr.y;
|
|
80
|
+
const p1x = curr.x + (curr.handleOut?.x ?? 0), p1y = curr.y + (curr.handleOut?.y ?? 0);
|
|
81
|
+
const p2x = next.x + (next.handleIn?.x ?? 0), p2y = next.y + (next.handleIn?.y ?? 0);
|
|
82
|
+
const p3x = next.x, p3y = next.y;
|
|
83
|
+
let length = 0, prevPx = p0x, prevPy = p0y;
|
|
84
|
+
for (let s = 1; s <= 20; s++) {
|
|
85
|
+
const t = s / 20;
|
|
86
|
+
const px = cubicBez(p0x, p1x, p2x, p3x, t), py = cubicBez(p0y, p1y, p2y, p3y, t);
|
|
87
|
+
length += Math.sqrt((px - prevPx) ** 2 + (py - prevPy) ** 2);
|
|
88
|
+
prevPx = px; prevPy = py;
|
|
89
|
+
}
|
|
90
|
+
segs.push({ p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y, length });
|
|
91
|
+
}
|
|
92
|
+
const totalLength = segs.reduce((sum, s) => sum + s.length, 0);
|
|
93
|
+
const targetLength = progress * totalLength;
|
|
94
|
+
let accum = 0;
|
|
95
|
+
for (const seg of segs) {
|
|
96
|
+
if (accum + seg.length >= targetLength || seg === segs[segs.length - 1]) {
|
|
97
|
+
const t = Math.max(0, Math.min(1, seg.length > 0 ? (targetLength - accum) / seg.length : 0));
|
|
98
|
+
return {
|
|
99
|
+
x: cubicBez(seg.p0x, seg.p1x, seg.p2x, seg.p3x, t),
|
|
100
|
+
y: cubicBez(seg.p0y, seg.p1y, seg.p2y, seg.p3y, t),
|
|
101
|
+
angle: Math.atan2(cubicBezDeriv(seg.p0y, seg.p1y, seg.p2y, seg.p3y, t), cubicBezDeriv(seg.p0x, seg.p1x, seg.p2x, seg.p3x, t)) * (180 / Math.PI)
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
accum += seg.length;
|
|
105
|
+
}
|
|
106
|
+
return { x: points[0].x, y: points[0].y, angle: 0 };
|
|
107
|
+
}
|
|
108
|
+
|
|
34
109
|
let {
|
|
35
110
|
src, data, autoplay = false, loop = false, controls = true, arrows = false,
|
|
36
111
|
progress: showProgress = true, keyboard = true, duration: durationOverride,
|
|
@@ -195,13 +270,15 @@
|
|
|
195
270
|
skewY: tween(element.skewY ?? 0, { duration: 500 }),
|
|
196
271
|
tiltX: tween(element.tiltX ?? 0, { duration: 500 }),
|
|
197
272
|
tiltY: tween(element.tiltY ?? 0, { duration: 500 }),
|
|
273
|
+
perspective: tween(element.perspective ?? 1000, { duration: 500 }),
|
|
198
274
|
opacity: tween(startOpacity, { duration: 300 }),
|
|
199
275
|
borderRadius: tween(br, { duration: 500 }),
|
|
200
276
|
fontSize: textEl ? tween(textEl.fontSize, { duration: 500 }) : null,
|
|
201
277
|
fillColor: shapeEl ? tween(shapeEl.fillColor, { duration: 500 }) : null,
|
|
202
278
|
strokeColor: shapeEl ? tween(shapeEl.strokeColor, { duration: 500 }) : null,
|
|
203
279
|
strokeWidth: shapeEl ? tween(shapeEl.strokeWidth, { duration: 500 }) : null,
|
|
204
|
-
shapeMorph: shapeEl ? tween(1, { duration: 500 }) : null
|
|
280
|
+
shapeMorph: shapeEl ? tween(1, { duration: 500 }) : null,
|
|
281
|
+
motionPathProgress: element.motionPathConfig ? tween(0, { duration: 500 }) : null
|
|
205
282
|
});
|
|
206
283
|
const currentSlideEl = getElementInSlide(currentSlide, element.id);
|
|
207
284
|
elementContent.set(element.id, JSON.parse(JSON.stringify(currentSlideEl || element)));
|
|
@@ -213,6 +290,46 @@
|
|
|
213
290
|
previousCodeContent = new Map(previousCodeContent);
|
|
214
291
|
}
|
|
215
292
|
|
|
293
|
+
async function animateMotionPaths(slide: Slide) {
|
|
294
|
+
cancelMotionPathLoops();
|
|
295
|
+
motionPathLoopAbort = new AbortController();
|
|
296
|
+
const signal = motionPathLoopAbort.signal;
|
|
297
|
+
|
|
298
|
+
const resets: Promise<void>[] = [];
|
|
299
|
+
for (const element of slide.canvas.elements) {
|
|
300
|
+
if (element.motionPathConfig) {
|
|
301
|
+
const animated = animatedElements.get(element.id);
|
|
302
|
+
if (animated?.motionPathProgress) {
|
|
303
|
+
resets.push(animated.motionPathProgress.to(0, { duration: 0 }));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
await Promise.all(resets);
|
|
308
|
+
for (const element of slide.canvas.elements) {
|
|
309
|
+
if (element.motionPathConfig) {
|
|
310
|
+
const animated = animatedElements.get(element.id);
|
|
311
|
+
if (animated?.motionPathProgress) {
|
|
312
|
+
const config = element.animationConfig;
|
|
313
|
+
const duration = config?.duration ?? 2000;
|
|
314
|
+
const easing = getEasingFn(config?.easing);
|
|
315
|
+
const shouldLoop = element.motionPathConfig.loop;
|
|
316
|
+
|
|
317
|
+
if (shouldLoop) {
|
|
318
|
+
(async () => {
|
|
319
|
+
while (!signal.aborted) {
|
|
320
|
+
await animated.motionPathProgress!.to(0, { duration: 0 });
|
|
321
|
+
await animated.motionPathProgress!.to(1, { duration, easing });
|
|
322
|
+
if (!signal.aborted) await new Promise(r => setTimeout(r, 50));
|
|
323
|
+
}
|
|
324
|
+
})();
|
|
325
|
+
} else {
|
|
326
|
+
animated.motionPathProgress.to(1, { duration, easing });
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
216
333
|
// Animate to slide
|
|
217
334
|
async function animateToSlide(targetIndex: number) {
|
|
218
335
|
if (isTransitioning || targetIndex < 0 || targetIndex >= slides.length) return;
|
|
@@ -221,6 +338,7 @@
|
|
|
221
338
|
transitionDirection = targetIndex > currentSlideIndex ? 'forward' : 'backward';
|
|
222
339
|
const targetSlide = slides[targetIndex];
|
|
223
340
|
clearAllTypewriterAnimations();
|
|
341
|
+
cancelMotionPathLoops();
|
|
224
342
|
const transition = targetSlide.transition;
|
|
225
343
|
const duration = durationOverride ?? transition.duration;
|
|
226
344
|
transitionDurationMs = duration;
|
|
@@ -249,6 +367,7 @@
|
|
|
249
367
|
animated.rotation.to(targetEl.rotation, { duration: 0 });
|
|
250
368
|
animated.skewX.to(targetEl.skewX ?? 0, { duration: 0 }); animated.skewY.to(targetEl.skewY ?? 0, { duration: 0 });
|
|
251
369
|
animated.tiltX.to(targetEl.tiltX ?? 0, { duration: 0 }); animated.tiltY.to(targetEl.tiltY ?? 0, { duration: 0 });
|
|
370
|
+
animated.perspective.to(targetEl.perspective ?? 1000, { duration: 0 });
|
|
252
371
|
animated.opacity.to(1, { duration: 0 });
|
|
253
372
|
animated.borderRadius.to((targetEl as any).borderRadius ?? 0, { duration: 0 });
|
|
254
373
|
if (targetEl.type === 'text') animated.fontSize?.to((targetEl as TextElement).fontSize, { duration: 0 });
|
|
@@ -258,6 +377,7 @@
|
|
|
258
377
|
animated.strokeColor?.to(s.strokeColor, { duration: 0 });
|
|
259
378
|
animated.strokeWidth?.to(s.strokeWidth, { duration: 0 });
|
|
260
379
|
}
|
|
380
|
+
if (animated.motionPathProgress) animated.motionPathProgress.to(0, { duration: 0 });
|
|
261
381
|
}
|
|
262
382
|
} else if (animated) { animated.opacity.to(0, { duration: 0 }); }
|
|
263
383
|
}
|
|
@@ -288,6 +408,7 @@
|
|
|
288
408
|
transitionClass = `transition-${transition.type}-in`;
|
|
289
409
|
await new Promise(r => setTimeout(r, duration * 0.6));
|
|
290
410
|
transitionClass = '';
|
|
411
|
+
animateMotionPaths(targetSlide);
|
|
291
412
|
isTransitioning = false;
|
|
292
413
|
onslidechange?.(targetIndex, slides.length);
|
|
293
414
|
if (targetIndex === slides.length - 1 && !loop) oncomplete?.();
|
|
@@ -310,6 +431,7 @@
|
|
|
310
431
|
await animated.skewY.to(currentEl.skewY ?? 0, { duration: 0 });
|
|
311
432
|
await animated.tiltX.to(currentEl.tiltX ?? 0, { duration: 0 });
|
|
312
433
|
await animated.tiltY.to(currentEl.tiltY ?? 0, { duration: 0 });
|
|
434
|
+
await animated.perspective.to(currentEl.perspective ?? 1000, { duration: 0 });
|
|
313
435
|
await animated.borderRadius.to((currentEl as any).borderRadius ?? 0, { duration: 0 });
|
|
314
436
|
await animated.opacity.to(1, { duration: 0 });
|
|
315
437
|
if (currentEl.type === 'text' && animated.fontSize) await animated.fontSize.to((currentEl as TextElement).fontSize, { duration: 0 });
|
|
@@ -336,7 +458,7 @@
|
|
|
336
458
|
const elementDuration = animConfig?.duration ?? duration;
|
|
337
459
|
|
|
338
460
|
if (targetEl) {
|
|
339
|
-
const easing =
|
|
461
|
+
const easing = getEasingFn(animConfig?.easing);
|
|
340
462
|
const propertySequences = targetEl.animationConfig?.propertySequences;
|
|
341
463
|
if (targetEl.type === 'text') {
|
|
342
464
|
const textEl = targetEl as TextElement;
|
|
@@ -361,6 +483,7 @@
|
|
|
361
483
|
if (!sequencedProps.has('skew')) { anims.push(animated.skewX.to(targetEl.skewX ?? 0, { duration: elementDuration, easing })); anims.push(animated.skewY.to(targetEl.skewY ?? 0, { duration: elementDuration, easing })); }
|
|
362
484
|
if (!sequencedProps.has('size')) { anims.push(animated.width.to(targetEl.size.width, { duration: elementDuration, easing })); anims.push(animated.height.to(targetEl.size.height, { duration: elementDuration, easing })); }
|
|
363
485
|
if (!sequencedProps.has('borderRadius')) anims.push(animated.borderRadius.to((targetEl as any).borderRadius ?? 0, { duration: elementDuration, easing }));
|
|
486
|
+
if (!sequencedProps.has('perspective')) anims.push(animated.perspective.to(targetEl.perspective ?? 1000, { duration: elementDuration, easing }));
|
|
364
487
|
const sortedSeqs = [...propertySequences].sort((a, b) => a.order - b.order);
|
|
365
488
|
let cumulativeDelay = 0;
|
|
366
489
|
for (const seq of sortedSeqs) {
|
|
@@ -379,6 +502,7 @@
|
|
|
379
502
|
animated.strokeColor?.to(s.strokeColor, { duration: seqDuration, easing });
|
|
380
503
|
animated.strokeWidth?.to(s.strokeWidth, { duration: seqDuration, easing });
|
|
381
504
|
}
|
|
505
|
+
else if (seq.property === 'perspective') animated.perspective.to(targetEl.perspective ?? 1000, { duration: seqDuration, easing });
|
|
382
506
|
}, seqDelay);
|
|
383
507
|
cumulativeDelay = seqDelay + seqDuration;
|
|
384
508
|
}
|
|
@@ -393,8 +517,19 @@
|
|
|
393
517
|
anims.push(animated.skewY.to(targetEl.skewY ?? 0, { duration: elementDuration, easing }));
|
|
394
518
|
anims.push(animated.tiltX.to(targetEl.tiltX ?? 0, { duration: elementDuration, easing }));
|
|
395
519
|
anims.push(animated.tiltY.to(targetEl.tiltY ?? 0, { duration: elementDuration, easing }));
|
|
520
|
+
anims.push(animated.perspective.to(targetEl.perspective ?? 1000, { duration: elementDuration, easing }));
|
|
396
521
|
anims.push(animated.borderRadius.to((targetEl as any).borderRadius ?? 0, { duration: elementDuration, easing }));
|
|
397
522
|
}
|
|
523
|
+
// Motion path progress — await reset, then animate forward
|
|
524
|
+
if (animated.motionPathProgress && targetEl.motionPathConfig) {
|
|
525
|
+
const shouldLoop = targetEl.motionPathConfig.loop;
|
|
526
|
+
if (!shouldLoop) {
|
|
527
|
+
anims.push((async () => {
|
|
528
|
+
await animated.motionPathProgress!.to(0, { duration: 0 });
|
|
529
|
+
await animated.motionPathProgress!.to(1, { duration: elementDuration, easing });
|
|
530
|
+
})());
|
|
531
|
+
}
|
|
532
|
+
}
|
|
398
533
|
if (targetEl.type === 'text' && animated.fontSize) anims.push(animated.fontSize.to((targetEl as TextElement).fontSize, { duration: elementDuration, easing }));
|
|
399
534
|
if (targetEl.type === 'shape' && currentEl?.type === 'shape') {
|
|
400
535
|
const ts = targetEl as ShapeElement;
|
|
@@ -416,12 +551,25 @@
|
|
|
416
551
|
if (animated.strokeColor) anims.push(animated.strokeColor.to(s.strokeColor, { duration: elementDuration, easing }));
|
|
417
552
|
if (animated.strokeWidth) anims.push(animated.strokeWidth.to(s.strokeWidth, { duration: elementDuration, easing }));
|
|
418
553
|
}
|
|
419
|
-
if (!currentEl)
|
|
554
|
+
if (!currentEl) {
|
|
555
|
+
const entrance = targetEl.animationConfig?.entrance ?? 'fade';
|
|
556
|
+
if (entrance === 'fade') {
|
|
557
|
+
anims.push(animated.opacity.to(1, { duration: elementDuration / 2, easing }));
|
|
558
|
+
} else {
|
|
559
|
+
anims.push(animated.opacity.to(1, { duration: 0 }));
|
|
560
|
+
}
|
|
561
|
+
}
|
|
420
562
|
return anims;
|
|
421
563
|
}
|
|
422
564
|
});
|
|
423
565
|
} else if (currentEl) {
|
|
424
|
-
|
|
566
|
+
const exit = currentEl.animationConfig?.exit ?? 'fade';
|
|
567
|
+
if (exit === 'fade') {
|
|
568
|
+
const fadeOutDuration = Math.min(elementDuration / 2, 300);
|
|
569
|
+
animationTasks.push({ elementId, order, delay, elementDuration, run: () => [animated.opacity.to(0, { duration: fadeOutDuration, easing: easeInOutCubic })] });
|
|
570
|
+
} else {
|
|
571
|
+
animationTasks.push({ elementId, order, delay: 0, elementDuration: 0, run: () => [animated.opacity.to(0, { duration: 0 })] });
|
|
572
|
+
}
|
|
425
573
|
}
|
|
426
574
|
}
|
|
427
575
|
|
|
@@ -479,6 +627,7 @@
|
|
|
479
627
|
elementContent = newElementContent;
|
|
480
628
|
currentSlideIndex = targetIndex;
|
|
481
629
|
isTransitioning = false;
|
|
630
|
+
animateMotionPaths(slides[targetIndex]);
|
|
482
631
|
onslidechange?.(targetIndex, slides.length);
|
|
483
632
|
if (targetIndex === slides.length - 1 && !loop) oncomplete?.();
|
|
484
633
|
}
|
|
@@ -570,6 +719,7 @@
|
|
|
570
719
|
initAllAnimatedElements();
|
|
571
720
|
await loadCodeHighlights();
|
|
572
721
|
loading = false;
|
|
722
|
+
if (currentSlide) setTimeout(() => animateMotionPaths(currentSlide!), 300);
|
|
573
723
|
if (autoplay) isAutoplay = true;
|
|
574
724
|
} catch (e: any) { error = e.message; loading = false; }
|
|
575
725
|
}
|
|
@@ -632,17 +782,27 @@
|
|
|
632
782
|
{@const floatCfg = element?.floatingAnimation}
|
|
633
783
|
{@const hasFloat = floatCfg?.enabled}
|
|
634
784
|
{@const floatGroupId = element?.groupId}
|
|
635
|
-
{
|
|
785
|
+
{@const mpConfig = element?.motionPathConfig}
|
|
786
|
+
{@const mpElement = mpConfig ? currentSlide?.canvas.elements.find(el => el.id === mpConfig.motionPathId) as MotionPathElement | undefined : undefined}
|
|
787
|
+
{@const mpProgress = animated?.motionPathProgress?.current ?? 0}
|
|
788
|
+
{@const mpPoint = mpElement && mpConfig ? getPresenterPointOnPath(mpElement.points, mpElement.closed, (mpConfig.startPercent + (mpConfig.endPercent - mpConfig.startPercent) * mpProgress) / 100) : null}
|
|
789
|
+
{@const elemX = mpPoint ? mpPoint.x - (animated?.width.current ?? 0) / 2 : animated?.x.current ?? 0}
|
|
790
|
+
{@const elemY = mpPoint ? mpPoint.y - (animated?.height.current ?? 0) / 2 : animated?.y.current ?? 0}
|
|
791
|
+
{@const mpRotation = mpPoint && mpConfig?.autoRotate
|
|
792
|
+
? mpPoint.angle + (mpConfig.orientationOffset ?? 0)
|
|
793
|
+
: null}
|
|
794
|
+
{#if element && animated && animated.opacity.current > 0.01 && element.visible !== false && !(element.type === 'motionPath' && !(element as MotionPathElement).showInPresentation)}
|
|
636
795
|
<div
|
|
637
796
|
class="animot-element"
|
|
638
797
|
class:floating={hasFloat}
|
|
639
|
-
style:left="{
|
|
640
|
-
style:top="{
|
|
798
|
+
style:left="{elemX}px"
|
|
799
|
+
style:top="{elemY}px"
|
|
641
800
|
style:width="{animated.width.current}px"
|
|
642
801
|
style:height="{animated.height.current}px"
|
|
643
802
|
style:opacity={animated.opacity.current}
|
|
644
|
-
style:transform="perspective(
|
|
803
|
+
style:transform="perspective({animated.perspective.current}px) rotateX({animated.tiltX.current}deg) rotateY({animated.tiltY.current}deg) rotate({mpRotation ?? animated.rotation.current}deg) skewX({animated.skewX.current}deg) skewY({animated.skewY.current}deg)"
|
|
645
804
|
style:transform-origin={element.tiltOrigin ?? 'center'}
|
|
805
|
+
style:backface-visibility={element.backfaceVisibility ?? 'visible'}
|
|
646
806
|
style:z-index={element.zIndex}
|
|
647
807
|
style:--float-amp="{hasFloat ? computeFloatAmp(floatCfg, floatGroupId || elementId) : 10}px"
|
|
648
808
|
style:--float-speed="{hasFloat ? computeFloatSpeed(floatCfg, floatGroupId || elementId) : 3}s"
|
|
@@ -722,7 +882,7 @@
|
|
|
722
882
|
{@const arrowAnimDuration = arrowEl.animation?.duration ?? 500}
|
|
723
883
|
{@const isStyledArrow = arrowEl.style !== 'solid'}
|
|
724
884
|
{@const baseDashArray = arrowEl.style === 'dashed' ? '10,5' : arrowEl.style === 'dotted' ? '2,5' : 'none'}
|
|
725
|
-
<svg class="animot-arrow-element" class:arrow-animate-draw={arrowAnimMode === 'draw' && !isStyledArrow} class:arrow-animate-grow={arrowAnimMode === 'grow'} viewBox="0 0 {arrowEl.size.width} {arrowEl.size.height}" preserveAspectRatio="none" style="
|
|
885
|
+
<svg class="animot-arrow-element" class:arrow-animate-draw={arrowAnimMode === 'draw' && !isStyledArrow} class:arrow-animate-grow={arrowAnimMode === 'grow'} viewBox="0 0 {arrowEl.size.width} {arrowEl.size.height}" preserveAspectRatio="none" style="--arrow-anim-duration: {arrowAnimDuration}ms;">
|
|
726
886
|
<path class="arrow-path" d={pathD} fill="none" stroke={arrowEl.color} stroke-width={arrowEl.strokeWidth} stroke-dasharray={baseDashArray} stroke-linecap="round" stroke-linejoin="round" use:animateStyledArrowDraw={{ enabled: arrowAnimMode === 'draw' && isStyledArrow, duration: arrowAnimDuration, dashPattern: baseDashArray, startX: arrowEl.startPoint.x, endX: arrowEl.endPoint.x, slideIndex: currentSlideIndex }} />
|
|
727
887
|
{#if arrowEl.showHead !== false}
|
|
728
888
|
<path class="arrow-head" class:arrow-head-styled-draw={arrowAnimMode === 'draw' && isStyledArrow} d={arrowHeadPath} fill="none" stroke={arrowEl.color} stroke-width={arrowEl.strokeWidth} stroke-linecap="round" stroke-linejoin="round" style={arrowAnimMode === 'draw' && isStyledArrow ? `--arrow-anim-duration: ${arrowAnimDuration}ms;` : ''} />
|
|
@@ -731,7 +891,7 @@
|
|
|
731
891
|
{:else if element.type === 'image'}
|
|
732
892
|
{@const imgEl = element as ImageElement}
|
|
733
893
|
{@const clipPath = imgEl.clipMask?.enabled ? (imgEl.clipMask.shapeType === 'circle' ? 'circle(50% at 50% 50%)' : imgEl.clipMask.shapeType === 'ellipse' ? 'ellipse(50% 50% at 50% 50%)' : imgEl.clipMask.shapeType === 'triangle' ? 'polygon(50% 0%, 0% 100%, 100% 100%)' : imgEl.clipMask.shapeType === 'star' ? 'polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%)' : imgEl.clipMask.shapeType === 'hexagon' ? 'polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%)' : (imgEl.clipMask.borderRadius ?? 0) > 0 ? `inset(0 round ${imgEl.clipMask.borderRadius}px)` : 'none') : 'none'}
|
|
734
|
-
<img class="animot-image-element" src={imgEl.src} alt="" style:object-fit={imgEl.objectFit} style:border-radius="{imgEl.clipMask?.enabled ? 0 : imgEl.borderRadius}px" style:opacity={imgEl.opacity} style:filter={imgEl.blur ? `blur(${imgEl.blur}px)` : 'none'} style:clip-path={clipPath} />
|
|
894
|
+
<img class="animot-image-element" src={imgEl.src} alt="" style:object-fit={imgEl.objectFit} style:border-radius="{imgEl.clipMask?.enabled ? 0 : imgEl.borderRadius}px" style:opacity={imgEl.opacity} style:filter={imgEl.blur ? `blur(${imgEl.blur}px)` : 'none'} style:clip-path={clipPath} style:background-color={imgEl.backgroundColor ?? 'transparent'} />
|
|
735
895
|
{:else if element.type === 'shape'}
|
|
736
896
|
{@const shapeEl = element as ShapeElement}
|
|
737
897
|
{@const animFill = animated.fillColor?.current ?? shapeEl.fillColor}
|
|
@@ -758,6 +918,23 @@
|
|
|
758
918
|
<ChartRenderer element={element as ChartElement} slideId={currentSlide?.id ?? ''} />
|
|
759
919
|
{:else if element.type === 'icon'}
|
|
760
920
|
<IconRenderer element={element as IconElement} />
|
|
921
|
+
{:else if element.type === 'svg'}
|
|
922
|
+
{@const svgEl = element as SvgElement}
|
|
923
|
+
{@const svgInner = (() => { const m = svgEl.svgContent.trim().match(/^<svg[^>]*>([\s\S]*)<\/svg>$/i); return m ? m[1] : svgEl.svgContent; })()}
|
|
924
|
+
<div class="animot-svg-element" style:opacity={svgEl.opacity}>
|
|
925
|
+
<svg width="100%" height="100%" viewBox="0 0 {svgEl.size.width} {svgEl.size.height}" preserveAspectRatio={svgEl.preserveAspectRatio} xmlns="http://www.w3.org/2000/svg">
|
|
926
|
+
<g style={svgEl.color ? `fill:${svgEl.color};stroke:${svgEl.color}` : ''}>
|
|
927
|
+
{@html svgInner}
|
|
928
|
+
</g>
|
|
929
|
+
</svg>
|
|
930
|
+
</div>
|
|
931
|
+
{:else if element.type === 'motionPath'}
|
|
932
|
+
{@const mpEl = element as MotionPathElement}
|
|
933
|
+
{#if mpEl.showInPresentation}
|
|
934
|
+
<svg width="100%" height="100%" style="position:absolute;top:0;left:0;pointer-events:none;overflow:visible;">
|
|
935
|
+
<path d={buildPresenterPathD(mpEl.points, mpEl.closed)} stroke={mpEl.pathColor} stroke-width={mpEl.pathWidth} fill="none" stroke-dasharray="8 4" />
|
|
936
|
+
</svg>
|
|
937
|
+
{/if}
|
|
761
938
|
{/if}
|
|
762
939
|
</div>
|
|
763
940
|
{/if}
|
|
@@ -848,6 +1025,7 @@
|
|
|
848
1025
|
position: absolute;
|
|
849
1026
|
box-sizing: border-box;
|
|
850
1027
|
will-change: transform, opacity, left, top, width, height;
|
|
1028
|
+
isolation: isolate;
|
|
851
1029
|
}
|
|
852
1030
|
|
|
853
1031
|
.animot-element.floating {
|
|
@@ -929,6 +1107,20 @@
|
|
|
929
1107
|
@keyframes animot-zoomOut { from { transform: scale(1.5); opacity: 0; } to { transform: scale(1); opacity: 1; } }
|
|
930
1108
|
@keyframes animot-flipIn { from { transform: perspective(1000px) rotateY(-90deg); opacity: 0; } to { transform: perspective(1000px) rotateY(0); opacity: 1; } }
|
|
931
1109
|
|
|
1110
|
+
/* Flip-X transition */
|
|
1111
|
+
.animot-canvas.transition-flip-x-out { transform: perspective(1000px) rotateX(90deg); opacity: 0; }
|
|
1112
|
+
.animot-canvas.transition-flip-x-in { animation: animot-flipXIn calc(var(--transition-duration) * 0.6) ease forwards; }
|
|
1113
|
+
@keyframes animot-flipXIn { from { transform: perspective(1000px) rotateX(-90deg); opacity: 0; } to { transform: perspective(1000px) rotateX(0); opacity: 1; } }
|
|
1114
|
+
|
|
1115
|
+
/* Flip-Y transition */
|
|
1116
|
+
.animot-canvas.transition-flip-y-out { transform: perspective(1000px) rotateY(90deg); opacity: 0; }
|
|
1117
|
+
.animot-canvas.transition-flip-y-in { animation: animot-flipYIn calc(var(--transition-duration) * 0.6) ease forwards; }
|
|
1118
|
+
@keyframes animot-flipYIn { from { transform: perspective(1000px) rotateY(-90deg); opacity: 0; } to { transform: perspective(1000px) rotateY(0); opacity: 1; } }
|
|
1119
|
+
|
|
1120
|
+
/* SVG element */
|
|
1121
|
+
.animot-svg-element { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; }
|
|
1122
|
+
.animot-svg-element :global(svg) { width: 100%; height: 100%; }
|
|
1123
|
+
|
|
932
1124
|
/* Controls */
|
|
933
1125
|
.animot-controls {
|
|
934
1126
|
position: absolute; bottom: 12px; left: 50%; transform: translateX(-50%);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.code-morph.svelte-1hmk0l{width:100%;height:100%;margin:0;padding:0;background:transparent;font-family:var(--font-mono, "JetBrains Mono", monospace);font-size:inherit;line-height:1.6;white-space:pre-wrap;word-wrap:break-word;color:#e6edf3;box-sizing:border-box;overflow:visible}.code-morph.svelte-1hmk0l pre{margin:0;padding:16px;background:transparent!important;font-family:var(--font-mono);font-size:inherit;line-height:1.6;overflow:visible}.code-morph.svelte-1hmk0l code{font-family:inherit;font-size:inherit;font-weight:inherit}.code-morph.svelte-1hmk0l .line-number{display:inline-block;width:2.5em;margin-right:1em;text-align:right;color:#6e7681;-webkit-user-select:none;user-select:none;opacity:.6}.code-morph.svelte-1hmk0l .word-highlight{background:var(--highlight-color, #facc15);color:#000;border-radius:3px;padding:1px 3px;margin:0 -3px;-webkit-box-decoration-break:clone;box-decoration-break:clone;animation:svelte-1hmk0l-fadeHighlight var(--duration, 1s) ease-out forwards}@keyframes svelte-1hmk0l-fadeHighlight{0%{background:var(--highlight-color, #facc15);color:#000}70%{background:var(--highlight-color, #facc15);color:#000}to{background:transparent;color:inherit}}.counter.svelte-1er5jjj{width:100%;height:100%;display:flex;align-items:center;justify-content:center;box-sizing:border-box;overflow:hidden;white-space:nowrap}.chart.svelte-1mq2d7j{width:100%;height:100%;display:flex;flex-direction:column;box-sizing:border-box;overflow:hidden}.chart-title.svelte-1mq2d7j{font-weight:600;text-align:center;margin-bottom:8px}.chart-content.svelte-1mq2d7j{flex:1;min-height:0}.chart-content.svelte-1mq2d7j svg:where(.svelte-1mq2d7j){width:100%;height:100%}.bar-chart.svelte-1mq2d7j,.line-chart.svelte-1mq2d7j{overflow:visible}.icon-element.svelte-2ld65o{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.icon-element.svelte-2ld65o svg{width:100%;height:100%}@keyframes float-vertical{0%,to{translate:0 0}50%{translate:0 calc(-1 * var(--float-amp, 10px))}}@keyframes float-horizontal{0%,to{translate:0 0}50%{translate:var(--float-amp, 10px) 0}}@keyframes float-both-0{0%{translate:0 0}15%{translate:calc(.8 * var(--float-amp, 10px)) calc(-.6 * var(--float-amp, 10px))}35%{translate:calc(-.4 * var(--float-amp, 10px)) calc(-1 * var(--float-amp, 10px))}55%{translate:calc(-.9 * var(--float-amp, 10px)) calc(.3 * var(--float-amp, 10px))}75%{translate:calc(.3 * var(--float-amp, 10px)) calc(.7 * var(--float-amp, 10px))}to{translate:0 0}}@keyframes float-both-1{0%{translate:0 0}20%{translate:calc(-.7 * var(--float-amp, 10px)) calc(-.8 * var(--float-amp, 10px))}40%{translate:calc(.5 * var(--float-amp, 10px)) calc(-.3 * var(--float-amp, 10px))}60%{translate:calc(.9 * var(--float-amp, 10px)) calc(.6 * var(--float-amp, 10px))}80%{translate:calc(-.4 * var(--float-amp, 10px)) calc(.9 * var(--float-amp, 10px))}to{translate:0 0}}@keyframes float-both-2{0%{translate:0 0}12%{translate:calc(.6 * var(--float-amp, 10px)) calc(.5 * var(--float-amp, 10px))}30%{translate:calc(1 * var(--float-amp, 10px)) calc(-.4 * var(--float-amp, 10px))}50%{translate:calc(-.3 * var(--float-amp, 10px)) calc(-.9 * var(--float-amp, 10px))}70%{translate:calc(-.8 * var(--float-amp, 10px)) calc(.2 * var(--float-amp, 10px))}88%{translate:calc(.2 * var(--float-amp, 10px)) calc(.8 * var(--float-amp, 10px))}to{translate:0 0}}@keyframes float-both-3{0%{translate:0 0}17%{translate:calc(-.9 * var(--float-amp, 10px)) calc(.4 * var(--float-amp, 10px))}33%{translate:calc(-.5 * var(--float-amp, 10px)) calc(-.7 * var(--float-amp, 10px))}50%{translate:calc(.7 * var(--float-amp, 10px)) calc(-.9 * var(--float-amp, 10px))}67%{translate:calc(.9 * var(--float-amp, 10px)) calc(.5 * var(--float-amp, 10px))}83%{translate:calc(-.2 * var(--float-amp, 10px)) calc(.8 * var(--float-amp, 10px))}to{translate:0 0}}.animot-presenter.svelte-16ocdv9{position:relative;width:100%;height:100%;display:flex;align-items:center;justify-content:center;overflow:hidden;background:transparent}.animot-canvas-wrapper.svelte-16ocdv9{display:flex;align-items:center;justify-content:center}.animot-canvas.svelte-16ocdv9{position:relative;overflow:hidden}.animot-element.svelte-16ocdv9{position:absolute;box-sizing:border-box;will-change:transform,opacity,left,top,width,height}.animot-element.floating.svelte-16ocdv9{animation-duration:var(--float-speed, 3s);animation-timing-function:ease-in-out;animation-iteration-count:infinite;animation-delay:var(--float-delay, 0s)}.animot-code-block.svelte-16ocdv9{width:100%;height:100%;background:#0d1117;overflow:hidden;display:flex;flex-direction:column;box-shadow:0 8px 32px #0006;margin:0;box-sizing:border-box}.animot-code-block.transparent-bg.svelte-16ocdv9{background:transparent;box-shadow:none}.animot-code-block.transparent-bg.svelte-16ocdv9 .animot-code-header:where(.svelte-16ocdv9){background:transparent;border-bottom-color:#ffffff1a}.animot-code-header.svelte-16ocdv9{display:flex;align-items:center;gap:12px;padding:12px 16px;background:#161b22;border-bottom:1px solid #30363d;flex-shrink:0}.animot-window-controls.svelte-16ocdv9{display:flex;gap:8px}.animot-control.svelte-16ocdv9{width:12px;height:12px;border-radius:50%;display:block}.macos.svelte-16ocdv9 .animot-control.close:where(.svelte-16ocdv9){background:#ff5f57}.macos.svelte-16ocdv9 .animot-control.minimize:where(.svelte-16ocdv9){background:#febc2e}.macos.svelte-16ocdv9 .animot-control.maximize:where(.svelte-16ocdv9){background:#28c840}.animot-filename.svelte-16ocdv9{color:#8b949e;font-size:14px;flex:1}.animot-code-content.svelte-16ocdv9{flex:1;overflow:hidden;position:relative}.animot-highlighted-code.svelte-16ocdv9{width:100%;height:100%}.animot-code-content.svelte-16ocdv9 pre,.animot-highlighted-code.svelte-16ocdv9 pre{margin:0;padding:16px;background:transparent!important;line-height:1.6;font-size:inherit;overflow:visible}.animot-highlighted-code.svelte-16ocdv9 code{font-family:inherit;font-size:inherit;font-weight:inherit}.animot-highlighted-code.svelte-16ocdv9 .line-number{display:inline-block;width:2.5em;margin-right:1em;text-align:right;color:#6e7681;-webkit-user-select:none;user-select:none;opacity:.6}.animot-text-element.svelte-16ocdv9{width:100%;height:100%;display:flex;align-items:center;white-space:pre-wrap;word-wrap:break-word}.animot-typewriter-cursor.svelte-16ocdv9{animation:svelte-16ocdv9-animot-blink .7s infinite;font-weight:100}@keyframes svelte-16ocdv9-animot-blink{0%,50%{opacity:1}51%,to{opacity:0}}.animot-arrow-element.svelte-16ocdv9{width:100%;height:100%}.arrow-animate-draw.svelte-16ocdv9 .arrow-path:where(.svelte-16ocdv9){stroke-dasharray:1000;stroke-dashoffset:1000;animation:svelte-16ocdv9-animot-arrow-draw var(--arrow-anim-duration, .5s) ease-out forwards}.arrow-head-styled-draw.svelte-16ocdv9{opacity:0;animation:svelte-16ocdv9-animot-arrow-head-appear var(--arrow-anim-duration, .5s) ease-out forwards;animation-delay:calc(var(--arrow-anim-duration, .5s) * .7)}.arrow-animate-draw.svelte-16ocdv9 .arrow-head:where(.svelte-16ocdv9){opacity:0;animation:svelte-16ocdv9-animot-arrow-head-appear var(--arrow-anim-duration, .5s) ease-out forwards;animation-delay:calc(var(--arrow-anim-duration, .5s) * .7)}.arrow-animate-grow.svelte-16ocdv9{transform-origin:left center;animation:svelte-16ocdv9-animot-arrow-grow var(--arrow-anim-duration, .5s) ease-out forwards}@keyframes svelte-16ocdv9-animot-arrow-draw{to{stroke-dashoffset:0}}@keyframes svelte-16ocdv9-animot-arrow-head-appear{0%{opacity:0}to{opacity:1}}@keyframes svelte-16ocdv9-animot-arrow-grow{0%{transform:scaleX(0);opacity:0}to{transform:scaleX(1);opacity:1}}.animot-image-element.svelte-16ocdv9{width:100%;height:100%;display:block}.animot-shape-element.svelte-16ocdv9{width:100%;height:100%;display:block;overflow:visible}.animot-canvas.svelte-16ocdv9{--transition-duration: .5s;transition:transform calc(var(--transition-duration) * .4) ease,opacity calc(var(--transition-duration) * .4) ease}.animot-canvas.transition-fade-out.svelte-16ocdv9{opacity:0}.animot-canvas.transition-fade-in.svelte-16ocdv9{animation:svelte-16ocdv9-animot-fadeIn calc(var(--transition-duration) * .6) ease forwards}.animot-canvas.transition-slide-left-out.forward.svelte-16ocdv9{transform:translate(-100%);opacity:0}.animot-canvas.transition-slide-left-in.forward.svelte-16ocdv9{animation:svelte-16ocdv9-animot-slideInFromRight calc(var(--transition-duration) * .6) ease forwards}.animot-canvas.transition-slide-left-out.backward.svelte-16ocdv9{transform:translate(100%);opacity:0}.animot-canvas.transition-slide-left-in.backward.svelte-16ocdv9{animation:svelte-16ocdv9-animot-slideInFromLeft calc(var(--transition-duration) * .6) ease forwards}.animot-canvas.transition-slide-right-out.forward.svelte-16ocdv9{transform:translate(100%);opacity:0}.animot-canvas.transition-slide-right-in.forward.svelte-16ocdv9{animation:svelte-16ocdv9-animot-slideInFromLeft calc(var(--transition-duration) * .6) ease forwards}.animot-canvas.transition-slide-up-out.svelte-16ocdv9{transform:translateY(-100%);opacity:0}.animot-canvas.transition-slide-up-in.svelte-16ocdv9{animation:svelte-16ocdv9-animot-slideInFromBottom calc(var(--transition-duration) * .6) ease forwards}.animot-canvas.transition-slide-down-out.svelte-16ocdv9{transform:translateY(100%);opacity:0}.animot-canvas.transition-slide-down-in.svelte-16ocdv9{animation:svelte-16ocdv9-animot-slideInFromTop calc(var(--transition-duration) * .6) ease forwards}.animot-canvas.transition-zoom-in-out.svelte-16ocdv9{transform:scale(.5);opacity:0}.animot-canvas.transition-zoom-in-in.svelte-16ocdv9{animation:svelte-16ocdv9-animot-zoomIn calc(var(--transition-duration) * .6) ease forwards}.animot-canvas.transition-zoom-out-out.svelte-16ocdv9{transform:scale(1.5);opacity:0}.animot-canvas.transition-zoom-out-in.svelte-16ocdv9{animation:svelte-16ocdv9-animot-zoomOut calc(var(--transition-duration) * .6) ease forwards}.animot-canvas.transition-flip-out.svelte-16ocdv9{transform:perspective(1000px) rotateY(90deg);opacity:0}.animot-canvas.transition-flip-in.svelte-16ocdv9{animation:svelte-16ocdv9-animot-flipIn calc(var(--transition-duration) * .6) ease forwards}@keyframes svelte-16ocdv9-animot-fadeIn{0%{opacity:0}to{opacity:1}}@keyframes svelte-16ocdv9-animot-slideInFromRight{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}@keyframes svelte-16ocdv9-animot-slideInFromLeft{0%{transform:translate(-100%);opacity:0}to{transform:translate(0);opacity:1}}@keyframes svelte-16ocdv9-animot-slideInFromBottom{0%{transform:translateY(100%);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes svelte-16ocdv9-animot-slideInFromTop{0%{transform:translateY(-100%);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes svelte-16ocdv9-animot-zoomIn{0%{transform:scale(.5);opacity:0}to{transform:scale(1);opacity:1}}@keyframes svelte-16ocdv9-animot-zoomOut{0%{transform:scale(1.5);opacity:0}to{transform:scale(1);opacity:1}}@keyframes svelte-16ocdv9-animot-flipIn{0%{transform:perspective(1000px) rotateY(-90deg);opacity:0}to{transform:perspective(1000px) rotateY(0);opacity:1}}.animot-controls.svelte-16ocdv9{position:absolute;bottom:12px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:8px;padding:8px 16px;background:#000000b3;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-radius:10px;opacity:0;transition:opacity .3s ease .15s;z-index:100}.animot-presenter.svelte-16ocdv9:hover .animot-controls:where(.svelte-16ocdv9),.animot-menu-visible.svelte-16ocdv9 .animot-controls:where(.svelte-16ocdv9){opacity:1;transition-delay:0s}.animot-controls.svelte-16ocdv9 button:where(.svelte-16ocdv9){display:flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:6px;border:none;cursor:pointer;background:#ffffff1a;color:#fff;transition:background .2s}.animot-controls.svelte-16ocdv9 button:where(.svelte-16ocdv9):hover:not(:disabled){background:#fff3}.animot-controls.svelte-16ocdv9 button:where(.svelte-16ocdv9):disabled{opacity:.3;cursor:not-allowed}.animot-controls.svelte-16ocdv9 button.active:where(.svelte-16ocdv9){background:#6366f199}.animot-controls.svelte-16ocdv9 button:where(.svelte-16ocdv9) svg:where(.svelte-16ocdv9){width:16px;height:16px}.animot-slide-indicator.svelte-16ocdv9{font-size:12px;color:#fff;min-width:50px;text-align:center;font-family:system-ui,sans-serif}.animot-arrow.svelte-16ocdv9{position:absolute;top:50%;transform:translateY(-50%);width:40px;height:40px;border-radius:50%;border:none;cursor:pointer;background:#00000080;color:#fff;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .3s .15s;z-index:100;padding:0;margin:0}.animot-presenter.svelte-16ocdv9:hover .animot-arrow:where(.svelte-16ocdv9){opacity:1;transition-delay:0s}.animot-presenter.svelte-16ocdv9:hover .animot-arrow:where(.svelte-16ocdv9):disabled{opacity:.3;cursor:not-allowed}.animot-arrow.svelte-16ocdv9:hover:not(:disabled){background:#000000b3}.animot-arrow.svelte-16ocdv9 svg:where(.svelte-16ocdv9){width:20px;height:20px}.animot-arrow-left.svelte-16ocdv9{left:8px}.animot-arrow-right.svelte-16ocdv9{right:8px}.animot-progress-bar.svelte-16ocdv9{position:absolute;bottom:0;left:0;right:0;height:3px;background:#ffffff1a;z-index:100;opacity:0;transition:opacity .3s .15s}.animot-presenter.svelte-16ocdv9:hover .animot-progress-bar:where(.svelte-16ocdv9){opacity:1;transition-delay:0s}.animot-progress-fill.svelte-16ocdv9{height:100%;background:linear-gradient(135deg,#7c3aed,#ec4899);transition:width .6s ease}.animot-loading.svelte-16ocdv9{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.animot-spinner.svelte-16ocdv9{width:32px;height:32px;border:3px solid rgba(255,255,255,.2);border-top-color:#7c3aed;border-radius:50%;animation:svelte-16ocdv9-animot-spin .8s linear infinite}@keyframes svelte-16ocdv9-animot-spin{to{transform:rotate(360deg)}}.animot-error.svelte-16ocdv9{color:#ef4444;padding:20px;text-align:center;font-family:system-ui,sans-serif}
|
|
1
|
+
.code-morph.svelte-1hmk0l{width:100%;height:100%;margin:0;padding:0;background:transparent;font-family:var(--font-mono, "JetBrains Mono", monospace);font-size:inherit;line-height:1.6;white-space:pre-wrap;word-wrap:break-word;color:#e6edf3;box-sizing:border-box;overflow:visible}.code-morph.svelte-1hmk0l pre{margin:0;padding:16px;background:transparent!important;font-family:var(--font-mono);font-size:inherit;line-height:1.6;overflow:visible}.code-morph.svelte-1hmk0l code{font-family:inherit;font-size:inherit;font-weight:inherit}.code-morph.svelte-1hmk0l .line-number{display:inline-block;width:2.5em;margin-right:1em;text-align:right;color:#6e7681;-webkit-user-select:none;user-select:none;opacity:.6}.code-morph.svelte-1hmk0l .word-highlight{background:var(--highlight-color, #facc15);color:#000;border-radius:3px;padding:1px 3px;margin:0 -3px;-webkit-box-decoration-break:clone;box-decoration-break:clone;animation:svelte-1hmk0l-fadeHighlight var(--duration, 1s) ease-out forwards}@keyframes svelte-1hmk0l-fadeHighlight{0%{background:var(--highlight-color, #facc15);color:#000}70%{background:var(--highlight-color, #facc15);color:#000}to{background:transparent;color:inherit}}.counter.svelte-1er5jjj{width:100%;height:100%;display:flex;align-items:center;justify-content:center;box-sizing:border-box;overflow:hidden;white-space:nowrap}.chart.svelte-1mq2d7j{width:100%;height:100%;display:flex;flex-direction:column;box-sizing:border-box;overflow:hidden}.chart-title.svelte-1mq2d7j{font-weight:600;text-align:center;margin-bottom:8px}.chart-content.svelte-1mq2d7j{flex:1;min-height:0}.chart-content.svelte-1mq2d7j svg:where(.svelte-1mq2d7j){width:100%;height:100%}.bar-chart.svelte-1mq2d7j,.line-chart.svelte-1mq2d7j{overflow:visible}.icon-element.svelte-2ld65o{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.icon-element.svelte-2ld65o svg{width:100%;height:100%}@keyframes float-vertical{0%,to{translate:0 0}50%{translate:0 calc(-1 * var(--float-amp, 10px))}}@keyframes float-horizontal{0%,to{translate:0 0}50%{translate:var(--float-amp, 10px) 0}}@keyframes float-both-0{0%{translate:0 0}15%{translate:calc(.8 * var(--float-amp, 10px)) calc(-.6 * var(--float-amp, 10px))}35%{translate:calc(-.4 * var(--float-amp, 10px)) calc(-1 * var(--float-amp, 10px))}55%{translate:calc(-.9 * var(--float-amp, 10px)) calc(.3 * var(--float-amp, 10px))}75%{translate:calc(.3 * var(--float-amp, 10px)) calc(.7 * var(--float-amp, 10px))}to{translate:0 0}}@keyframes float-both-1{0%{translate:0 0}20%{translate:calc(-.7 * var(--float-amp, 10px)) calc(-.8 * var(--float-amp, 10px))}40%{translate:calc(.5 * var(--float-amp, 10px)) calc(-.3 * var(--float-amp, 10px))}60%{translate:calc(.9 * var(--float-amp, 10px)) calc(.6 * var(--float-amp, 10px))}80%{translate:calc(-.4 * var(--float-amp, 10px)) calc(.9 * var(--float-amp, 10px))}to{translate:0 0}}@keyframes float-both-2{0%{translate:0 0}12%{translate:calc(.6 * var(--float-amp, 10px)) calc(.5 * var(--float-amp, 10px))}30%{translate:calc(1 * var(--float-amp, 10px)) calc(-.4 * var(--float-amp, 10px))}50%{translate:calc(-.3 * var(--float-amp, 10px)) calc(-.9 * var(--float-amp, 10px))}70%{translate:calc(-.8 * var(--float-amp, 10px)) calc(.2 * var(--float-amp, 10px))}88%{translate:calc(.2 * var(--float-amp, 10px)) calc(.8 * var(--float-amp, 10px))}to{translate:0 0}}@keyframes float-both-3{0%{translate:0 0}17%{translate:calc(-.9 * var(--float-amp, 10px)) calc(.4 * var(--float-amp, 10px))}33%{translate:calc(-.5 * var(--float-amp, 10px)) calc(-.7 * var(--float-amp, 10px))}50%{translate:calc(.7 * var(--float-amp, 10px)) calc(-.9 * var(--float-amp, 10px))}67%{translate:calc(.9 * var(--float-amp, 10px)) calc(.5 * var(--float-amp, 10px))}83%{translate:calc(-.2 * var(--float-amp, 10px)) calc(.8 * var(--float-amp, 10px))}to{translate:0 0}}.animot-presenter.svelte-16ocdv9{position:relative;width:100%;height:100%;display:flex;align-items:center;justify-content:center;overflow:hidden;background:transparent}.animot-canvas-wrapper.svelte-16ocdv9{display:flex;align-items:center;justify-content:center}.animot-canvas.svelte-16ocdv9{position:relative;overflow:hidden}.animot-element.svelte-16ocdv9{position:absolute;box-sizing:border-box;will-change:transform,opacity,left,top,width,height;isolation:isolate}.animot-element.floating.svelte-16ocdv9{animation-duration:var(--float-speed, 3s);animation-timing-function:ease-in-out;animation-iteration-count:infinite;animation-delay:var(--float-delay, 0s)}.animot-code-block.svelte-16ocdv9{width:100%;height:100%;background:#0d1117;overflow:hidden;display:flex;flex-direction:column;box-shadow:0 8px 32px #0006;margin:0;box-sizing:border-box}.animot-code-block.transparent-bg.svelte-16ocdv9{background:transparent;box-shadow:none}.animot-code-block.transparent-bg.svelte-16ocdv9 .animot-code-header:where(.svelte-16ocdv9){background:transparent;border-bottom-color:#ffffff1a}.animot-code-header.svelte-16ocdv9{display:flex;align-items:center;gap:12px;padding:12px 16px;background:#161b22;border-bottom:1px solid #30363d;flex-shrink:0}.animot-window-controls.svelte-16ocdv9{display:flex;gap:8px}.animot-control.svelte-16ocdv9{width:12px;height:12px;border-radius:50%;display:block}.macos.svelte-16ocdv9 .animot-control.close:where(.svelte-16ocdv9){background:#ff5f57}.macos.svelte-16ocdv9 .animot-control.minimize:where(.svelte-16ocdv9){background:#febc2e}.macos.svelte-16ocdv9 .animot-control.maximize:where(.svelte-16ocdv9){background:#28c840}.animot-filename.svelte-16ocdv9{color:#8b949e;font-size:14px;flex:1}.animot-code-content.svelte-16ocdv9{flex:1;overflow:hidden;position:relative}.animot-highlighted-code.svelte-16ocdv9{width:100%;height:100%}.animot-code-content.svelte-16ocdv9 pre,.animot-highlighted-code.svelte-16ocdv9 pre{margin:0;padding:16px;background:transparent!important;line-height:1.6;font-size:inherit;overflow:visible}.animot-highlighted-code.svelte-16ocdv9 code{font-family:inherit;font-size:inherit;font-weight:inherit}.animot-highlighted-code.svelte-16ocdv9 .line-number{display:inline-block;width:2.5em;margin-right:1em;text-align:right;color:#6e7681;-webkit-user-select:none;user-select:none;opacity:.6}.animot-text-element.svelte-16ocdv9{width:100%;height:100%;display:flex;align-items:center;white-space:pre-wrap;word-wrap:break-word}.animot-typewriter-cursor.svelte-16ocdv9{animation:svelte-16ocdv9-animot-blink .7s infinite;font-weight:100}@keyframes svelte-16ocdv9-animot-blink{0%,50%{opacity:1}51%,to{opacity:0}}.animot-arrow-element.svelte-16ocdv9{width:100%;height:100%}.arrow-animate-draw.svelte-16ocdv9 .arrow-path:where(.svelte-16ocdv9){stroke-dasharray:1000;stroke-dashoffset:1000;animation:svelte-16ocdv9-animot-arrow-draw var(--arrow-anim-duration, .5s) ease-out forwards}.arrow-head-styled-draw.svelte-16ocdv9{opacity:0;animation:svelte-16ocdv9-animot-arrow-head-appear var(--arrow-anim-duration, .5s) ease-out forwards;animation-delay:calc(var(--arrow-anim-duration, .5s) * .7)}.arrow-animate-draw.svelte-16ocdv9 .arrow-head:where(.svelte-16ocdv9){opacity:0;animation:svelte-16ocdv9-animot-arrow-head-appear var(--arrow-anim-duration, .5s) ease-out forwards;animation-delay:calc(var(--arrow-anim-duration, .5s) * .7)}.arrow-animate-grow.svelte-16ocdv9{transform-origin:left center;animation:svelte-16ocdv9-animot-arrow-grow var(--arrow-anim-duration, .5s) ease-out forwards}@keyframes svelte-16ocdv9-animot-arrow-draw{to{stroke-dashoffset:0}}@keyframes svelte-16ocdv9-animot-arrow-head-appear{0%{opacity:0}to{opacity:1}}@keyframes svelte-16ocdv9-animot-arrow-grow{0%{transform:scaleX(0);opacity:0}to{transform:scaleX(1);opacity:1}}.animot-image-element.svelte-16ocdv9{width:100%;height:100%;display:block}.animot-shape-element.svelte-16ocdv9{width:100%;height:100%;display:block;overflow:visible}.animot-canvas.svelte-16ocdv9{--transition-duration: .5s;transition:transform calc(var(--transition-duration) * .4) ease,opacity calc(var(--transition-duration) * .4) ease}.animot-canvas.transition-fade-out.svelte-16ocdv9{opacity:0}.animot-canvas.transition-fade-in.svelte-16ocdv9{animation:svelte-16ocdv9-animot-fadeIn calc(var(--transition-duration) * .6) ease forwards}.animot-canvas.transition-slide-left-out.forward.svelte-16ocdv9{transform:translate(-100%);opacity:0}.animot-canvas.transition-slide-left-in.forward.svelte-16ocdv9{animation:svelte-16ocdv9-animot-slideInFromRight calc(var(--transition-duration) * .6) ease forwards}.animot-canvas.transition-slide-left-out.backward.svelte-16ocdv9{transform:translate(100%);opacity:0}.animot-canvas.transition-slide-left-in.backward.svelte-16ocdv9{animation:svelte-16ocdv9-animot-slideInFromLeft calc(var(--transition-duration) * .6) ease forwards}.animot-canvas.transition-slide-right-out.forward.svelte-16ocdv9{transform:translate(100%);opacity:0}.animot-canvas.transition-slide-right-in.forward.svelte-16ocdv9{animation:svelte-16ocdv9-animot-slideInFromLeft calc(var(--transition-duration) * .6) ease forwards}.animot-canvas.transition-slide-up-out.svelte-16ocdv9{transform:translateY(-100%);opacity:0}.animot-canvas.transition-slide-up-in.svelte-16ocdv9{animation:svelte-16ocdv9-animot-slideInFromBottom calc(var(--transition-duration) * .6) ease forwards}.animot-canvas.transition-slide-down-out.svelte-16ocdv9{transform:translateY(100%);opacity:0}.animot-canvas.transition-slide-down-in.svelte-16ocdv9{animation:svelte-16ocdv9-animot-slideInFromTop calc(var(--transition-duration) * .6) ease forwards}.animot-canvas.transition-zoom-in-out.svelte-16ocdv9{transform:scale(.5);opacity:0}.animot-canvas.transition-zoom-in-in.svelte-16ocdv9{animation:svelte-16ocdv9-animot-zoomIn calc(var(--transition-duration) * .6) ease forwards}.animot-canvas.transition-zoom-out-out.svelte-16ocdv9{transform:scale(1.5);opacity:0}.animot-canvas.transition-zoom-out-in.svelte-16ocdv9{animation:svelte-16ocdv9-animot-zoomOut calc(var(--transition-duration) * .6) ease forwards}.animot-canvas.transition-flip-out.svelte-16ocdv9{transform:perspective(1000px) rotateY(90deg);opacity:0}.animot-canvas.transition-flip-in.svelte-16ocdv9{animation:svelte-16ocdv9-animot-flipIn calc(var(--transition-duration) * .6) ease forwards}@keyframes svelte-16ocdv9-animot-fadeIn{0%{opacity:0}to{opacity:1}}@keyframes svelte-16ocdv9-animot-slideInFromRight{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}@keyframes svelte-16ocdv9-animot-slideInFromLeft{0%{transform:translate(-100%);opacity:0}to{transform:translate(0);opacity:1}}@keyframes svelte-16ocdv9-animot-slideInFromBottom{0%{transform:translateY(100%);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes svelte-16ocdv9-animot-slideInFromTop{0%{transform:translateY(-100%);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes svelte-16ocdv9-animot-zoomIn{0%{transform:scale(.5);opacity:0}to{transform:scale(1);opacity:1}}@keyframes svelte-16ocdv9-animot-zoomOut{0%{transform:scale(1.5);opacity:0}to{transform:scale(1);opacity:1}}@keyframes svelte-16ocdv9-animot-flipIn{0%{transform:perspective(1000px) rotateY(-90deg);opacity:0}to{transform:perspective(1000px) rotateY(0);opacity:1}}.animot-canvas.transition-flip-x-out.svelte-16ocdv9{transform:perspective(1000px) rotateX(90deg);opacity:0}.animot-canvas.transition-flip-x-in.svelte-16ocdv9{animation:svelte-16ocdv9-animot-flipXIn calc(var(--transition-duration) * .6) ease forwards}@keyframes svelte-16ocdv9-animot-flipXIn{0%{transform:perspective(1000px) rotateX(-90deg);opacity:0}to{transform:perspective(1000px) rotateX(0);opacity:1}}.animot-canvas.transition-flip-y-out.svelte-16ocdv9{transform:perspective(1000px) rotateY(90deg);opacity:0}.animot-canvas.transition-flip-y-in.svelte-16ocdv9{animation:svelte-16ocdv9-animot-flipYIn calc(var(--transition-duration) * .6) ease forwards}@keyframes svelte-16ocdv9-animot-flipYIn{0%{transform:perspective(1000px) rotateY(-90deg);opacity:0}to{transform:perspective(1000px) rotateY(0);opacity:1}}.animot-svg-element.svelte-16ocdv9{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.animot-svg-element.svelte-16ocdv9 svg{width:100%;height:100%}.animot-controls.svelte-16ocdv9{position:absolute;bottom:12px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:8px;padding:8px 16px;background:#000000b3;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-radius:10px;opacity:0;transition:opacity .3s ease .15s;z-index:100}.animot-presenter.svelte-16ocdv9:hover .animot-controls:where(.svelte-16ocdv9),.animot-menu-visible.svelte-16ocdv9 .animot-controls:where(.svelte-16ocdv9){opacity:1;transition-delay:0s}.animot-controls.svelte-16ocdv9 button:where(.svelte-16ocdv9){display:flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:6px;border:none;cursor:pointer;background:#ffffff1a;color:#fff;transition:background .2s}.animot-controls.svelte-16ocdv9 button:where(.svelte-16ocdv9):hover:not(:disabled){background:#fff3}.animot-controls.svelte-16ocdv9 button:where(.svelte-16ocdv9):disabled{opacity:.3;cursor:not-allowed}.animot-controls.svelte-16ocdv9 button.active:where(.svelte-16ocdv9){background:#6366f199}.animot-controls.svelte-16ocdv9 button:where(.svelte-16ocdv9) svg:where(.svelte-16ocdv9){width:16px;height:16px}.animot-slide-indicator.svelte-16ocdv9{font-size:12px;color:#fff;min-width:50px;text-align:center;font-family:system-ui,sans-serif}.animot-arrow.svelte-16ocdv9{position:absolute;top:50%;transform:translateY(-50%);width:40px;height:40px;border-radius:50%;border:none;cursor:pointer;background:#00000080;color:#fff;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .3s .15s;z-index:100;padding:0;margin:0}.animot-presenter.svelte-16ocdv9:hover .animot-arrow:where(.svelte-16ocdv9){opacity:1;transition-delay:0s}.animot-presenter.svelte-16ocdv9:hover .animot-arrow:where(.svelte-16ocdv9):disabled{opacity:.3;cursor:not-allowed}.animot-arrow.svelte-16ocdv9:hover:not(:disabled){background:#000000b3}.animot-arrow.svelte-16ocdv9 svg:where(.svelte-16ocdv9){width:20px;height:20px}.animot-arrow-left.svelte-16ocdv9{left:8px}.animot-arrow-right.svelte-16ocdv9{right:8px}.animot-progress-bar.svelte-16ocdv9{position:absolute;bottom:0;left:0;right:0;height:3px;background:#ffffff1a;z-index:100;opacity:0;transition:opacity .3s .15s}.animot-presenter.svelte-16ocdv9:hover .animot-progress-bar:where(.svelte-16ocdv9){opacity:1;transition-delay:0s}.animot-progress-fill.svelte-16ocdv9{height:100%;background:linear-gradient(135deg,#7c3aed,#ec4899);transition:width .6s ease}.animot-loading.svelte-16ocdv9{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.animot-spinner.svelte-16ocdv9{width:32px;height:32px;border:3px solid rgba(255,255,255,.2);border-top-color:#7c3aed;border-radius:50%;animation:svelte-16ocdv9-animot-spin .8s linear infinite}@keyframes svelte-16ocdv9-animot-spin{to{transform:rotate(360deg)}}.animot-error.svelte-16ocdv9{color:#ef4444;padding:20px;text-align:center;font-family:system-ui,sans-serif}
|