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 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