animot-presenter 0.1.3 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AnimotPresenter.svelte +236 -12
- package/dist/cdn/animot-presenter.css +1 -1
- package/dist/cdn/animot-presenter.esm.js +4664 -4473
- package/dist/cdn/animot-presenter.min.js +10 -10
- 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 +43 -4
- package/package.json +1 -1
|
@@ -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 });
|
|
@@ -322,6 +444,16 @@
|
|
|
322
444
|
}
|
|
323
445
|
}
|
|
324
446
|
|
|
447
|
+
// Update elementContent BEFORE animations start so rendered elements
|
|
448
|
+
// (especially SVG viewBox) use target slide data while animating
|
|
449
|
+
for (const elementId of allElementIds) {
|
|
450
|
+
const targetEl = getElementInSlide(targetSlide, elementId);
|
|
451
|
+
if (targetEl && targetEl.type !== 'code') {
|
|
452
|
+
elementContent.set(elementId, JSON.parse(JSON.stringify(targetEl)));
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
elementContent = new Map(elementContent);
|
|
456
|
+
|
|
325
457
|
interface AnimationTask { elementId: string; order: number; delay: number; elementDuration: number; run: () => Promise<void>[]; }
|
|
326
458
|
const animationTasks: AnimationTask[] = [];
|
|
327
459
|
|
|
@@ -336,7 +468,7 @@
|
|
|
336
468
|
const elementDuration = animConfig?.duration ?? duration;
|
|
337
469
|
|
|
338
470
|
if (targetEl) {
|
|
339
|
-
const easing =
|
|
471
|
+
const easing = getEasingFn(animConfig?.easing);
|
|
340
472
|
const propertySequences = targetEl.animationConfig?.propertySequences;
|
|
341
473
|
if (targetEl.type === 'text') {
|
|
342
474
|
const textEl = targetEl as TextElement;
|
|
@@ -361,6 +493,7 @@
|
|
|
361
493
|
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
494
|
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
495
|
if (!sequencedProps.has('borderRadius')) anims.push(animated.borderRadius.to((targetEl as any).borderRadius ?? 0, { duration: elementDuration, easing }));
|
|
496
|
+
if (!sequencedProps.has('perspective')) anims.push(animated.perspective.to(targetEl.perspective ?? 1000, { duration: elementDuration, easing }));
|
|
364
497
|
const sortedSeqs = [...propertySequences].sort((a, b) => a.order - b.order);
|
|
365
498
|
let cumulativeDelay = 0;
|
|
366
499
|
for (const seq of sortedSeqs) {
|
|
@@ -379,6 +512,7 @@
|
|
|
379
512
|
animated.strokeColor?.to(s.strokeColor, { duration: seqDuration, easing });
|
|
380
513
|
animated.strokeWidth?.to(s.strokeWidth, { duration: seqDuration, easing });
|
|
381
514
|
}
|
|
515
|
+
else if (seq.property === 'perspective') animated.perspective.to(targetEl.perspective ?? 1000, { duration: seqDuration, easing });
|
|
382
516
|
}, seqDelay);
|
|
383
517
|
cumulativeDelay = seqDelay + seqDuration;
|
|
384
518
|
}
|
|
@@ -393,8 +527,19 @@
|
|
|
393
527
|
anims.push(animated.skewY.to(targetEl.skewY ?? 0, { duration: elementDuration, easing }));
|
|
394
528
|
anims.push(animated.tiltX.to(targetEl.tiltX ?? 0, { duration: elementDuration, easing }));
|
|
395
529
|
anims.push(animated.tiltY.to(targetEl.tiltY ?? 0, { duration: elementDuration, easing }));
|
|
530
|
+
anims.push(animated.perspective.to(targetEl.perspective ?? 1000, { duration: elementDuration, easing }));
|
|
396
531
|
anims.push(animated.borderRadius.to((targetEl as any).borderRadius ?? 0, { duration: elementDuration, easing }));
|
|
397
532
|
}
|
|
533
|
+
// Motion path progress — await reset, then animate forward
|
|
534
|
+
if (animated.motionPathProgress && targetEl.motionPathConfig) {
|
|
535
|
+
const shouldLoop = targetEl.motionPathConfig.loop;
|
|
536
|
+
if (!shouldLoop) {
|
|
537
|
+
anims.push((async () => {
|
|
538
|
+
await animated.motionPathProgress!.to(0, { duration: 0 });
|
|
539
|
+
await animated.motionPathProgress!.to(1, { duration: elementDuration, easing });
|
|
540
|
+
})());
|
|
541
|
+
}
|
|
542
|
+
}
|
|
398
543
|
if (targetEl.type === 'text' && animated.fontSize) anims.push(animated.fontSize.to((targetEl as TextElement).fontSize, { duration: elementDuration, easing }));
|
|
399
544
|
if (targetEl.type === 'shape' && currentEl?.type === 'shape') {
|
|
400
545
|
const ts = targetEl as ShapeElement;
|
|
@@ -416,12 +561,47 @@
|
|
|
416
561
|
if (animated.strokeColor) anims.push(animated.strokeColor.to(s.strokeColor, { duration: elementDuration, easing }));
|
|
417
562
|
if (animated.strokeWidth) anims.push(animated.strokeWidth.to(s.strokeWidth, { duration: elementDuration, easing }));
|
|
418
563
|
}
|
|
419
|
-
if (!currentEl)
|
|
564
|
+
if (!currentEl) {
|
|
565
|
+
// Snap ALL properties to target instantly — the tween may hold
|
|
566
|
+
// stale values from a previous slide where the element last appeared
|
|
567
|
+
anims.push(animated.x.to(targetEl.position.x, { duration: 0 }));
|
|
568
|
+
anims.push(animated.y.to(targetEl.position.y, { duration: 0 }));
|
|
569
|
+
anims.push(animated.width.to(targetEl.size.width, { duration: 0 }));
|
|
570
|
+
anims.push(animated.height.to(targetEl.size.height, { duration: 0 }));
|
|
571
|
+
anims.push(animated.rotation.to(targetEl.rotation, { duration: 0 }));
|
|
572
|
+
anims.push(animated.skewX.to(targetEl.skewX ?? 0, { duration: 0 }));
|
|
573
|
+
anims.push(animated.skewY.to(targetEl.skewY ?? 0, { duration: 0 }));
|
|
574
|
+
anims.push(animated.tiltX.to(targetEl.tiltX ?? 0, { duration: 0 }));
|
|
575
|
+
anims.push(animated.tiltY.to(targetEl.tiltY ?? 0, { duration: 0 }));
|
|
576
|
+
anims.push(animated.perspective.to(targetEl.perspective ?? 1000, { duration: 0 }));
|
|
577
|
+
anims.push(animated.borderRadius.to((targetEl as any).borderRadius ?? 0, { duration: 0 }));
|
|
578
|
+
if (targetEl.type === 'text' && animated.fontSize) {
|
|
579
|
+
anims.push(animated.fontSize.to((targetEl as TextElement).fontSize, { duration: 0 }));
|
|
580
|
+
}
|
|
581
|
+
if (targetEl.type === 'shape') {
|
|
582
|
+
const s = targetEl as ShapeElement;
|
|
583
|
+
if (animated.fillColor) anims.push(animated.fillColor.to(s.fillColor, { duration: 0 }));
|
|
584
|
+
if (animated.strokeColor) anims.push(animated.strokeColor.to(s.strokeColor, { duration: 0 }));
|
|
585
|
+
if (animated.strokeWidth) anims.push(animated.strokeWidth.to(s.strokeWidth, { duration: 0 }));
|
|
586
|
+
}
|
|
587
|
+
const entrance = targetEl.animationConfig?.entrance ?? 'fade';
|
|
588
|
+
if (entrance === 'fade') {
|
|
589
|
+
anims.push(animated.opacity.to(1, { duration: elementDuration / 2, easing }));
|
|
590
|
+
} else {
|
|
591
|
+
anims.push(animated.opacity.to(1, { duration: 0 }));
|
|
592
|
+
}
|
|
593
|
+
}
|
|
420
594
|
return anims;
|
|
421
595
|
}
|
|
422
596
|
});
|
|
423
597
|
} else if (currentEl) {
|
|
424
|
-
|
|
598
|
+
const exit = currentEl.animationConfig?.exit ?? 'fade';
|
|
599
|
+
if (exit === 'fade') {
|
|
600
|
+
const fadeOutDuration = Math.min(elementDuration / 2, 300);
|
|
601
|
+
animationTasks.push({ elementId, order, delay, elementDuration, run: () => [animated.opacity.to(0, { duration: fadeOutDuration, easing: easeInOutCubic })] });
|
|
602
|
+
} else {
|
|
603
|
+
animationTasks.push({ elementId, order, delay: 0, elementDuration: 0, run: () => [animated.opacity.to(0, { duration: 0 })] });
|
|
604
|
+
}
|
|
425
605
|
}
|
|
426
606
|
}
|
|
427
607
|
|
|
@@ -479,6 +659,7 @@
|
|
|
479
659
|
elementContent = newElementContent;
|
|
480
660
|
currentSlideIndex = targetIndex;
|
|
481
661
|
isTransitioning = false;
|
|
662
|
+
animateMotionPaths(slides[targetIndex]);
|
|
482
663
|
onslidechange?.(targetIndex, slides.length);
|
|
483
664
|
if (targetIndex === slides.length - 1 && !loop) oncomplete?.();
|
|
484
665
|
}
|
|
@@ -570,6 +751,7 @@
|
|
|
570
751
|
initAllAnimatedElements();
|
|
571
752
|
await loadCodeHighlights();
|
|
572
753
|
loading = false;
|
|
754
|
+
if (currentSlide) setTimeout(() => animateMotionPaths(currentSlide!), 300);
|
|
573
755
|
if (autoplay) isAutoplay = true;
|
|
574
756
|
} catch (e: any) { error = e.message; loading = false; }
|
|
575
757
|
}
|
|
@@ -632,17 +814,27 @@
|
|
|
632
814
|
{@const floatCfg = element?.floatingAnimation}
|
|
633
815
|
{@const hasFloat = floatCfg?.enabled}
|
|
634
816
|
{@const floatGroupId = element?.groupId}
|
|
635
|
-
{
|
|
817
|
+
{@const mpConfig = element?.motionPathConfig}
|
|
818
|
+
{@const mpElement = mpConfig ? currentSlide?.canvas.elements.find(el => el.id === mpConfig.motionPathId) as MotionPathElement | undefined : undefined}
|
|
819
|
+
{@const mpProgress = animated?.motionPathProgress?.current ?? 0}
|
|
820
|
+
{@const mpPoint = mpElement && mpConfig ? getPresenterPointOnPath(mpElement.points, mpElement.closed, (mpConfig.startPercent + (mpConfig.endPercent - mpConfig.startPercent) * mpProgress) / 100) : null}
|
|
821
|
+
{@const elemX = mpPoint ? mpPoint.x - (animated?.width.current ?? 0) / 2 : animated?.x.current ?? 0}
|
|
822
|
+
{@const elemY = mpPoint ? mpPoint.y - (animated?.height.current ?? 0) / 2 : animated?.y.current ?? 0}
|
|
823
|
+
{@const mpRotation = mpPoint && mpConfig?.autoRotate
|
|
824
|
+
? mpPoint.angle + (mpConfig.orientationOffset ?? 0)
|
|
825
|
+
: null}
|
|
826
|
+
{#if element && animated && animated.opacity.current > 0.01 && element.visible !== false && !(element.type === 'motionPath' && !(element as MotionPathElement).showInPresentation)}
|
|
636
827
|
<div
|
|
637
828
|
class="animot-element"
|
|
638
829
|
class:floating={hasFloat}
|
|
639
|
-
style:left="{
|
|
640
|
-
style:top="{
|
|
830
|
+
style:left="{elemX}px"
|
|
831
|
+
style:top="{elemY}px"
|
|
641
832
|
style:width="{animated.width.current}px"
|
|
642
833
|
style:height="{animated.height.current}px"
|
|
643
834
|
style:opacity={animated.opacity.current}
|
|
644
|
-
style:transform="perspective(
|
|
835
|
+
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
836
|
style:transform-origin={element.tiltOrigin ?? 'center'}
|
|
837
|
+
style:backface-visibility={element.backfaceVisibility ?? 'visible'}
|
|
646
838
|
style:z-index={element.zIndex}
|
|
647
839
|
style:--float-amp="{hasFloat ? computeFloatAmp(floatCfg, floatGroupId || elementId) : 10}px"
|
|
648
840
|
style:--float-speed="{hasFloat ? computeFloatSpeed(floatCfg, floatGroupId || elementId) : 3}s"
|
|
@@ -722,7 +914,7 @@
|
|
|
722
914
|
{@const arrowAnimDuration = arrowEl.animation?.duration ?? 500}
|
|
723
915
|
{@const isStyledArrow = arrowEl.style !== 'solid'}
|
|
724
916
|
{@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="
|
|
917
|
+
<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
918
|
<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
919
|
{#if arrowEl.showHead !== false}
|
|
728
920
|
<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 +923,7 @@
|
|
|
731
923
|
{:else if element.type === 'image'}
|
|
732
924
|
{@const imgEl = element as ImageElement}
|
|
733
925
|
{@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} />
|
|
926
|
+
<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
927
|
{:else if element.type === 'shape'}
|
|
736
928
|
{@const shapeEl = element as ShapeElement}
|
|
737
929
|
{@const animFill = animated.fillColor?.current ?? shapeEl.fillColor}
|
|
@@ -758,6 +950,23 @@
|
|
|
758
950
|
<ChartRenderer element={element as ChartElement} slideId={currentSlide?.id ?? ''} />
|
|
759
951
|
{:else if element.type === 'icon'}
|
|
760
952
|
<IconRenderer element={element as IconElement} />
|
|
953
|
+
{:else if element.type === 'svg'}
|
|
954
|
+
{@const svgEl = element as SvgElement}
|
|
955
|
+
{@const svgParsed = (() => { const m = svgEl.svgContent.trim().match(/^<svg([^>]*)>([\s\S]*)<\/svg>$/i); if (m) { const vb = m[1].match(/viewBox=["']([^"']+)["']/i); return { inner: m[2], viewBox: vb ? vb[1] : null }; } return { inner: svgEl.svgContent, viewBox: null }; })()}
|
|
956
|
+
<div class="animot-svg-element" style:opacity={svgEl.opacity}>
|
|
957
|
+
<svg width="100%" height="100%" viewBox={svgEl.viewBox ?? svgParsed.viewBox ?? `0 0 ${svgEl.size.width} ${svgEl.size.height}`} preserveAspectRatio={svgEl.preserveAspectRatio} xmlns="http://www.w3.org/2000/svg">
|
|
958
|
+
<g style={svgEl.color ? `fill:${svgEl.color};stroke:${svgEl.color}` : ''}>
|
|
959
|
+
{@html svgParsed.inner}
|
|
960
|
+
</g>
|
|
961
|
+
</svg>
|
|
962
|
+
</div>
|
|
963
|
+
{:else if element.type === 'motionPath'}
|
|
964
|
+
{@const mpEl = element as MotionPathElement}
|
|
965
|
+
{#if mpEl.showInPresentation}
|
|
966
|
+
<svg width="100%" height="100%" style="position:absolute;top:0;left:0;pointer-events:none;overflow:visible;">
|
|
967
|
+
<path d={buildPresenterPathD(mpEl.points, mpEl.closed)} stroke={mpEl.pathColor} stroke-width={mpEl.pathWidth} fill="none" stroke-dasharray="8 4" />
|
|
968
|
+
</svg>
|
|
969
|
+
{/if}
|
|
761
970
|
{/if}
|
|
762
971
|
</div>
|
|
763
972
|
{/if}
|
|
@@ -848,6 +1057,7 @@
|
|
|
848
1057
|
position: absolute;
|
|
849
1058
|
box-sizing: border-box;
|
|
850
1059
|
will-change: transform, opacity, left, top, width, height;
|
|
1060
|
+
isolation: isolate;
|
|
851
1061
|
}
|
|
852
1062
|
|
|
853
1063
|
.animot-element.floating {
|
|
@@ -929,6 +1139,20 @@
|
|
|
929
1139
|
@keyframes animot-zoomOut { from { transform: scale(1.5); opacity: 0; } to { transform: scale(1); opacity: 1; } }
|
|
930
1140
|
@keyframes animot-flipIn { from { transform: perspective(1000px) rotateY(-90deg); opacity: 0; } to { transform: perspective(1000px) rotateY(0); opacity: 1; } }
|
|
931
1141
|
|
|
1142
|
+
/* Flip-X transition */
|
|
1143
|
+
.animot-canvas.transition-flip-x-out { transform: perspective(1000px) rotateX(90deg); opacity: 0; }
|
|
1144
|
+
.animot-canvas.transition-flip-x-in { animation: animot-flipXIn calc(var(--transition-duration) * 0.6) ease forwards; }
|
|
1145
|
+
@keyframes animot-flipXIn { from { transform: perspective(1000px) rotateX(-90deg); opacity: 0; } to { transform: perspective(1000px) rotateX(0); opacity: 1; } }
|
|
1146
|
+
|
|
1147
|
+
/* Flip-Y transition */
|
|
1148
|
+
.animot-canvas.transition-flip-y-out { transform: perspective(1000px) rotateY(90deg); opacity: 0; }
|
|
1149
|
+
.animot-canvas.transition-flip-y-in { animation: animot-flipYIn calc(var(--transition-duration) * 0.6) ease forwards; }
|
|
1150
|
+
@keyframes animot-flipYIn { from { transform: perspective(1000px) rotateY(-90deg); opacity: 0; } to { transform: perspective(1000px) rotateY(0); opacity: 1; } }
|
|
1151
|
+
|
|
1152
|
+
/* SVG element */
|
|
1153
|
+
.animot-svg-element { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; }
|
|
1154
|
+
.animot-svg-element :global(svg) { width: 100%; height: 100%; }
|
|
1155
|
+
|
|
932
1156
|
/* Controls */
|
|
933
1157
|
.animot-controls {
|
|
934
1158
|
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}
|