animot-presenter 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +12 -0
- package/README.md +582 -0
- package/dist/AnimotPresenter.svelte +979 -0
- package/dist/AnimotPresenter.svelte.d.ts +14 -0
- package/dist/cdn/animot-presenter.css +1 -0
- package/dist/cdn/animot-presenter.esm.js +12427 -0
- package/dist/cdn/animot-presenter.min.js +16 -0
- package/dist/effects/ConfettiEffect.svelte +83 -0
- package/dist/effects/ConfettiEffect.svelte.d.ts +9 -0
- package/dist/effects/ParticlesBackground.svelte +114 -0
- package/dist/effects/ParticlesBackground.svelte.d.ts +9 -0
- package/dist/element.d.ts +24 -0
- package/dist/element.js +128 -0
- package/dist/engine/utils.d.ts +22 -0
- package/dist/engine/utils.js +72 -0
- package/dist/highlight/CodeMorph.svelte +136 -0
- package/dist/highlight/CodeMorph.svelte.d.ts +16 -0
- package/dist/highlight/highlighter-web.d.ts +10 -0
- package/dist/highlight/highlighter-web.js +54 -0
- package/dist/highlight/highlighter.d.ts +6 -0
- package/dist/highlight/highlighter.js +45 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -0
- package/dist/renderers/ChartRenderer.svelte +341 -0
- package/dist/renderers/ChartRenderer.svelte.d.ts +8 -0
- package/dist/renderers/CounterRenderer.svelte +64 -0
- package/dist/renderers/CounterRenderer.svelte.d.ts +8 -0
- package/dist/renderers/IconRenderer.svelte +18 -0
- package/dist/renderers/IconRenderer.svelte.d.ts +7 -0
- package/dist/styles/presenter.css +48 -0
- package/dist/types.d.ts +319 -0
- package/dist/types.js +1 -0
- package/package.json +83 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Business Source License 1.1
|
|
2
|
+
|
|
3
|
+
Licensor: Beeblock
|
|
4
|
+
Licensed Work: animot-presenter
|
|
5
|
+
Change Date: Four years from each release date
|
|
6
|
+
Change License: Apache License, Version 2.0
|
|
7
|
+
|
|
8
|
+
The full text of the Business Source License 1.1 is available at:
|
|
9
|
+
https://mariadb.com/bsl11/
|
|
10
|
+
|
|
11
|
+
Usage Grant: You may use the Licensed Work for any non-commercial purpose.
|
|
12
|
+
Commercial use requires a separate license from the Licensor.
|
package/README.md
ADDED
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
# animot-presenter
|
|
2
|
+
|
|
3
|
+
Embed animated presentations anywhere. A single `<animot-presenter>` tag that plays [Animot](https://animot.io) animation JSON files with morphing transitions, code syntax highlighting, charts, particles, and more.
|
|
4
|
+
|
|
5
|
+
**Works with any framework:** vanilla HTML/JS, React, Vue, Angular, Svelte, or any frontend stack.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
### npm (recommended for bundled projects)
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install animot-presenter
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### CDN (for vanilla HTML or quick prototyping)
|
|
16
|
+
|
|
17
|
+
```html
|
|
18
|
+
<link rel="stylesheet" href="https://unpkg.com/animot-presenter/dist/cdn/animot-presenter.css">
|
|
19
|
+
<script src="https://unpkg.com/animot-presenter/dist/cdn/animot-presenter.min.js"></script>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Or use the ES module version:
|
|
23
|
+
|
|
24
|
+
```html
|
|
25
|
+
<link rel="stylesheet" href="https://unpkg.com/animot-presenter/dist/cdn/animot-presenter.css">
|
|
26
|
+
<script type="module" src="https://unpkg.com/animot-presenter/dist/cdn/animot-presenter.esm.js"></script>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
```html
|
|
32
|
+
<animot-presenter src="/my-animation.json" autoplay loop controls></animot-presenter>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
That's it. The component loads the JSON, renders the animation canvas, and handles everything — morphing, transitions, code highlighting, keyboard navigation.
|
|
36
|
+
|
|
37
|
+
## Usage by Framework
|
|
38
|
+
|
|
39
|
+
### Vanilla HTML / JavaScript
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<!DOCTYPE html>
|
|
43
|
+
<html>
|
|
44
|
+
<head>
|
|
45
|
+
<script src="https://unpkg.com/animot-presenter/dist/cdn/animot-presenter.min.js"></script>
|
|
46
|
+
<style>
|
|
47
|
+
/* Size the presenter however you want */
|
|
48
|
+
.hero-animation {
|
|
49
|
+
width: 100%;
|
|
50
|
+
height: 500px;
|
|
51
|
+
}
|
|
52
|
+
</style>
|
|
53
|
+
</head>
|
|
54
|
+
<body>
|
|
55
|
+
<animot-presenter
|
|
56
|
+
class="hero-animation"
|
|
57
|
+
src="/animations/hero.json"
|
|
58
|
+
autoplay
|
|
59
|
+
loop
|
|
60
|
+
controls
|
|
61
|
+
></animot-presenter>
|
|
62
|
+
|
|
63
|
+
<script>
|
|
64
|
+
const presenter = document.querySelector('animot-presenter');
|
|
65
|
+
|
|
66
|
+
// Listen for events
|
|
67
|
+
presenter.addEventListener('slidechange', (e) => {
|
|
68
|
+
console.log(`Slide ${e.detail.index + 1} of ${e.detail.total}`);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
presenter.addEventListener('complete', () => {
|
|
72
|
+
console.log('Animation finished');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Load data programmatically
|
|
76
|
+
fetch('/animations/demo.json')
|
|
77
|
+
.then(res => res.json())
|
|
78
|
+
.then(data => {
|
|
79
|
+
presenter.data = data;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Control programmatically
|
|
83
|
+
presenter.next();
|
|
84
|
+
presenter.prev();
|
|
85
|
+
</script>
|
|
86
|
+
</body>
|
|
87
|
+
</html>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Svelte 5
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npm install animot-presenter
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```svelte
|
|
97
|
+
<script>
|
|
98
|
+
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
|
+
</script>
|
|
109
|
+
|
|
110
|
+
<!-- Option A: Load from URL -->
|
|
111
|
+
<div style="width: 100%; height: 500px;">
|
|
112
|
+
<AnimotPresenter
|
|
113
|
+
src="/animations/hero.json"
|
|
114
|
+
autoplay
|
|
115
|
+
loop
|
|
116
|
+
controls
|
|
117
|
+
onslidechange={(index, total) => console.log(`${index + 1}/${total}`)}
|
|
118
|
+
/>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
<!-- Option B: Pass data directly -->
|
|
122
|
+
<div style="width: 800px; height: 450px;">
|
|
123
|
+
{#if animationData}
|
|
124
|
+
<AnimotPresenter data={animationData} controls arrows />
|
|
125
|
+
{/if}
|
|
126
|
+
</div>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### React
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npm install animot-presenter
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
```jsx
|
|
136
|
+
// Import once to register the custom element
|
|
137
|
+
import 'animot-presenter/element';
|
|
138
|
+
import { useEffect, useRef } from 'react';
|
|
139
|
+
|
|
140
|
+
function HeroAnimation() {
|
|
141
|
+
const ref = useRef(null);
|
|
142
|
+
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
const el = ref.current;
|
|
145
|
+
if (!el) return;
|
|
146
|
+
|
|
147
|
+
const handleSlideChange = (e) => {
|
|
148
|
+
console.log(`Slide ${e.detail.index + 1} of ${e.detail.total}`);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
el.addEventListener('slidechange', handleSlideChange);
|
|
152
|
+
return () => el.removeEventListener('slidechange', handleSlideChange);
|
|
153
|
+
}, []);
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
<animot-presenter
|
|
157
|
+
ref={ref}
|
|
158
|
+
src="/animations/hero.json"
|
|
159
|
+
autoplay
|
|
160
|
+
loop
|
|
161
|
+
controls
|
|
162
|
+
style={{ width: '100%', height: '500px', display: 'block' }}
|
|
163
|
+
/>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// With programmatic data
|
|
168
|
+
function ProgrammaticDemo({ data }) {
|
|
169
|
+
const ref = useRef(null);
|
|
170
|
+
|
|
171
|
+
useEffect(() => {
|
|
172
|
+
if (ref.current && data) {
|
|
173
|
+
ref.current.data = data;
|
|
174
|
+
}
|
|
175
|
+
}, [data]);
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
<animot-presenter
|
|
179
|
+
ref={ref}
|
|
180
|
+
controls
|
|
181
|
+
arrows
|
|
182
|
+
style={{ width: '100%', height: '400px', display: 'block' }}
|
|
183
|
+
/>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**TypeScript:** Add this to your `react-app-env.d.ts` or a global `.d.ts` file:
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
declare namespace JSX {
|
|
192
|
+
interface IntrinsicElements {
|
|
193
|
+
'animot-presenter': React.DetailedHTMLProps<
|
|
194
|
+
React.HTMLAttributes<HTMLElement> & {
|
|
195
|
+
src?: string;
|
|
196
|
+
autoplay?: boolean;
|
|
197
|
+
loop?: boolean;
|
|
198
|
+
controls?: boolean;
|
|
199
|
+
arrows?: boolean;
|
|
200
|
+
progress?: boolean;
|
|
201
|
+
keyboard?: boolean;
|
|
202
|
+
duration?: number;
|
|
203
|
+
'start-slide'?: number;
|
|
204
|
+
},
|
|
205
|
+
HTMLElement
|
|
206
|
+
>;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Vue 3
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
npm install animot-presenter
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
```vue
|
|
218
|
+
<script setup>
|
|
219
|
+
import 'animot-presenter/element';
|
|
220
|
+
import { ref, onMounted } from 'vue';
|
|
221
|
+
|
|
222
|
+
const presenterRef = ref(null);
|
|
223
|
+
const animationData = ref(null);
|
|
224
|
+
|
|
225
|
+
function onSlideChange(e) {
|
|
226
|
+
console.log(`Slide ${e.detail.index + 1} of ${e.detail.total}`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Load data programmatically
|
|
230
|
+
onMounted(async () => {
|
|
231
|
+
const res = await fetch('/animations/demo.json');
|
|
232
|
+
animationData.value = await res.json();
|
|
233
|
+
if (presenterRef.value) {
|
|
234
|
+
presenterRef.value.data = animationData.value;
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
</script>
|
|
238
|
+
|
|
239
|
+
<template>
|
|
240
|
+
<!-- Option A: Load from URL -->
|
|
241
|
+
<animot-presenter
|
|
242
|
+
src="/animations/hero.json"
|
|
243
|
+
autoplay
|
|
244
|
+
loop
|
|
245
|
+
controls
|
|
246
|
+
style="width: 100%; height: 500px; display: block"
|
|
247
|
+
@slidechange="onSlideChange"
|
|
248
|
+
/>
|
|
249
|
+
|
|
250
|
+
<!-- Option B: Programmatic data -->
|
|
251
|
+
<animot-presenter
|
|
252
|
+
ref="presenterRef"
|
|
253
|
+
controls
|
|
254
|
+
arrows
|
|
255
|
+
style="width: 800px; height: 450px; display: block"
|
|
256
|
+
/>
|
|
257
|
+
</template>
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**Important:** Tell Vue to treat `animot-presenter` as a custom element. In `vite.config.ts`:
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
export default defineConfig({
|
|
264
|
+
plugins: [
|
|
265
|
+
vue({
|
|
266
|
+
template: {
|
|
267
|
+
compilerOptions: {
|
|
268
|
+
isCustomElement: (tag) => tag === 'animot-presenter'
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
})
|
|
272
|
+
]
|
|
273
|
+
});
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Angular
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
npm install animot-presenter
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**1. Register the custom element** in `main.ts`:
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
import 'animot-presenter/element';
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**2. Allow custom elements** in your module or standalone component:
|
|
289
|
+
|
|
290
|
+
```ts
|
|
291
|
+
// app.module.ts
|
|
292
|
+
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
|
293
|
+
|
|
294
|
+
@NgModule({
|
|
295
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
296
|
+
// ...
|
|
297
|
+
})
|
|
298
|
+
export class AppModule {}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Or in a standalone component:
|
|
302
|
+
|
|
303
|
+
```ts
|
|
304
|
+
@Component({
|
|
305
|
+
selector: 'app-hero',
|
|
306
|
+
standalone: true,
|
|
307
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
308
|
+
template: `
|
|
309
|
+
<animot-presenter
|
|
310
|
+
src="/animations/hero.json"
|
|
311
|
+
autoplay
|
|
312
|
+
loop
|
|
313
|
+
controls
|
|
314
|
+
style="width: 100%; height: 500px; display: block"
|
|
315
|
+
(slidechange)="onSlideChange($event)"
|
|
316
|
+
(complete)="onComplete()"
|
|
317
|
+
></animot-presenter>
|
|
318
|
+
`
|
|
319
|
+
})
|
|
320
|
+
export class HeroComponent {
|
|
321
|
+
onSlideChange(event: CustomEvent) {
|
|
322
|
+
console.log(`Slide ${event.detail.index + 1} of ${event.detail.total}`);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
onComplete() {
|
|
326
|
+
console.log('Animation finished');
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**3. Programmatic control:**
|
|
332
|
+
|
|
333
|
+
```ts
|
|
334
|
+
import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
|
|
335
|
+
|
|
336
|
+
@Component({
|
|
337
|
+
selector: 'app-demo',
|
|
338
|
+
standalone: true,
|
|
339
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
340
|
+
template: `
|
|
341
|
+
<animot-presenter #presenter controls arrows
|
|
342
|
+
style="width: 100%; height: 400px; display: block">
|
|
343
|
+
</animot-presenter>
|
|
344
|
+
<button (click)="loadAnimation()">Load</button>
|
|
345
|
+
`
|
|
346
|
+
})
|
|
347
|
+
export class DemoComponent implements AfterViewInit {
|
|
348
|
+
@ViewChild('presenter') presenterRef!: ElementRef;
|
|
349
|
+
|
|
350
|
+
async loadAnimation() {
|
|
351
|
+
const res = await fetch('/animations/demo.json');
|
|
352
|
+
const data = await res.json();
|
|
353
|
+
this.presenterRef.nativeElement.data = data;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Props / Attributes
|
|
359
|
+
|
|
360
|
+
| Attribute | Type | Default | Description |
|
|
361
|
+
|----------------|-----------|---------|------------------------------------------|
|
|
362
|
+
| `src` | `string` | — | URL to an Animot JSON file |
|
|
363
|
+
| `data` | `object` | — | Inline JSON object (JS property only) |
|
|
364
|
+
| `autoplay` | `boolean` | `false` | Auto-advance slides |
|
|
365
|
+
| `loop` | `boolean` | `false` | Loop back to first slide after last |
|
|
366
|
+
| `controls` | `boolean` | `true` | Show prev/next/play controls |
|
|
367
|
+
| `arrows` | `boolean` | `false` | Show left/right carousel arrows |
|
|
368
|
+
| `progress` | `boolean` | `true` | Show progress bar at bottom |
|
|
369
|
+
| `keyboard` | `boolean` | `true` | Enable arrow key navigation |
|
|
370
|
+
| `duration` | `number` | — | Override all transition durations (ms) |
|
|
371
|
+
| `start-slide` | `number` | `0` | Initial slide index |
|
|
372
|
+
|
|
373
|
+
**Note:** `data` can only be set via JavaScript property, not as an HTML attribute.
|
|
374
|
+
|
|
375
|
+
## Events
|
|
376
|
+
|
|
377
|
+
| Event | Detail | Description |
|
|
378
|
+
|----------------|-------------------------------|--------------------------------------|
|
|
379
|
+
| `slidechange` | `{ index: number, total: number }` | Fired when slide changes |
|
|
380
|
+
| `complete` | — | Fired when last slide is reached |
|
|
381
|
+
|
|
382
|
+
```js
|
|
383
|
+
// Vanilla JS
|
|
384
|
+
presenter.addEventListener('slidechange', (e) => {
|
|
385
|
+
console.log(e.detail.index, e.detail.total);
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
// Svelte
|
|
389
|
+
<AnimotPresenter onslidechange={(i, t) => ...} oncomplete={() => ...} />
|
|
390
|
+
|
|
391
|
+
// Vue
|
|
392
|
+
<animot-presenter @slidechange="handler" @complete="handler" />
|
|
393
|
+
|
|
394
|
+
// Angular
|
|
395
|
+
<animot-presenter (slidechange)="handler($event)" (complete)="handler()" />
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
## Styling
|
|
399
|
+
|
|
400
|
+
The presenter fills its parent container. Control the size by styling the parent:
|
|
401
|
+
|
|
402
|
+
```css
|
|
403
|
+
/* Full page */
|
|
404
|
+
animot-presenter {
|
|
405
|
+
display: block;
|
|
406
|
+
width: 100vw;
|
|
407
|
+
height: 100vh;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/* Hero section */
|
|
411
|
+
animot-presenter {
|
|
412
|
+
display: block;
|
|
413
|
+
width: 100%;
|
|
414
|
+
height: 500px;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/* Fixed size card */
|
|
418
|
+
animot-presenter {
|
|
419
|
+
display: block;
|
|
420
|
+
width: 400px;
|
|
421
|
+
height: 225px;
|
|
422
|
+
border-radius: 12px;
|
|
423
|
+
overflow: hidden;
|
|
424
|
+
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.2);
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
### Customizing Controls
|
|
429
|
+
|
|
430
|
+
Override the built-in styles using CSS specificity:
|
|
431
|
+
|
|
432
|
+
```css
|
|
433
|
+
/* Custom control bar background */
|
|
434
|
+
animot-presenter .animot-controls {
|
|
435
|
+
background: rgba(30, 30, 30, 0.9);
|
|
436
|
+
border-radius: 20px;
|
|
437
|
+
padding: 6px 12px;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/* Custom button style */
|
|
441
|
+
animot-presenter .animot-controls button {
|
|
442
|
+
background: transparent;
|
|
443
|
+
border-radius: 50%;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
animot-presenter .animot-controls button:hover {
|
|
447
|
+
background: rgba(255, 255, 255, 0.15);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/* Custom progress bar */
|
|
451
|
+
animot-presenter .animot-progress-fill {
|
|
452
|
+
background: #3b82f6;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/* Custom arrow buttons */
|
|
456
|
+
animot-presenter .animot-arrow {
|
|
457
|
+
background: rgba(0, 0, 0, 0.6);
|
|
458
|
+
width: 48px;
|
|
459
|
+
height: 48px;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/* Always show controls (no hover needed) */
|
|
463
|
+
animot-presenter .animot-controls,
|
|
464
|
+
animot-presenter .animot-arrow,
|
|
465
|
+
animot-presenter .animot-progress-bar {
|
|
466
|
+
opacity: 1 !important;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/* Hide controls entirely via CSS */
|
|
470
|
+
animot-presenter .animot-controls { display: none; }
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
### Tailwind CSS
|
|
474
|
+
|
|
475
|
+
```html
|
|
476
|
+
<animot-presenter
|
|
477
|
+
class="w-full h-[500px] rounded-xl overflow-hidden shadow-2xl"
|
|
478
|
+
src="/animation.json"
|
|
479
|
+
autoplay
|
|
480
|
+
loop
|
|
481
|
+
></animot-presenter>
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
## Features
|
|
485
|
+
|
|
486
|
+
- **Morphing animations** — Elements with the same ID across slides smoothly morph position, size, rotation, color, opacity, and border radius
|
|
487
|
+
- **Code highlighting** — Syntax highlighting via Shiki with typewriter, highlight-changes, and instant animation modes
|
|
488
|
+
- **Shape morphing** — Rectangles, circles, triangles, stars, hexagons with smooth transitions
|
|
489
|
+
- **Charts** — Animated bar, line, area, pie, and donut charts
|
|
490
|
+
- **Counters** — Animated number counting with formatting
|
|
491
|
+
- **Particles** — Canvas-based particle backgrounds with configurable shapes and connections
|
|
492
|
+
- **Confetti** — Burst, continuous, fireworks, and snow confetti effects
|
|
493
|
+
- **Floating animations** — Gentle floating motion for elements (vertical, horizontal, or both)
|
|
494
|
+
- **Transitions** — Fade, slide, zoom, flip, and morphing (none) transition types
|
|
495
|
+
- **Responsive** — Automatically scales to fit any container size
|
|
496
|
+
- **Keyboard navigation** — Arrow keys, spacebar, Home/End
|
|
497
|
+
- **Property sequencing** — Fine-grained control over which properties animate first
|
|
498
|
+
|
|
499
|
+
## JSON Schema
|
|
500
|
+
|
|
501
|
+
Animot JSON files follow this structure:
|
|
502
|
+
|
|
503
|
+
```json
|
|
504
|
+
{
|
|
505
|
+
"schemaVersion": 1,
|
|
506
|
+
"id": "unique-id",
|
|
507
|
+
"name": "My Animation",
|
|
508
|
+
"slides": [
|
|
509
|
+
{
|
|
510
|
+
"id": "slide-1",
|
|
511
|
+
"name": "Intro",
|
|
512
|
+
"canvas": {
|
|
513
|
+
"width": 1920,
|
|
514
|
+
"height": 1080,
|
|
515
|
+
"background": {
|
|
516
|
+
"type": "gradient",
|
|
517
|
+
"gradient": { "type": "linear", "angle": 135, "colors": ["#1a1a2e", "#16213e"] }
|
|
518
|
+
},
|
|
519
|
+
"elements": [
|
|
520
|
+
{
|
|
521
|
+
"id": "title",
|
|
522
|
+
"type": "text",
|
|
523
|
+
"content": "Hello World",
|
|
524
|
+
"position": { "x": 100, "y": 200 },
|
|
525
|
+
"size": { "width": 600, "height": 80 },
|
|
526
|
+
"fontSize": 48,
|
|
527
|
+
"fontWeight": 700,
|
|
528
|
+
"color": "#ffffff",
|
|
529
|
+
"rotation": 0,
|
|
530
|
+
"visible": true,
|
|
531
|
+
"zIndex": 1
|
|
532
|
+
}
|
|
533
|
+
]
|
|
534
|
+
},
|
|
535
|
+
"transition": { "type": "fade", "duration": 500, "easing": "ease-in-out" },
|
|
536
|
+
"duration": 3000
|
|
537
|
+
}
|
|
538
|
+
],
|
|
539
|
+
"settings": {
|
|
540
|
+
"defaultCanvasWidth": 1920,
|
|
541
|
+
"defaultCanvasHeight": 1080,
|
|
542
|
+
"defaultTransition": { "type": "fade", "duration": 500, "easing": "ease-in-out" },
|
|
543
|
+
"defaultSlideDuration": 3000
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
Create animations visually at [animot.io](https://animot.io) and export as JSON.
|
|
549
|
+
|
|
550
|
+
## Bundle Size
|
|
551
|
+
|
|
552
|
+
| Build | Raw | Gzipped |
|
|
553
|
+
|-------|-----|---------|
|
|
554
|
+
| CDN (IIFE) | ~5.0 MB | ~850 KB |
|
|
555
|
+
| CDN (ESM) | ~5.2 MB | ~870 KB |
|
|
556
|
+
| Svelte (tree-shakeable) | ~56 KB | — |
|
|
557
|
+
|
|
558
|
+
The CDN bundle includes [Shiki](https://shiki.matsu.io/) for code syntax highlighting with 70 web-focused languages (see list below). The npm Svelte package is much smaller since Shiki is loaded lazily at runtime with all 500+ languages available.
|
|
559
|
+
|
|
560
|
+
### CDN supported languages
|
|
561
|
+
|
|
562
|
+
The CDN bundle includes these languages for code highlighting:
|
|
563
|
+
|
|
564
|
+
`angular-html`, `angular-ts`, `astro`, `bash`, `blade`, `c`, `c++`, `coffee`, `cpp`, `css`, `glsl`, `gql`, `graphql`, `haml`, `handlebars`, `html`, `http`, `imba`, `java`, `javascript`, `jinja`, `jison`, `json`, `json5`, `jsonc`, `jsonl`, `js`, `jsx`, `julia`, `less`, `lit`, `markdown`, `marko`, `mdc`, `mdx`, `php`, `postcss`, `pug`, `python`, `r`, `regex`, `sass`, `scss`, `sh`, `shell`, `sql`, `stylus`, `svelte`, `ts`, `tsx`, `typescript`, `vue`, `wasm`, `wgsl`, `xml`, `yaml`, `yml`, `zsh`
|
|
565
|
+
|
|
566
|
+
> **npm install** gives you all 500+ Shiki languages. The CDN bundle uses the lighter `shiki/bundle/web` with 70 common web/programming languages. If your code blocks use an unsupported language, it falls back to JavaScript highlighting.
|
|
567
|
+
|
|
568
|
+
## Browser Support
|
|
569
|
+
|
|
570
|
+
Works in all modern browsers that support Custom Elements v1:
|
|
571
|
+
- Chrome 67+
|
|
572
|
+
- Firefox 63+
|
|
573
|
+
- Safari 10.1+
|
|
574
|
+
- Edge 79+
|
|
575
|
+
|
|
576
|
+
## License
|
|
577
|
+
|
|
578
|
+
Business Source License 1.1 (BUSL-1.1)
|
|
579
|
+
|
|
580
|
+
- **Free** for non-commercial and personal use
|
|
581
|
+
- **Commercial use** requires a paid license — contact support@beeblock.com.br
|
|
582
|
+
- After the change date (4 years from each release), the code converts to Apache-2.0
|