animot-presenter 0.5.25 → 0.6.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/dist/AnimotPresenter.svelte +224 -9
- package/dist/cdn/animot-presenter.css +1 -1
- package/dist/cdn/animot-presenter.esm.js +6759 -6283
- package/dist/cdn/animot-presenter.min.js +9 -9
- package/dist/engine/utils.d.ts +7 -0
- package/dist/engine/utils.js +64 -0
- package/dist/styles/presenter.css +170 -0
- package/dist/types.d.ts +11 -3
- package/dist/utils/text-animate.d.ts +1 -1
- package/dist/utils/text-animate.js +371 -0
- package/package.json +1 -1
|
@@ -143,6 +143,347 @@ export function textAnimate(node, params) {
|
|
|
143
143
|
}
|
|
144
144
|
raf = requestAnimationFrame(step);
|
|
145
145
|
}
|
|
146
|
+
// ─── Phase 3 runners (mirrored from animot app) ───────────────────
|
|
147
|
+
function wrapWords(text) {
|
|
148
|
+
const wrap = document.createElement('span');
|
|
149
|
+
wrap.className = 'ta-wrap';
|
|
150
|
+
const words = [];
|
|
151
|
+
const parts = text.split(/(\s+)/);
|
|
152
|
+
for (const p of parts) {
|
|
153
|
+
if (/^\s+$/.test(p))
|
|
154
|
+
wrap.appendChild(document.createTextNode(p));
|
|
155
|
+
else if (p.length > 0) {
|
|
156
|
+
const w = document.createElement('span');
|
|
157
|
+
w.className = 'ta-word';
|
|
158
|
+
w.style.display = 'inline-block';
|
|
159
|
+
w.textContent = p;
|
|
160
|
+
wrap.appendChild(w);
|
|
161
|
+
words.push(w);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return { wrap, words };
|
|
165
|
+
}
|
|
166
|
+
function runScrambleIn() {
|
|
167
|
+
originalContent = params.content ?? '';
|
|
168
|
+
node.innerHTML = '';
|
|
169
|
+
const wrap = wrapChars(originalContent);
|
|
170
|
+
node.appendChild(wrap);
|
|
171
|
+
const chars = Array.from(wrap.querySelectorAll('.ta-char'));
|
|
172
|
+
const finalText = Array.from(originalContent);
|
|
173
|
+
const stagger = params.stagger ?? Math.max(30, Math.min(80, 800 / Math.max(1, chars.length)));
|
|
174
|
+
const settleMs = 500;
|
|
175
|
+
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%&*';
|
|
176
|
+
const start = performance.now();
|
|
177
|
+
const dur = effectiveDuration();
|
|
178
|
+
function step(now) {
|
|
179
|
+
const elapsed = (now - start) % (params.loop ? Math.max(stagger * chars.length + settleMs, dur) : Number.POSITIVE_INFINITY);
|
|
180
|
+
let allDone = true;
|
|
181
|
+
for (let i = 0; i < chars.length; i++) {
|
|
182
|
+
const local = elapsed - i * stagger;
|
|
183
|
+
if (local < 0) {
|
|
184
|
+
chars[i].textContent = ' ';
|
|
185
|
+
allDone = false;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (local >= settleMs) {
|
|
189
|
+
chars[i].textContent = finalText[i];
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
allDone = false;
|
|
193
|
+
chars[i].textContent = finalText[i] === ' ' ? ' ' : alphabet[(Math.random() * alphabet.length) | 0];
|
|
194
|
+
}
|
|
195
|
+
if (params.loop || !allDone)
|
|
196
|
+
raf = requestAnimationFrame(step);
|
|
197
|
+
else
|
|
198
|
+
raf = 0;
|
|
199
|
+
}
|
|
200
|
+
raf = requestAnimationFrame(step);
|
|
201
|
+
}
|
|
202
|
+
function runSlotMachine() {
|
|
203
|
+
originalContent = params.content ?? '';
|
|
204
|
+
node.innerHTML = '';
|
|
205
|
+
const wrap = wrapChars(originalContent);
|
|
206
|
+
node.appendChild(wrap);
|
|
207
|
+
const chars = Array.from(wrap.querySelectorAll('.ta-char'));
|
|
208
|
+
const finalText = Array.from(originalContent);
|
|
209
|
+
const stagger = params.stagger ?? 60;
|
|
210
|
+
const spinMs = 600;
|
|
211
|
+
const reel = '0123456789!@#$%ABCDEFGH';
|
|
212
|
+
const start = performance.now();
|
|
213
|
+
function step(now) {
|
|
214
|
+
const elapsed = now - start;
|
|
215
|
+
let allDone = true;
|
|
216
|
+
for (let i = 0; i < chars.length; i++) {
|
|
217
|
+
const local = elapsed - i * stagger;
|
|
218
|
+
if (local < 0) {
|
|
219
|
+
chars[i].textContent = ' ';
|
|
220
|
+
allDone = false;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (local >= spinMs) {
|
|
224
|
+
chars[i].textContent = finalText[i];
|
|
225
|
+
chars[i].style.transform = 'translateY(0)';
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
allDone = false;
|
|
229
|
+
const t = local / spinMs;
|
|
230
|
+
const offsetY = (1 - t) * -0.3;
|
|
231
|
+
chars[i].textContent = finalText[i] === ' ' ? ' ' : reel[((local / 60) | 0) % reel.length];
|
|
232
|
+
chars[i].style.transform = `translateY(${offsetY}em)`;
|
|
233
|
+
}
|
|
234
|
+
if (params.loop || !allDone)
|
|
235
|
+
raf = requestAnimationFrame(step);
|
|
236
|
+
else
|
|
237
|
+
raf = 0;
|
|
238
|
+
}
|
|
239
|
+
for (const c of chars)
|
|
240
|
+
c.style.transform = 'translateY(-0.3em)';
|
|
241
|
+
raf = requestAnimationFrame(step);
|
|
242
|
+
}
|
|
243
|
+
function runDrop() {
|
|
244
|
+
originalContent = params.content ?? '';
|
|
245
|
+
node.innerHTML = '';
|
|
246
|
+
const wrap = wrapChars(originalContent);
|
|
247
|
+
node.appendChild(wrap);
|
|
248
|
+
const chars = Array.from(wrap.querySelectorAll('.ta-char'));
|
|
249
|
+
const stagger = params.stagger ?? Math.max(30, Math.min(90, 700 / Math.max(1, chars.length)));
|
|
250
|
+
const perLetter = 520;
|
|
251
|
+
for (const c of chars) {
|
|
252
|
+
c.style.opacity = '0';
|
|
253
|
+
c.style.transform = 'translateY(-1.2em)';
|
|
254
|
+
}
|
|
255
|
+
const start = performance.now();
|
|
256
|
+
function step(now) {
|
|
257
|
+
const elapsed = now - start;
|
|
258
|
+
let allDone = true;
|
|
259
|
+
for (let i = 0; i < chars.length; i++) {
|
|
260
|
+
const t = Math.min(1, Math.max(0, (elapsed - i * stagger) / perLetter));
|
|
261
|
+
if (t < 1)
|
|
262
|
+
allDone = false;
|
|
263
|
+
let b;
|
|
264
|
+
if (t < 0.5)
|
|
265
|
+
b = 4 * t * t * t;
|
|
266
|
+
else
|
|
267
|
+
b = 1 - Math.pow(-2 * t + 2, 3) / 2;
|
|
268
|
+
const overshoot = t > 0.7 ? Math.sin((t - 0.7) * Math.PI / 0.3) * 0.08 : 0;
|
|
269
|
+
const translate = (1 - b) * -1.2 + overshoot;
|
|
270
|
+
chars[i].style.opacity = String(Math.min(1, t * 2));
|
|
271
|
+
chars[i].style.transform = `translateY(${translate}em)`;
|
|
272
|
+
}
|
|
273
|
+
if (!allDone)
|
|
274
|
+
raf = requestAnimationFrame(step);
|
|
275
|
+
else
|
|
276
|
+
raf = 0;
|
|
277
|
+
}
|
|
278
|
+
raf = requestAnimationFrame(step);
|
|
279
|
+
}
|
|
280
|
+
function runGlitch() {
|
|
281
|
+
originalContent = params.content ?? '';
|
|
282
|
+
node.innerHTML = '';
|
|
283
|
+
const wrap = wrapChars(originalContent);
|
|
284
|
+
node.appendChild(wrap);
|
|
285
|
+
const chars = Array.from(wrap.querySelectorAll('.ta-char'));
|
|
286
|
+
const dur = 1100;
|
|
287
|
+
for (const c of chars) {
|
|
288
|
+
c.style.opacity = '0';
|
|
289
|
+
}
|
|
290
|
+
const start = performance.now();
|
|
291
|
+
function step(now) {
|
|
292
|
+
const elapsed = now - start;
|
|
293
|
+
let allDone = true;
|
|
294
|
+
for (let i = 0; i < chars.length; i++) {
|
|
295
|
+
const localStart = (i / Math.max(1, chars.length)) * (dur * 0.4);
|
|
296
|
+
const t = Math.min(1, Math.max(0, (elapsed - localStart) / (dur - localStart)));
|
|
297
|
+
if (t < 1)
|
|
298
|
+
allDone = false;
|
|
299
|
+
const jitter = t < 0.85 ? (Math.random() - 0.5) * 0.08 * (1 - t) : 0;
|
|
300
|
+
const filter = t < 0.7
|
|
301
|
+
? `drop-shadow(${(Math.random() - 0.5) * 4}px 0 0 #06b6d4) drop-shadow(${(Math.random() - 0.5) * 4}px 0 0 #ec4899)`
|
|
302
|
+
: 'none';
|
|
303
|
+
chars[i].style.opacity = String(t);
|
|
304
|
+
chars[i].style.transform = `translate(${jitter}em, ${jitter}em)`;
|
|
305
|
+
chars[i].style.filter = filter;
|
|
306
|
+
}
|
|
307
|
+
if (!allDone)
|
|
308
|
+
raf = requestAnimationFrame(step);
|
|
309
|
+
else {
|
|
310
|
+
for (const c of chars) {
|
|
311
|
+
c.style.filter = 'none';
|
|
312
|
+
c.style.transform = 'none';
|
|
313
|
+
}
|
|
314
|
+
raf = 0;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
raf = requestAnimationFrame(step);
|
|
318
|
+
}
|
|
319
|
+
function runMarquee() {
|
|
320
|
+
originalContent = params.content ?? '';
|
|
321
|
+
node.innerHTML = '';
|
|
322
|
+
const wrap = document.createElement('span');
|
|
323
|
+
wrap.className = 'ta-wrap';
|
|
324
|
+
wrap.style.display = 'inline-block';
|
|
325
|
+
wrap.style.whiteSpace = 'nowrap';
|
|
326
|
+
wrap.textContent = originalContent + ' ' + originalContent;
|
|
327
|
+
node.style.overflow = 'hidden';
|
|
328
|
+
node.style.whiteSpace = 'nowrap';
|
|
329
|
+
node.appendChild(wrap);
|
|
330
|
+
const start = performance.now();
|
|
331
|
+
const cycle = effectiveDuration() || 6000;
|
|
332
|
+
function step(now) {
|
|
333
|
+
const elapsed = (now - start) % cycle;
|
|
334
|
+
const pct = elapsed / cycle;
|
|
335
|
+
wrap.style.transform = `translateX(${-50 * pct}%)`;
|
|
336
|
+
raf = requestAnimationFrame(step);
|
|
337
|
+
}
|
|
338
|
+
raf = requestAnimationFrame(step);
|
|
339
|
+
}
|
|
340
|
+
function runBlurIn() {
|
|
341
|
+
originalContent = params.content ?? '';
|
|
342
|
+
node.innerHTML = '';
|
|
343
|
+
const wrap = wrapChars(originalContent);
|
|
344
|
+
node.appendChild(wrap);
|
|
345
|
+
const chars = Array.from(wrap.querySelectorAll('.ta-char'));
|
|
346
|
+
const stagger = params.stagger ?? Math.max(20, Math.min(60, 600 / Math.max(1, chars.length)));
|
|
347
|
+
const perLetter = 600;
|
|
348
|
+
for (const c of chars) {
|
|
349
|
+
c.style.opacity = '0';
|
|
350
|
+
c.style.filter = 'blur(12px)';
|
|
351
|
+
}
|
|
352
|
+
const start = performance.now();
|
|
353
|
+
function step(now) {
|
|
354
|
+
const elapsed = now - start;
|
|
355
|
+
let allDone = true;
|
|
356
|
+
for (let i = 0; i < chars.length; i++) {
|
|
357
|
+
const t = Math.min(1, Math.max(0, (elapsed - i * stagger) / perLetter));
|
|
358
|
+
if (t < 1)
|
|
359
|
+
allDone = false;
|
|
360
|
+
const eased = 1 - Math.pow(1 - t, 2);
|
|
361
|
+
chars[i].style.opacity = String(eased);
|
|
362
|
+
chars[i].style.filter = `blur(${(1 - eased) * 12}px)`;
|
|
363
|
+
}
|
|
364
|
+
if (!allDone)
|
|
365
|
+
raf = requestAnimationFrame(step);
|
|
366
|
+
else {
|
|
367
|
+
for (const c of chars)
|
|
368
|
+
c.style.filter = 'none';
|
|
369
|
+
raf = 0;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
raf = requestAnimationFrame(step);
|
|
373
|
+
}
|
|
374
|
+
function runStretch() {
|
|
375
|
+
originalContent = params.content ?? '';
|
|
376
|
+
node.innerHTML = '';
|
|
377
|
+
const wrap = wrapChars(originalContent);
|
|
378
|
+
node.appendChild(wrap);
|
|
379
|
+
const chars = Array.from(wrap.querySelectorAll('.ta-char'));
|
|
380
|
+
const stagger = params.stagger ?? 50;
|
|
381
|
+
const perLetter = 450;
|
|
382
|
+
for (const c of chars) {
|
|
383
|
+
c.style.opacity = '0';
|
|
384
|
+
c.style.transform = 'scaleY(0.1)';
|
|
385
|
+
c.style.transformOrigin = '50% 100%';
|
|
386
|
+
}
|
|
387
|
+
const start = performance.now();
|
|
388
|
+
function step(now) {
|
|
389
|
+
const elapsed = now - start;
|
|
390
|
+
let allDone = true;
|
|
391
|
+
for (let i = 0; i < chars.length; i++) {
|
|
392
|
+
const t = Math.min(1, Math.max(0, (elapsed - i * stagger) / perLetter));
|
|
393
|
+
if (t < 1)
|
|
394
|
+
allDone = false;
|
|
395
|
+
const eased = 1 - Math.pow(1 - t, 4);
|
|
396
|
+
const overshoot = t > 0.8 ? Math.sin((t - 0.8) * Math.PI / 0.2) * 0.15 : 0;
|
|
397
|
+
const sy = 0.1 + (1 - 0.1) * eased + overshoot;
|
|
398
|
+
chars[i].style.opacity = String(Math.min(1, t * 1.5));
|
|
399
|
+
chars[i].style.transform = `scaleY(${sy})`;
|
|
400
|
+
}
|
|
401
|
+
if (!allDone)
|
|
402
|
+
raf = requestAnimationFrame(step);
|
|
403
|
+
else
|
|
404
|
+
raf = 0;
|
|
405
|
+
}
|
|
406
|
+
raf = requestAnimationFrame(step);
|
|
407
|
+
}
|
|
408
|
+
function runSlideWords() {
|
|
409
|
+
originalContent = params.content ?? '';
|
|
410
|
+
node.innerHTML = '';
|
|
411
|
+
const { wrap, words } = wrapWords(originalContent);
|
|
412
|
+
node.appendChild(wrap);
|
|
413
|
+
const stagger = params.stagger ?? 100;
|
|
414
|
+
const perWord = 500;
|
|
415
|
+
for (const w of words) {
|
|
416
|
+
w.style.opacity = '0';
|
|
417
|
+
w.style.transform = 'translateY(0.6em)';
|
|
418
|
+
}
|
|
419
|
+
const start = performance.now();
|
|
420
|
+
function step(now) {
|
|
421
|
+
const elapsed = now - start;
|
|
422
|
+
let allDone = true;
|
|
423
|
+
for (let i = 0; i < words.length; i++) {
|
|
424
|
+
const t = Math.min(1, Math.max(0, (elapsed - i * stagger) / perWord));
|
|
425
|
+
if (t < 1)
|
|
426
|
+
allDone = false;
|
|
427
|
+
const eased = 1 - Math.pow(1 - t, 3);
|
|
428
|
+
words[i].style.opacity = String(eased);
|
|
429
|
+
words[i].style.transform = `translateY(${(1 - eased) * 0.6}em)`;
|
|
430
|
+
}
|
|
431
|
+
if (!allDone)
|
|
432
|
+
raf = requestAnimationFrame(step);
|
|
433
|
+
else
|
|
434
|
+
raf = 0;
|
|
435
|
+
}
|
|
436
|
+
raf = requestAnimationFrame(step);
|
|
437
|
+
}
|
|
438
|
+
function runWave() {
|
|
439
|
+
originalContent = params.content ?? '';
|
|
440
|
+
node.innerHTML = '';
|
|
441
|
+
const wrap = wrapChars(originalContent);
|
|
442
|
+
node.appendChild(wrap);
|
|
443
|
+
const chars = Array.from(wrap.querySelectorAll('.ta-char'));
|
|
444
|
+
const cycle = effectiveDuration() || 1800;
|
|
445
|
+
const amp = 0.18;
|
|
446
|
+
const start = performance.now();
|
|
447
|
+
function step(now) {
|
|
448
|
+
const elapsed = (now - start) / cycle;
|
|
449
|
+
for (let i = 0; i < chars.length; i++) {
|
|
450
|
+
const phase = elapsed * Math.PI * 2 + (i / Math.max(1, chars.length)) * Math.PI * 1.4;
|
|
451
|
+
chars[i].style.transform = `translateY(${Math.sin(phase) * amp}em)`;
|
|
452
|
+
}
|
|
453
|
+
raf = requestAnimationFrame(step);
|
|
454
|
+
}
|
|
455
|
+
raf = requestAnimationFrame(step);
|
|
456
|
+
}
|
|
457
|
+
function runTypewriterErase() {
|
|
458
|
+
originalContent = params.content ?? '';
|
|
459
|
+
const chars = Array.from(originalContent);
|
|
460
|
+
const speed = 50;
|
|
461
|
+
const charMs = 1000 / speed;
|
|
462
|
+
const holdMs = 1200;
|
|
463
|
+
const eraseMs = chars.length * charMs * 0.6;
|
|
464
|
+
const cycle = chars.length * charMs + holdMs + eraseMs + 400;
|
|
465
|
+
const start = performance.now();
|
|
466
|
+
function step(now) {
|
|
467
|
+
const t = (now - start) % cycle;
|
|
468
|
+
let shown;
|
|
469
|
+
if (t < chars.length * charMs)
|
|
470
|
+
shown = Math.floor(t / charMs);
|
|
471
|
+
else if (t < chars.length * charMs + holdMs)
|
|
472
|
+
shown = chars.length;
|
|
473
|
+
else if (t < chars.length * charMs + holdMs + eraseMs) {
|
|
474
|
+
const eraseProgress = (t - chars.length * charMs - holdMs) / eraseMs;
|
|
475
|
+
shown = Math.max(0, chars.length - Math.floor(eraseProgress * chars.length));
|
|
476
|
+
}
|
|
477
|
+
else
|
|
478
|
+
shown = 0;
|
|
479
|
+
node.textContent = chars.slice(0, shown).join('') + (Math.floor(now / 500) % 2 === 0 ? '|' : '');
|
|
480
|
+
if (params.loop || t < cycle)
|
|
481
|
+
raf = requestAnimationFrame(step);
|
|
482
|
+
else
|
|
483
|
+
raf = 0;
|
|
484
|
+
}
|
|
485
|
+
raf = requestAnimationFrame(step);
|
|
486
|
+
}
|
|
146
487
|
function runHandwriting() {
|
|
147
488
|
// Real per-character handwriting: each glyph is its own <text> element
|
|
148
489
|
// with its own stroke-dasharray. We measure char positions from a single
|
|
@@ -313,6 +654,36 @@ export function textAnimate(node, params) {
|
|
|
313
654
|
case 'handwriting':
|
|
314
655
|
runHandwriting();
|
|
315
656
|
break;
|
|
657
|
+
case 'scramble-in':
|
|
658
|
+
runScrambleIn();
|
|
659
|
+
break;
|
|
660
|
+
case 'slot-machine':
|
|
661
|
+
runSlotMachine();
|
|
662
|
+
break;
|
|
663
|
+
case 'drop':
|
|
664
|
+
runDrop();
|
|
665
|
+
break;
|
|
666
|
+
case 'glitch':
|
|
667
|
+
runGlitch();
|
|
668
|
+
break;
|
|
669
|
+
case 'marquee':
|
|
670
|
+
runMarquee();
|
|
671
|
+
break;
|
|
672
|
+
case 'blur-in':
|
|
673
|
+
runBlurIn();
|
|
674
|
+
break;
|
|
675
|
+
case 'stretch':
|
|
676
|
+
runStretch();
|
|
677
|
+
break;
|
|
678
|
+
case 'slide-words':
|
|
679
|
+
runSlideWords();
|
|
680
|
+
break;
|
|
681
|
+
case 'wave':
|
|
682
|
+
runWave();
|
|
683
|
+
break;
|
|
684
|
+
case 'typewriter-erase':
|
|
685
|
+
runTypewriterErase();
|
|
686
|
+
break;
|
|
316
687
|
default: /* other modes handled elsewhere */ break;
|
|
317
688
|
}
|
|
318
689
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "animot-presenter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Embed animated presentations anywhere. Works with vanilla JS, React, Vue, Angular, Svelte, and any frontend framework. Morphing animations, code highlighting, charts, particles, and more.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"svelte": "./dist/index.js",
|