captions.js 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,10 +1,1719 @@
1
+ // src/fonts/googleFonts.config.ts
2
+ var googleFontsList = [
3
+ "Roboto",
4
+ "Open Sans",
5
+ "Lato",
6
+ "Montserrat",
7
+ "Nunito",
8
+ "Poppins",
9
+ "Ubuntu",
10
+ "PT Sans",
11
+ "Merriweather Sans",
12
+ "Lobster",
13
+ "Amatic SC",
14
+ "Pacifico",
15
+ "Raleway",
16
+ "Cinzel",
17
+ "Quicksand",
18
+ "Zilla Slab",
19
+ "Caveat",
20
+ "Crimson Pro",
21
+ "Bebas Neue",
22
+ "Comfortaa",
23
+ "Satisfy",
24
+ "Permanent Marker",
25
+ "Oswald",
26
+ "Onset",
27
+ "Bangers",
28
+ "Kanit",
29
+ "Work Sans",
30
+ "Fira Sans",
31
+ "Anton",
32
+ "Playfair Display",
33
+ "Rubik",
34
+ "Alumni Sans",
35
+ "Righteous",
36
+ "Comico",
37
+ "Excon",
38
+ "Kalam",
39
+ "Tanker",
40
+ "Arsenal",
41
+ "Balsamiq Sans",
42
+ "Bona Nova SC"
43
+ ];
44
+
45
+ // src/stylePresets/stylePresets.config.ts
46
+ var stylePresets = [
47
+ {
48
+ id: 1,
49
+ captionsSettings: {
50
+ style: {
51
+ font: {
52
+ italic: false,
53
+ fontSize: 20,
54
+ fontColor: "#ffffffFF",
55
+ underline: false,
56
+ fontFamily: "Montserrat",
57
+ fontWeight: "black",
58
+ fontCapitalize: false,
59
+ fontStrokeColor: "#000000FF",
60
+ fontStrokeWidth: 0
61
+ },
62
+ name: "Karaoke",
63
+ backgroundColor: "#E4E4E4FF",
64
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/karaoke_preview.png",
65
+ aplifiedWordColor: "#04f827FF"
66
+ },
67
+ position: "bottom",
68
+ animation: "bounce",
69
+ linesPerPage: 3
70
+ },
71
+ layoutSettings: {
72
+ aspectRatio: "9:16",
73
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
74
+ fitLayoutAspectRatio: "original"
75
+ }
76
+ },
77
+ {
78
+ id: 2,
79
+ captionsSettings: {
80
+ style: {
81
+ font: {
82
+ italic: false,
83
+ fontSize: 25,
84
+ fontColor: "#ffffffFF",
85
+ underline: false,
86
+ fontFamily: "Permanent Marker",
87
+ fontWeight: "black",
88
+ fontCapitalize: true,
89
+ fontStrokeColor: "#000000FF",
90
+ fontStrokeWidth: 0
91
+ },
92
+ name: "Beasty",
93
+ backgroundColor: "#E4E4E4FF",
94
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/beasty_preview.png",
95
+ aplifiedWordColor: "#ff0000ff"
96
+ },
97
+ position: "bottom",
98
+ animation: "pop",
99
+ linesPerPage: 1
100
+ },
101
+ layoutSettings: {
102
+ aspectRatio: "9:16",
103
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
104
+ fitLayoutAspectRatio: "original"
105
+ }
106
+ },
107
+ {
108
+ id: 3,
109
+ captionsSettings: {
110
+ style: {
111
+ font: {
112
+ italic: false,
113
+ fontSize: 23,
114
+ fontColor: "#C6C6C6FF",
115
+ underline: false,
116
+ fontFamily: "Poppins",
117
+ fontWeight: "bold",
118
+ fontCapitalize: false,
119
+ fontStrokeColor: "#000000FF",
120
+ fontStrokeWidth: 0
121
+ },
122
+ name: "Safari",
123
+ backgroundColor: "#E4E4E4FF",
124
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/safari_preview.png",
125
+ aplifiedWordColor: "#000000FF"
126
+ },
127
+ position: "bottom",
128
+ animation: "box",
129
+ linesPerPage: 1
130
+ },
131
+ layoutSettings: {
132
+ aspectRatio: "9:16",
133
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
134
+ fitLayoutAspectRatio: "original"
135
+ }
136
+ },
137
+ {
138
+ id: 4,
139
+ captionsSettings: {
140
+ style: {
141
+ font: {
142
+ italic: false,
143
+ fontSize: 24,
144
+ fontColor: "#817B81FF",
145
+ underline: false,
146
+ fontFamily: "PT Sans",
147
+ fontWeight: "black",
148
+ fontCapitalize: false,
149
+ fontStrokeColor: "#000000FF",
150
+ fontStrokeWidth: 0
151
+ },
152
+ name: "Acid",
153
+ backgroundColor: "#00000000",
154
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/aciv_preview.png",
155
+ aplifiedWordColor: "#6BF5C7FF"
156
+ },
157
+ position: "bottom",
158
+ animation: "none",
159
+ linesPerPage: 1,
160
+ positionTopOffset: 42
161
+ },
162
+ layoutSettings: {
163
+ aspectRatio: "9:16",
164
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
165
+ fitLayoutAspectRatio: "original"
166
+ }
167
+ },
168
+ {
169
+ id: 5,
170
+ captionsSettings: {
171
+ style: {
172
+ font: {
173
+ italic: false,
174
+ fontSize: 26,
175
+ fontColor: "#F43FE0FF",
176
+ underline: false,
177
+ fontFamily: "Raleway",
178
+ fontWeight: "bold",
179
+ fontCapitalize: false,
180
+ fontStrokeColor: "#000000FF",
181
+ fontStrokeWidth: 8
182
+ },
183
+ name: "Popline",
184
+ backgroundColor: "#E4E4E4FF",
185
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/popline_preview.png",
186
+ aplifiedWordColor: "#F43FE0FF"
187
+ },
188
+ position: "bottom",
189
+ animation: "none",
190
+ linesPerPage: 1
191
+ },
192
+ layoutSettings: {
193
+ aspectRatio: "9:16",
194
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
195
+ fitLayoutAspectRatio: "original"
196
+ }
197
+ },
198
+ {
199
+ id: 6,
200
+ captionsSettings: {
201
+ style: {
202
+ font: {
203
+ italic: false,
204
+ fontSize: 20,
205
+ fontColor: "#FFFFFFFF",
206
+ underline: false,
207
+ fontFamily: "Montserrat",
208
+ fontWeight: "black",
209
+ fontCapitalize: true,
210
+ fontStrokeColor: "#000000FF",
211
+ fontStrokeWidth: 0
212
+ },
213
+ name: "Desert",
214
+ backgroundColor: "#E4E4E4FF",
215
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/desert_preview.png",
216
+ aplifiedWordColor: "#8F2EEDFF"
217
+ },
218
+ position: "bottom",
219
+ animation: "bounce",
220
+ linesPerPage: 2
221
+ },
222
+ layoutSettings: {
223
+ aspectRatio: "9:16",
224
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
225
+ fitLayoutAspectRatio: "original"
226
+ }
227
+ },
228
+ {
229
+ id: 7,
230
+ captionsSettings: {
231
+ style: {
232
+ font: {
233
+ italic: false,
234
+ fontSize: 26,
235
+ fontColor: "#FFFFFFFF",
236
+ underline: false,
237
+ fontFamily: "Lato",
238
+ fontWeight: "black",
239
+ fontCapitalize: true,
240
+ fontStrokeColor: "#000000FF",
241
+ fontStrokeWidth: 0
242
+ },
243
+ name: "Hook",
244
+ backgroundColor: "#E4E4E4FF",
245
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/hook_preview.png",
246
+ aplifiedWordColor: "#8F2EEDFF"
247
+ },
248
+ position: "bottom",
249
+ animation: "underline",
250
+ linesPerPage: 2
251
+ },
252
+ layoutSettings: {
253
+ aspectRatio: "9:16",
254
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
255
+ fitLayoutAspectRatio: "original"
256
+ }
257
+ },
258
+ {
259
+ id: 8,
260
+ captionsSettings: {
261
+ style: {
262
+ font: {
263
+ italic: false,
264
+ fontSize: 20,
265
+ fontColor: "#FFFFFFFF",
266
+ underline: false,
267
+ fontFamily: "Montserrat",
268
+ fontWeight: "black",
269
+ fontCapitalize: true,
270
+ fontStrokeColor: "#000000FF",
271
+ fontStrokeWidth: 0
272
+ },
273
+ name: "Sky",
274
+ backgroundColor: "#E4E4E4FF",
275
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/sky_preview.png",
276
+ aplifiedWordColor: "#FFFFFFFF"
277
+ },
278
+ position: "bottom",
279
+ animation: "slide-left",
280
+ linesPerPage: 2
281
+ },
282
+ layoutSettings: {
283
+ aspectRatio: "9:16",
284
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
285
+ fitLayoutAspectRatio: "original"
286
+ }
287
+ },
288
+ {
289
+ id: 9,
290
+ captionsSettings: {
291
+ style: {
292
+ font: {
293
+ italic: false,
294
+ fontSize: 20,
295
+ fontColor: "#FFFFFFFF",
296
+ underline: false,
297
+ fontFamily: "Montserrat",
298
+ fontWeight: "black",
299
+ fontCapitalize: true,
300
+ fontStrokeColor: "#000000FF",
301
+ fontStrokeWidth: 0
302
+ },
303
+ name: "Flamingo",
304
+ backgroundColor: "#E4E4E4FF",
305
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/flamingo_preview.png",
306
+ aplifiedWordColor: "#ff0000ff"
307
+ },
308
+ position: "bottom",
309
+ animation: "scale",
310
+ linesPerPage: 2
311
+ },
312
+ layoutSettings: {
313
+ aspectRatio: "9:16",
314
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
315
+ fitLayoutAspectRatio: "original"
316
+ }
317
+ },
318
+ {
319
+ id: 10,
320
+ captionsSettings: {
321
+ style: {
322
+ font: {
323
+ italic: false,
324
+ fontSize: 26,
325
+ fontColor: "#8a8a8aff",
326
+ underline: false,
327
+ fontFamily: "Raleway",
328
+ fontWeight: "bold",
329
+ fontCapitalize: false,
330
+ fontStrokeColor: "#000000FF",
331
+ fontStrokeWidth: 0
332
+ },
333
+ name: "Deep Diver B&W",
334
+ backgroundColor: "#000000ff",
335
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/captions-deep-diver-b&w.png",
336
+ aplifiedWordColor: "#ffffffff"
337
+ },
338
+ position: "bottom",
339
+ animation: "box",
340
+ linesPerPage: 1
341
+ },
342
+ layoutSettings: {
343
+ aspectRatio: "9:16",
344
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
345
+ fitLayoutAspectRatio: "original"
346
+ }
347
+ },
348
+ {
349
+ id: 11,
350
+ captionsSettings: {
351
+ style: {
352
+ font: {
353
+ italic: false,
354
+ fontSize: 20,
355
+ fontColor: "#b0b0b0ff",
356
+ underline: false,
357
+ fontFamily: "Montserrat",
358
+ fontWeight: "bold",
359
+ fontCapitalize: true,
360
+ fontStrokeColor: "#000000FF",
361
+ fontStrokeWidth: 0
362
+ },
363
+ name: "New",
364
+ backgroundColor: "#E4E4E4FF",
365
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/flamingo_preview.png",
366
+ aplifiedWordColor: "#dbff00ff"
367
+ },
368
+ position: "middle",
369
+ animation: "pop",
370
+ linesPerPage: 3
371
+ },
372
+ layoutSettings: {
373
+ aspectRatio: "9:16",
374
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
375
+ fitLayoutAspectRatio: "original"
376
+ }
377
+ },
378
+ {
379
+ id: 12,
380
+ captionsSettings: {
381
+ style: {
382
+ font: {
383
+ italic: false,
384
+ fontSize: 30,
385
+ fontColor: "#ffffffFF",
386
+ underline: false,
387
+ fontFamily: "Bangers",
388
+ fontWeight: "bold",
389
+ fontCapitalize: true,
390
+ fontStrokeColor: "#000000ff",
391
+ fontStrokeWidth: 60
392
+ },
393
+ name: "Banger",
394
+ backgroundColor: "#E4E4E4FF",
395
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/beasty_preview.png",
396
+ aplifiedWordColor: "#fdfa14ff"
397
+ },
398
+ position: "bottom",
399
+ animation: "pop",
400
+ linesPerPage: 1
401
+ },
402
+ layoutSettings: {
403
+ aspectRatio: "9:16",
404
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
405
+ fitLayoutAspectRatio: "original"
406
+ }
407
+ },
408
+ {
409
+ id: 13,
410
+ captionsSettings: {
411
+ style: {
412
+ font: {
413
+ italic: false,
414
+ fontSize: 20,
415
+ fontColor: "#FFFFFFFF",
416
+ underline: false,
417
+ fontFamily: "Montserrat",
418
+ fontWeight: "black",
419
+ fontCapitalize: true,
420
+ fontStrokeColor: "#000000FF",
421
+ fontStrokeWidth: 30
422
+ },
423
+ name: "Catchy",
424
+ backgroundColor: "#E4E4E4FF",
425
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/desert_preview.png",
426
+ aplifiedWordColor: "#ff5700ff"
427
+ },
428
+ position: "bottom",
429
+ animation: "bounce",
430
+ linesPerPage: 2
431
+ },
432
+ layoutSettings: {
433
+ aspectRatio: "9:16",
434
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
435
+ fitLayoutAspectRatio: "original"
436
+ }
437
+ },
438
+ {
439
+ id: 14,
440
+ captionsSettings: {
441
+ style: {
442
+ font: {
443
+ italic: false,
444
+ fontSize: 25,
445
+ fontColor: "#ffffffFF",
446
+ underline: false,
447
+ fontFamily: "Rubik",
448
+ fontWeight: "black",
449
+ fontCapitalize: true,
450
+ fontStrokeColor: "#000000FF",
451
+ fontStrokeWidth: 40
452
+ },
453
+ name: "Karaoke 2",
454
+ backgroundColor: "#E4E4E4FF",
455
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/karaoke_preview.png",
456
+ aplifiedWordColor: "#2bf82aff"
457
+ },
458
+ position: "bottom",
459
+ animation: "bounce",
460
+ linesPerPage: 2
461
+ },
462
+ layoutSettings: {
463
+ aspectRatio: "9:16",
464
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
465
+ fitLayoutAspectRatio: "original"
466
+ }
467
+ },
468
+ {
469
+ id: 15,
470
+ captionsSettings: {
471
+ style: {
472
+ font: {
473
+ italic: false,
474
+ fontSize: 25,
475
+ fontColor: "#ffffffFF",
476
+ underline: false,
477
+ fontFamily: "Rubik",
478
+ fontWeight: "black",
479
+ fontCapitalize: true,
480
+ fontStrokeColor: "#000000FF",
481
+ fontStrokeWidth: 60
482
+ },
483
+ name: "Karaoke 3",
484
+ backgroundColor: "#E4E4E4FF",
485
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/karaoke_preview.png",
486
+ aplifiedWordColor: "#2bf82aff"
487
+ },
488
+ position: "bottom",
489
+ animation: "bounce",
490
+ linesPerPage: 2
491
+ },
492
+ layoutSettings: {
493
+ aspectRatio: "9:16",
494
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
495
+ fitLayoutAspectRatio: "original"
496
+ }
497
+ },
498
+ {
499
+ id: 16,
500
+ captionsSettings: {
501
+ style: {
502
+ font: {
503
+ italic: false,
504
+ shadow: {
505
+ fontShadowBlur: 0,
506
+ fontShadowColor: "#000000ff",
507
+ fontShadowOffsetX: 2,
508
+ fontShadowOffsetY: 2
509
+ },
510
+ fontSize: 25,
511
+ fontColor: "#ffffffFF",
512
+ underline: false,
513
+ fontFamily: "Kanit",
514
+ fontWeight: "black",
515
+ fontCapitalize: true,
516
+ fontStrokeColor: "#000000FF",
517
+ fontStrokeWidth: 40
518
+ },
519
+ name: "From",
520
+ backgroundColor: "#E4E4E4FF",
521
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/karaoke_preview.png",
522
+ aplifiedWordColor: "#ffdd03ff"
523
+ },
524
+ position: "bottom",
525
+ animation: "pop",
526
+ linesPerPage: 1
527
+ },
528
+ layoutSettings: {
529
+ aspectRatio: "9:16",
530
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
531
+ fitLayoutAspectRatio: "original"
532
+ }
533
+ },
534
+ {
535
+ id: 17,
536
+ captionsSettings: {
537
+ style: {
538
+ font: {
539
+ italic: false,
540
+ fontSize: 15,
541
+ fontColor: "#ffffffff",
542
+ underline: false,
543
+ fontFamily: "Roboto",
544
+ fontWeight: "bold",
545
+ fontCapitalize: false,
546
+ fontStrokeColor: "#000000FF",
547
+ fontStrokeWidth: 20
548
+ },
549
+ name: "Classic",
550
+ backgroundColor: "#000000ff",
551
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/safari_preview.png",
552
+ aplifiedWordColor: "#ffffffff"
553
+ },
554
+ position: "bottom",
555
+ animation: "none",
556
+ linesPerPage: 2
557
+ },
558
+ layoutSettings: {
559
+ aspectRatio: "9:16",
560
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
561
+ fitLayoutAspectRatio: "original"
562
+ }
563
+ },
564
+ {
565
+ id: 18,
566
+ captionsSettings: {
567
+ style: {
568
+ font: {
569
+ italic: false,
570
+ fontSize: 30,
571
+ fontColor: "#ffffffff",
572
+ underline: false,
573
+ fontFamily: "Roboto",
574
+ fontWeight: "medium",
575
+ fontCapitalize: false,
576
+ fontStrokeColor: "#000000FF",
577
+ fontStrokeWidth: 40
578
+ },
579
+ name: "Classic Big",
580
+ backgroundColor: "#000000ff",
581
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/safari_preview.png",
582
+ aplifiedWordColor: "#ffffffff"
583
+ },
584
+ position: "bottom",
585
+ animation: "none",
586
+ linesPerPage: 2
587
+ },
588
+ layoutSettings: {
589
+ aspectRatio: "9:16",
590
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
591
+ fitLayoutAspectRatio: "original"
592
+ }
593
+ },
594
+ {
595
+ id: 19,
596
+ captionsSettings: {
597
+ style: {
598
+ font: {
599
+ italic: false,
600
+ fontSize: 25,
601
+ fontColor: "#FFFFFFFF",
602
+ underline: false,
603
+ fontFamily: "Montserrat",
604
+ fontWeight: "black",
605
+ fontCapitalize: true,
606
+ fontStrokeColor: "#000000FF",
607
+ fontStrokeWidth: 80
608
+ },
609
+ name: "Crazy",
610
+ backgroundColor: "#E4E4E4FF",
611
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/desert_preview.png",
612
+ aplifiedWordColor: "#ebf901ff"
613
+ },
614
+ position: "bottom",
615
+ animation: "none",
616
+ linesPerPage: 2,
617
+ positionTopOffset: 0
618
+ },
619
+ layoutSettings: {
620
+ aspectRatio: "9:16",
621
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
622
+ fitLayoutAspectRatio: "original"
623
+ }
624
+ },
625
+ {
626
+ id: 20,
627
+ captionsSettings: {
628
+ style: {
629
+ font: {
630
+ italic: false,
631
+ fontSize: 30,
632
+ fontColor: "#ffffffff",
633
+ underline: false,
634
+ fontFamily: "PT Sans",
635
+ fontWeight: "black",
636
+ fontCapitalize: false,
637
+ fontStrokeColor: "#000000FF",
638
+ fontStrokeWidth: 40
639
+ },
640
+ name: "Acid 2",
641
+ backgroundColor: "#00000000",
642
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/aciv_preview.png",
643
+ aplifiedWordColor: "#6BF5C7FF"
644
+ },
645
+ position: "bottom",
646
+ animation: "none",
647
+ linesPerPage: 1,
648
+ positionTopOffset: 42
649
+ },
650
+ layoutSettings: {
651
+ aspectRatio: "9:16",
652
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
653
+ fitLayoutAspectRatio: "original"
654
+ }
655
+ },
656
+ {
657
+ id: 21,
658
+ captionsSettings: {
659
+ style: {
660
+ font: {
661
+ italic: false,
662
+ fontSize: 20,
663
+ fontColor: "#ffffffff",
664
+ underline: false,
665
+ fontFamily: "Oswald",
666
+ fontWeight: "medium",
667
+ fontCapitalize: false,
668
+ fontStrokeColor: "#000000FF",
669
+ fontStrokeWidth: 40
670
+ },
671
+ name: "Marvel",
672
+ backgroundColor: "#00000000",
673
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/aciv_preview.png",
674
+ aplifiedWordColor: "#a76dffff"
675
+ },
676
+ position: "bottom",
677
+ animation: "scale",
678
+ linesPerPage: 2,
679
+ positionTopOffset: 0
680
+ },
681
+ layoutSettings: {
682
+ aspectRatio: "9:16",
683
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
684
+ fitLayoutAspectRatio: "original"
685
+ }
686
+ },
687
+ {
688
+ id: 22,
689
+ captionsSettings: {
690
+ style: {
691
+ font: {
692
+ italic: false,
693
+ shadow: {
694
+ fontShadowBlur: 1,
695
+ fontShadowColor: "0",
696
+ fontShadowOffsetX: 2,
697
+ fontShadowOffsetY: 2
698
+ },
699
+ fontSize: 25,
700
+ fontColor: "#ffffffff",
701
+ underline: false,
702
+ fontFamily: "Pacifico",
703
+ fontWeight: "medium",
704
+ fontCapitalize: false,
705
+ fontStrokeColor: "#000000FF",
706
+ fontStrokeWidth: 0
707
+ },
708
+ name: "Lovly",
709
+ backgroundColor: "#00000000",
710
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/aciv_preview.png",
711
+ aplifiedWordColor: "#f866cfff"
712
+ },
713
+ position: "bottom",
714
+ animation: "scale",
715
+ linesPerPage: 2,
716
+ positionTopOffset: 0
717
+ },
718
+ layoutSettings: {
719
+ aspectRatio: "9:16",
720
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
721
+ fitLayoutAspectRatio: "original"
722
+ }
723
+ },
724
+ {
725
+ id: 23,
726
+ captionsSettings: {
727
+ style: {
728
+ font: {
729
+ italic: false,
730
+ shadow: {
731
+ fontShadowBlur: 0,
732
+ fontShadowColor: "#023210ff",
733
+ fontShadowOffsetX: 2,
734
+ fontShadowOffsetY: 2
735
+ },
736
+ fontSize: 25,
737
+ fontColor: "#ffffffff",
738
+ underline: false,
739
+ fontFamily: "Playfair Display",
740
+ fontWeight: "regular",
741
+ fontCapitalize: false,
742
+ fontStrokeColor: "#000000FF",
743
+ fontStrokeWidth: 0
744
+ },
745
+ name: "Old Money",
746
+ backgroundColor: "#00000000",
747
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/aciv_preview.png",
748
+ aplifiedWordColor: "#ffffffff"
749
+ },
750
+ position: "bottom",
751
+ animation: "slide-up",
752
+ linesPerPage: 3,
753
+ positionTopOffset: 0
754
+ },
755
+ layoutSettings: {
756
+ aspectRatio: "9:16",
757
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
758
+ fitLayoutAspectRatio: "original"
759
+ }
760
+ },
761
+ {
762
+ id: 24,
763
+ captionsSettings: {
764
+ style: {
765
+ font: {
766
+ italic: false,
767
+ fontSize: 14,
768
+ fontColor: "#e4e900ff",
769
+ underline: false,
770
+ fontFamily: "Lato",
771
+ fontWeight: "bold",
772
+ fontCapitalize: false,
773
+ fontStrokeColor: "#000000FF",
774
+ fontStrokeWidth: 20
775
+ },
776
+ name: "Cinema",
777
+ backgroundColor: "#000000ff",
778
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/safari_preview.png",
779
+ aplifiedWordColor: "#e4e900ff"
780
+ },
781
+ position: "bottom",
782
+ animation: "none",
783
+ linesPerPage: 2
784
+ },
785
+ layoutSettings: {
786
+ aspectRatio: "9:16",
787
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
788
+ fitLayoutAspectRatio: "original"
789
+ }
790
+ },
791
+ {
792
+ id: 25,
793
+ captionsSettings: {
794
+ style: {
795
+ font: {
796
+ italic: false,
797
+ shadow: {
798
+ fontShadowBlur: 10,
799
+ fontShadowColor: "#000000ff",
800
+ fontShadowOffsetX: 2,
801
+ fontShadowOffsetY: 2
802
+ },
803
+ fontSize: 20,
804
+ fontColor: "#FFFFFFFF",
805
+ underline: false,
806
+ fontFamily: "Raleway",
807
+ fontWeight: "black",
808
+ fontCapitalize: false,
809
+ fontStrokeColor: "#000000FF",
810
+ fontStrokeWidth: 0
811
+ },
812
+ name: "Marker",
813
+ backgroundColor: "#E4E4E4FF",
814
+ verticalCoverImg: "https://storage.googleapis.com/loomz-front-static/video-editor/img/flamingo_preview.png",
815
+ aplifiedWordColor: "#6f0eecff"
816
+ },
817
+ position: "bottom",
818
+ animation: "underline",
819
+ linesPerPage: 2
820
+ },
821
+ layoutSettings: {
822
+ aspectRatio: "9:16",
823
+ aIAutoLayout: ["fill", "fit", "split", "three", "four", "screenShare"],
824
+ fitLayoutAspectRatio: "original"
825
+ }
826
+ }
827
+ ];
828
+
829
+ // src/fonts/googleFonts.helpers.ts
830
+ import Konva from "konva";
831
+ async function loadGoogleFont2(fontFamily) {
832
+ const fontNameForUrl = fontFamily.replace(/\s+/g, "+");
833
+ const fontUrl = `https://fonts.googleapis.com/css2?family=${fontNameForUrl}:wght@400;700&display=swap`;
834
+ if (!document.querySelector(`link[href="${fontUrl}"]`)) {
835
+ const link = document.createElement("link");
836
+ link.rel = "stylesheet";
837
+ link.href = fontUrl;
838
+ document.head.appendChild(link);
839
+ }
840
+ try {
841
+ await document.fonts.load(`16px "${fontFamily}"`);
842
+ await document.fonts.ready;
843
+ } catch (err) {
844
+ console.warn(`[loadGoogleFont] failed to load font "${fontFamily}":`, err);
845
+ }
846
+ Konva.stages?.forEach((stage) => stage.batchDraw());
847
+ console.log(
848
+ `[loadGoogleFont] Font "${fontFamily}" loaded and ready for Konva.`
849
+ );
850
+ }
851
+
852
+ // src/render/renderString.ts
853
+ import Konva2 from "konva";
854
+ async function renderString(canvas, text, options) {
855
+ const { preset } = options;
856
+ const width = parseInt(canvas.style.width);
857
+ const height = parseInt(canvas.style.height);
858
+ const container = document.createElement("div");
859
+ var stage = new Konva2.Stage({
860
+ container,
861
+ width,
862
+ height
863
+ });
864
+ console.log("width, height", width, height);
865
+ var layer = new Konva2.Layer();
866
+ stage.add(layer);
867
+ await loadGoogleFont2(
868
+ preset.captionsSettings.style.font.fontFamily
869
+ );
870
+ await new Promise((resolve) => requestAnimationFrame(resolve));
871
+ const background = new Konva2.Rect({
872
+ x: 0,
873
+ y: 0,
874
+ width,
875
+ height,
876
+ fill: "black"
877
+ });
878
+ layer.add(background);
879
+ const textOptions = {
880
+ x: width / 2,
881
+ y: height / 2,
882
+ text,
883
+ fontSize: preset.captionsSettings.style.font.fontSize,
884
+ fontFamily: preset.captionsSettings.style.font.fontFamily,
885
+ fill: preset.captionsSettings.style.font.fontColor,
886
+ align: "center",
887
+ offsetX: 0,
888
+ offsetY: 0
889
+ };
890
+ console.log("textOptions", textOptions);
891
+ const konvaText = new Konva2.Text(textOptions);
892
+ konvaText.offsetX(konvaText.width() / 2);
893
+ konvaText.offsetY(konvaText.height() / 2);
894
+ layer.add(konvaText);
895
+ layer.draw();
896
+ const konvaCanvas = layer.getCanvas()._canvas;
897
+ const konvaContext = konvaCanvas.getContext("2d");
898
+ if (konvaContext) {
899
+ const targetContext = canvas.getContext("2d");
900
+ if (targetContext) {
901
+ targetContext.setTransform(
902
+ Konva2.pixelRatio,
903
+ 0,
904
+ 0,
905
+ Konva2.pixelRatio,
906
+ 0,
907
+ 0
908
+ );
909
+ targetContext.drawImage(konvaCanvas, 0, 0, width, height);
910
+ }
911
+ }
912
+ return true;
913
+ }
914
+
915
+ // src/captions/Captions.ts
916
+ import Konva5 from "konva";
917
+
918
+ // src/canvas-captions/index.ts
919
+ import Konva4 from "konva";
920
+
921
+ // src/canvas-captions/animate.ts
922
+ import Konva3 from "konva";
923
+
924
+ // src/canvas-captions/easing.ts
925
+ var mapEaseToFn = {
926
+ ["linear" /* linear */]: linear,
927
+ ["easeInSine" /* inSine */]: easeInSine,
928
+ ["easeOutSine" /* outSine */]: easeOutSine,
929
+ ["easeInOutSine" /* inOutSine */]: easeInOutSine,
930
+ ["easeInQuad" /* inQuad */]: easeInQuad,
931
+ ["easeOutQuad" /* outQuad */]: easeOutQuad,
932
+ ["easeInOutQuad" /* inOutQuad */]: easeInOutQuad,
933
+ ["easeInCubic" /* inCubic */]: easeInCubic,
934
+ ["easeOutCubic" /* outCubic */]: easeOutCubic,
935
+ ["easeInOutCubic" /* inOutCubic */]: easeInOutCubic,
936
+ ["easeInQuart" /* inQuart */]: easeInQuart,
937
+ ["easeOutQuart" /* outQuart */]: easeOutQuart,
938
+ ["easeInOutQuart" /* inOutQuart */]: easeInOutQuart,
939
+ ["easeInQuint" /* inQuint */]: easeInQuint,
940
+ ["easeOutQuint" /* outQuint */]: easeOutQuint,
941
+ ["easeInOutQuint" /* inOutQuint */]: easeInOutQuint,
942
+ ["easeInExpo" /* inExpo */]: easeInExpo,
943
+ ["easeOutExpo" /* outExpo */]: easeOutExpo,
944
+ ["easeInOutExpo" /* inOutExpo */]: easeInOutExpo,
945
+ ["easeInCirc" /* inCirc */]: easeInCirc,
946
+ ["easeOutCirc" /* outCirc */]: easeOutCirc,
947
+ ["easeInOutCirc" /* inOutCirc */]: easeInOutCirc,
948
+ ["easeInBack" /* inBack */]: easeInBack,
949
+ ["easeOutBack" /* outBack */]: easeOutBack,
950
+ ["easeInOutBack" /* inOutBack */]: easeInOutBack,
951
+ ["easeInElastic" /* inElastic */]: easeInElastic,
952
+ ["easeOutElastic" /* outElastic */]: easeOutElastic,
953
+ ["easeInOutElastic" /* inOutElastic */]: easeInOutElastic,
954
+ ["easeInBounce" /* inBounce */]: easeInBounce,
955
+ ["easeOutBounce" /* outBounce */]: easeOutBounce,
956
+ ["easeInOutBounce" /* inOutBounce */]: easeInOutBounce
957
+ };
958
+ function linear(x) {
959
+ return x;
960
+ }
961
+ function easeInSine(x) {
962
+ return 1 - Math.cos(x * Math.PI / 2);
963
+ }
964
+ function easeOutSine(x) {
965
+ return Math.sin(x * Math.PI / 2);
966
+ }
967
+ function easeInOutSine(x) {
968
+ return -(Math.cos(Math.PI * x) - 1) / 2;
969
+ }
970
+ function easeInQuad(x) {
971
+ return x * x;
972
+ }
973
+ function easeOutQuad(x) {
974
+ return 1 - (1 - x) * (1 - x);
975
+ }
976
+ function easeInOutQuad(x) {
977
+ return x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2;
978
+ }
979
+ function easeInCubic(x) {
980
+ return x * x * x;
981
+ }
982
+ function easeOutCubic(x) {
983
+ return 1 - Math.pow(1 - x, 3);
984
+ }
985
+ function easeInOutCubic(x) {
986
+ return x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2;
987
+ }
988
+ function easeInQuart(x) {
989
+ return x * x * x * x;
990
+ }
991
+ function easeOutQuart(x) {
992
+ return 1 - Math.pow(1 - x, 4);
993
+ }
994
+ function easeInOutQuart(x) {
995
+ return x < 0.5 ? 8 * x * x * x * x : 1 - Math.pow(-2 * x + 2, 4) / 2;
996
+ }
997
+ function easeInQuint(x) {
998
+ return x * x * x * x * x;
999
+ }
1000
+ function easeOutQuint(x) {
1001
+ return 1 - Math.pow(1 - x, 5);
1002
+ }
1003
+ function easeInOutQuint(x) {
1004
+ return x < 0.5 ? 16 * x * x * x * x * x : 1 - Math.pow(-2 * x + 2, 5) / 2;
1005
+ }
1006
+ function easeInExpo(x) {
1007
+ return x === 0 ? 0 : Math.pow(2, 10 * x - 10);
1008
+ }
1009
+ function easeOutExpo(x) {
1010
+ return x === 1 ? 1 : 1 - Math.pow(2, -10 * x);
1011
+ }
1012
+ function easeInOutExpo(x) {
1013
+ return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ? Math.pow(2, 20 * x - 10) / 2 : (2 - Math.pow(2, -20 * x + 10)) / 2;
1014
+ }
1015
+ function easeInCirc(x) {
1016
+ return 1 - Math.sqrt(1 - Math.pow(x, 2));
1017
+ }
1018
+ function easeOutCirc(x) {
1019
+ return Math.sqrt(1 - Math.pow(x - 1, 2));
1020
+ }
1021
+ function easeInOutCirc(x) {
1022
+ return x < 0.5 ? (1 - Math.sqrt(1 - Math.pow(2 * x, 2))) / 2 : (Math.sqrt(1 - Math.pow(-2 * x + 2, 2)) + 1) / 2;
1023
+ }
1024
+ function easeInBack(x) {
1025
+ const c1 = 1.70158;
1026
+ const c3 = c1 + 1;
1027
+ return c3 * x * x * x - c1 * x * x;
1028
+ }
1029
+ function easeOutBack(x) {
1030
+ const c1 = 1.70158;
1031
+ const c3 = c1 + 1;
1032
+ return 1 + c3 * Math.pow(x - 1, 3) + c1 * Math.pow(x - 1, 2);
1033
+ }
1034
+ function easeInOutBack(x) {
1035
+ const c1 = 1.70158;
1036
+ const c2 = c1 * 1.525;
1037
+ return x < 0.5 ? Math.pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2) / 2 : (Math.pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2;
1038
+ }
1039
+ function easeInElastic(x) {
1040
+ const c4 = 2 * Math.PI / 3;
1041
+ return x === 0 ? 0 : x === 1 ? 1 : -Math.pow(2, 10 * x - 10) * Math.sin((x * 10 - 10.75) * c4);
1042
+ }
1043
+ function easeOutElastic(x) {
1044
+ const c4 = 2 * Math.PI / 3;
1045
+ return x === 0 ? 0 : x === 1 ? 1 : Math.pow(2, -10 * x) * Math.sin((x * 10 - 0.75) * c4) + 1;
1046
+ }
1047
+ function easeInOutElastic(x) {
1048
+ const c5 = 2 * Math.PI / 4.5;
1049
+ return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ? -(Math.pow(2, 20 * x - 10) * Math.sin((20 * x - 11.125) * c5)) / 2 : Math.pow(2, -20 * x + 10) * Math.sin((20 * x - 11.125) * c5) / 2 + 1;
1050
+ }
1051
+ function easeInBounce(x) {
1052
+ return 1 - easeOutBounce(1 - x);
1053
+ }
1054
+ function easeOutBounce(x) {
1055
+ const n1 = 7.5625;
1056
+ const d1 = 2.75;
1057
+ if (x < 1 / d1) {
1058
+ return n1 * x * x;
1059
+ } else if (x < 2 / d1) {
1060
+ return n1 * (x -= 1.5 / d1) * x + 0.75;
1061
+ } else if (x < 2.5 / d1) {
1062
+ return n1 * (x -= 2.25 / d1) * x + 0.9375;
1063
+ } else {
1064
+ return n1 * (x -= 2.625 / d1) * x + 0.984375;
1065
+ }
1066
+ }
1067
+ function easeInOutBounce(x) {
1068
+ return x < 0.5 ? (1 - easeOutBounce(1 - 2 * x)) / 2 : (1 + easeOutBounce(2 * x - 1)) / 2;
1069
+ }
1070
+
1071
+ // src/canvas-captions/animate.ts
1072
+ var animate = (captionsSettings, progress, chunk, current) => {
1073
+ const easeFn = mapEaseToFn["easeInQuint" /* inQuint */];
1074
+ const slideOffset = 7;
1075
+ switch (captionsSettings.animation) {
1076
+ case "bounce":
1077
+ if (current) {
1078
+ current.text.offsetX(current.text.width() / 2);
1079
+ current.text.offsetY(current.text.height() / 2);
1080
+ current.text.x(current.text.x() + current.text.width() / 2);
1081
+ current.text.y(current.text.y() + current.text.height() / 2);
1082
+ current.text.scale({
1083
+ x: 1 + 0.3 * easeFn(1),
1084
+ y: 1 + 0.3 * easeFn(1)
1085
+ });
1086
+ const offsetModule = captionsSettings.style.font.fontSize * 0.3;
1087
+ const curreentChildIndex = current.text.parent?.children.indexOf(current.text) || 0;
1088
+ current.text.parent?.children.forEach((child, index) => {
1089
+ if (index !== curreentChildIndex) {
1090
+ const offset = index < curreentChildIndex ? -offsetModule : offsetModule;
1091
+ child.x(child.x() + offset * easeFn(1));
1092
+ }
1093
+ });
1094
+ }
1095
+ break;
1096
+ case "underline":
1097
+ if (current) {
1098
+ const underline = new Konva3.Line({
1099
+ points: [
1100
+ current.text.x(),
1101
+ current.text.height(),
1102
+ current.text.x() + current.text.width() * easeFn(1),
1103
+ current.text.height()
1104
+ ],
1105
+ lineCap: "round",
1106
+ stroke: current.caption.highlightColor ? current.caption.highlightColor : captionsSettings.style.aplifiedWordColor,
1107
+ strokeWidth: 5
1108
+ //opacity: easeFn(current.progress),
1109
+ });
1110
+ current.text.parent?.add(underline);
1111
+ }
1112
+ break;
1113
+ case "box":
1114
+ const xOffset = 12;
1115
+ const yOffset = 5;
1116
+ const cornerRadius = 6;
1117
+ const box = new Konva3.Rect({
1118
+ x: -xOffset,
1119
+ y: -yOffset - 2,
1120
+ width: chunk.width + 2 * xOffset,
1121
+ height: chunk.height + 2 * yOffset + 2,
1122
+ fill: captionsSettings.style.backgroundColor,
1123
+ cornerRadius
1124
+ });
1125
+ chunk.group.add(box);
1126
+ box.moveToBottom();
1127
+ break;
1128
+ case "box-word":
1129
+ if (current) {
1130
+ const underline = new Konva3.Line({
1131
+ id: "box-word",
1132
+ points: [
1133
+ current.text.x() + 6,
1134
+ current.text.height() - current.text.height() / 2,
1135
+ current.text.x() + (current.textTrim.width() - 6) * easeFn(1),
1136
+ current.text.height() - current.text.height() / 2
1137
+ ],
1138
+ lineCap: "round",
1139
+ stroke: captionsSettings.style.backgroundColor,
1140
+ strokeWidth: current.textTrim.height() + 2
1141
+ });
1142
+ underline.zIndex(4);
1143
+ current.text?.parent?.add(underline);
1144
+ }
1145
+ break;
1146
+ case "pop":
1147
+ const scaleFactor = 0.5 + 0.5 * mapEaseToFn["easeOutBack" /* outBack */](progress);
1148
+ chunk.group.scale({
1149
+ x: scaleFactor,
1150
+ y: scaleFactor
1151
+ });
1152
+ break;
1153
+ case "scale":
1154
+ const scaleFactor2 = 0.4 + 0.6 * mapEaseToFn["linear" /* linear */](progress);
1155
+ chunk.group.scale({
1156
+ x: scaleFactor2,
1157
+ y: scaleFactor2
1158
+ });
1159
+ break;
1160
+ case "slide-down":
1161
+ chunk.group.y(
1162
+ chunk.group.y() - slideOffset + slideOffset * mapEaseToFn["linear" /* linear */](progress)
1163
+ );
1164
+ break;
1165
+ case "slide-up":
1166
+ chunk.group.y(
1167
+ chunk.group.y() + slideOffset - slideOffset * mapEaseToFn["linear" /* linear */](progress)
1168
+ );
1169
+ break;
1170
+ case "slide-left":
1171
+ chunk.group.x(
1172
+ chunk.group.x() + slideOffset - slideOffset * mapEaseToFn["linear" /* linear */](progress)
1173
+ );
1174
+ break;
1175
+ default:
1176
+ break;
1177
+ }
1178
+ };
1179
+
1180
+ // src/canvas-captions/utils.ts
1181
+ var SOCIAL_NETWORK_OFFSET = 70;
1182
+ var splitCaptionsBytotalWordsToDisplay = (captions, totalWordsToDisplay, linesPerPage) => {
1183
+ const result = [];
1184
+ let currentCaptionIndex = 0;
1185
+ let currentSymbolsLength = 0;
1186
+ let currentBlock = [];
1187
+ let currentLine = 1;
1188
+ const maxWordGapSec = 1;
1189
+ const isValidBlockGap = (currentBlock2, caption) => {
1190
+ return currentBlock2.length > 0 && caption.startTime - currentBlock2[currentBlock2.length - 1].endTime < maxWordGapSec || currentBlock2.length === 0;
1191
+ };
1192
+ while (currentCaptionIndex < captions.length) {
1193
+ const caption = captions[currentCaptionIndex];
1194
+ if (currentSymbolsLength + caption.word.length <= totalWordsToDisplay && isValidBlockGap(currentBlock, caption)) {
1195
+ currentBlock.push(caption);
1196
+ currentSymbolsLength += caption.word.length;
1197
+ currentCaptionIndex++;
1198
+ } else if (linesPerPage > currentLine && isValidBlockGap(currentBlock, caption)) {
1199
+ currentBlock.push(caption);
1200
+ currentCaptionIndex++;
1201
+ currentSymbolsLength = caption.word.length;
1202
+ currentLine++;
1203
+ } else {
1204
+ if (currentBlock.length > 0) {
1205
+ result.push(currentBlock);
1206
+ }
1207
+ currentBlock = [];
1208
+ currentBlock.push(caption);
1209
+ currentSymbolsLength = caption.word.length;
1210
+ currentCaptionIndex++;
1211
+ currentLine = 1;
1212
+ }
1213
+ }
1214
+ if (currentBlock.length > 0) {
1215
+ result.push(currentBlock);
1216
+ }
1217
+ return result;
1218
+ };
1219
+ var fontWeightToFontStyle = (fontWeight, isItalic) => {
1220
+ return (isItalic ? "italic " : "") + fontWeightToNumber(fontWeight);
1221
+ };
1222
+ var fontWeightToNumber = (fontWeight) => {
1223
+ switch (fontWeight) {
1224
+ case "thin":
1225
+ return 100;
1226
+ case "light":
1227
+ return 300;
1228
+ case "regular":
1229
+ return 400;
1230
+ case "medium":
1231
+ return 500;
1232
+ case "bold":
1233
+ return 700;
1234
+ case "black":
1235
+ return 900;
1236
+ default:
1237
+ return 400;
1238
+ }
1239
+ };
1240
+ var getFillColor = (caption, isCurrentCaption, isPastCaption, captionsSettings) => {
1241
+ if (captionsSettings.animation === "underline") {
1242
+ return captionsSettings.style.font.fontColor;
1243
+ }
1244
+ if (captionsSettings.animation === "box" && (isCurrentCaption || isPastCaption)) {
1245
+ return caption.highlightColor || captionsSettings.style.aplifiedWordColor;
1246
+ }
1247
+ if (isCurrentCaption) {
1248
+ return caption.highlightColor || captionsSettings.style.aplifiedWordColor;
1249
+ }
1250
+ return captionsSettings.style.font.fontColor;
1251
+ };
1252
+ var getCaptionsGroupY = (groupHeight, canvasWidth, canvasHeight, position, offset, toCoef) => {
1253
+ const aspectRatio = canvasWidth / canvasHeight;
1254
+ const socialOffset = aspectRatio <= 1 ? SOCIAL_NETWORK_OFFSET * toCoef : 0;
1255
+ switch (position) {
1256
+ case "top":
1257
+ return (offset + 20) * toCoef + groupHeight / 2;
1258
+ case "middle":
1259
+ return canvasHeight / 2 + offset * toCoef;
1260
+ default:
1261
+ return canvasHeight - groupHeight / 2 - (20 + offset) * toCoef - socialOffset;
1262
+ }
1263
+ };
1264
+ var alignLinesInGroup = (group, maxGroupWidth, xOffset) => {
1265
+ group.children.forEach((line, i) => {
1266
+ const lineWords = line.children;
1267
+ const lineWordsWidth = lineWords.reduce(
1268
+ (acc, word, currentIndex) => acc + word.width() + (currentIndex > 0 ? xOffset : 0),
1269
+ 0
1270
+ );
1271
+ const lineX = (maxGroupWidth - lineWordsWidth) / 2;
1272
+ line.x(lineX);
1273
+ });
1274
+ };
1275
+ var alphabetEN = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
1276
+ var alphabetRU = "\u0410\u0411\u0412\u0413\u0414\u0415\u0401\u0416\u0417\u0418\u0419\u041A\u041B\u041C\u041D\u041E\u041F\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042A\u042B\u042C\u042D\u042E\u042F\u0430\u0431\u0432\u0433\u0434\u0435\u0451\u0436\u0437\u0438\u0439\u043A\u043B\u043C\u043D\u043E\u043F\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044A\u044B\u044C\u044D\u044E\u044F";
1277
+ var alphabetArabic = "\u0627 \u0628 \u062A \u062B \u062C \u062D \u062E \u062F \u0630 \u0631 \u0632 \u0633 \u0634 \u0635 \u0636 \u0637 \u0638 \u0639 \u063A \u0641 \u0642 \u0643 \u0644 \u0645 \u0646 \u0647 \u0648 \u064A";
1278
+ var getAverageSymbolsInLine = (targetWidth, textWidth, alphabetLength, captionsSettings) => {
1279
+ const offset = captionsSettings.animation === "box" || captionsSettings.animation === "bounce" ? 4 : 2;
1280
+ const avg = Math.round(targetWidth / (textWidth / alphabetLength)) - offset;
1281
+ return avg > 0 ? avg : 0;
1282
+ };
1283
+ var getAlphabet = (kind) => {
1284
+ switch (kind) {
1285
+ case "cyrillic" /* Cyrillic */:
1286
+ return alphabetRU;
1287
+ case "latin" /* Latin */:
1288
+ return alphabetEN;
1289
+ case "arabic" /* Arabic */:
1290
+ return alphabetArabic;
1291
+ default:
1292
+ return "latin" /* Latin */;
1293
+ }
1294
+ };
1295
+ var detectAlphabetKind = (text) => {
1296
+ if (isCyrillic(text)) {
1297
+ return "cyrillic" /* Cyrillic */;
1298
+ }
1299
+ if (isLatin(text)) {
1300
+ return "latin" /* Latin */;
1301
+ }
1302
+ if (isArabic(text)) {
1303
+ return "arabic" /* Arabic */;
1304
+ }
1305
+ return "latin" /* Latin */;
1306
+ };
1307
+ function isCyrillic(text) {
1308
+ return /[\u0400-\u04FF]/.test(text);
1309
+ }
1310
+ function isLatin(text) {
1311
+ return /[A-Za-z]/.test(text);
1312
+ }
1313
+ function isArabic(text) {
1314
+ return /[\u0600-\u06FF]/.test(text);
1315
+ }
1316
+
1317
+ // src/canvas-captions/index.ts
1318
+ import objectHash from "object-hash";
1319
+ var memo = {};
1320
+ var renderFrame = (captionsSettings, layoutSettings, captions, currentTime, targetSize, layer, toCoef, position) => {
1321
+ const style = captionsSettings.style.name;
1322
+ const [width, height] = targetSize;
1323
+ const targetFontSize = captionsSettings.style.font.fontSize * (toCoef ?? 1);
1324
+ let totalSymbolInLine = 0;
1325
+ const hash = objectHash({ captionsSettings });
1326
+ if (memo[hash]) {
1327
+ totalSymbolInLine = memo[hash];
1328
+ } else {
1329
+ const textForDetectAlphabet = captions.slice(0, 10).map((x) => x.word).join("");
1330
+ const alphabetKind = detectAlphabetKind(textForDetectAlphabet);
1331
+ const alphabet = getAlphabet(alphabetKind);
1332
+ const alphabetText = new Konva4.Text({
1333
+ text: captionsSettings.style.font.fontCapitalize ? alphabet.toUpperCase() : alphabet,
1334
+ x: 0,
1335
+ y: 0,
1336
+ fontSize: targetFontSize,
1337
+ fontFamily: captionsSettings.style.font.fontFamily,
1338
+ fontStyle: fontWeightToFontStyle(
1339
+ captionsSettings.style.font.fontWeight,
1340
+ captionsSettings.style.font.italic
1341
+ ),
1342
+ stroke: captionsSettings.style.font.fontStrokeColor,
1343
+ strokeWidth: captionsSettings.style.font.fontStrokeWidth ? captionsSettings.style.font.fontStrokeWidth / 10 : 0,
1344
+ textDecoration: captionsSettings.style.font.underline ? "underline" : "",
1345
+ fill: "black"
1346
+ });
1347
+ alphabetText.fillAfterStrokeEnabled(true);
1348
+ totalSymbolInLine = getAverageSymbolsInLine(
1349
+ layer.getWidth(),
1350
+ alphabetText.getWidth(),
1351
+ alphabet.length,
1352
+ captionsSettings
1353
+ );
1354
+ memo[hash] = totalSymbolInLine;
1355
+ }
1356
+ const chunks = splitCaptionsBytotalWordsToDisplay(
1357
+ captions,
1358
+ totalSymbolInLine - 6,
1359
+ captionsSettings.linesPerPage
1360
+ );
1361
+ const currentChunk = chunks.find(
1362
+ (chunk) => chunk[0].startTime <= currentTime && chunk[chunk.length - 1].endTime >= currentTime
1363
+ );
1364
+ const xOffset = targetFontSize * 0.1;
1365
+ const yOffset = captionsSettings.lineSpacing ?? 4;
1366
+ if (currentChunk) {
1367
+ var group = new Konva4.Group();
1368
+ let x = 0;
1369
+ let y = 0;
1370
+ let maxGroupWidth = 0;
1371
+ let groupWidth = 0;
1372
+ let groupHeight = 0;
1373
+ let line = new Konva4.Group();
1374
+ let currentSymbolsLength = 0;
1375
+ let box = new Konva4.Group();
1376
+ let current = void 0;
1377
+ currentChunk.forEach((caption, index) => {
1378
+ const isCurrentCaption = caption.startTime <= currentTime && caption.endTime >= currentTime;
1379
+ const isPastCaption = caption.endTime < currentTime;
1380
+ const fillColor = getFillColor(
1381
+ caption,
1382
+ isCurrentCaption,
1383
+ isPastCaption,
1384
+ captionsSettings
1385
+ );
1386
+ const isLastWordInLine = currentSymbolsLength + caption.word.length + (index < currentChunk.length - 1 ? currentChunk[index + 1].word.length : 0) > totalSymbolInLine || currentChunk.length - 1 === index;
1387
+ let word = captionsSettings.style.font.fontCapitalize ? caption.word.toUpperCase() : caption.word;
1388
+ word = isLastWordInLine ? word.trim() : word;
1389
+ const createKonvaText = (word2, x2, targetFontSize2, captionsSettings2, fillColor2, trim) => {
1390
+ return new Konva4.Text({
1391
+ text: trim ? word2?.trim() : word2,
1392
+ x: x2,
1393
+ y: 0,
1394
+ drawBorder: true,
1395
+ fontSize: targetFontSize2,
1396
+ fontFamily: captionsSettings2.style.font.fontFamily,
1397
+ fontStyle: fontWeightToFontStyle(
1398
+ captionsSettings2.style.font.fontWeight,
1399
+ captionsSettings2.style.font.italic
1400
+ ),
1401
+ stroke: captionsSettings2.style.font.fontStrokeColor,
1402
+ strokeWidth: captionsSettings2.style.font.fontStrokeWidth ? captionsSettings2.style.font.fontStrokeWidth / 10 : 0,
1403
+ textDecoration: captionsSettings2.style.font.underline ? "underline" : "",
1404
+ fill: fillColor2,
1405
+ shadowColor: captionsSettings2.style.font.shadow?.fontShadowColor,
1406
+ shadowBlur: captionsSettings2.style.font.shadow?.fontShadowBlur ?? 0,
1407
+ shadowOffset: captionsSettings2.style.font.shadow ? {
1408
+ x: captionsSettings2.style.font.shadow?.fontShadowOffsetX ?? 0,
1409
+ y: captionsSettings2.style.font.shadow?.fontShadowOffsetY ?? 0
1410
+ } : void 0
1411
+ });
1412
+ };
1413
+ const text = createKonvaText(
1414
+ word,
1415
+ x,
1416
+ targetFontSize,
1417
+ captionsSettings,
1418
+ fillColor,
1419
+ false
1420
+ );
1421
+ text.fillAfterStrokeEnabled(true);
1422
+ const textTrim = captionsSettings.animation === "box-word" ? createKonvaText(
1423
+ word,
1424
+ x,
1425
+ targetFontSize,
1426
+ captionsSettings,
1427
+ fillColor,
1428
+ true
1429
+ ) : null;
1430
+ if (isCurrentCaption) {
1431
+ current = {
1432
+ caption,
1433
+ text,
1434
+ progress: (currentTime - caption.startTime) / (caption.endTime - caption.startTime),
1435
+ textTrim
1436
+ //progress: Math.min(1, (currentTime - caption.start_time) / 0.5),
1437
+ };
1438
+ }
1439
+ x += text.width() + xOffset + (captionsSettings.animation === "bounce" ? 8 : 0) + (captionsSettings.style.font.fontCapitalize ? 2 : 0);
1440
+ groupWidth += text.width() + (isLastWordInLine ? 0 : xOffset);
1441
+ line.y(y);
1442
+ line.add(text);
1443
+ if (isLastWordInLine) {
1444
+ group.add(line);
1445
+ x = 0;
1446
+ const isLastLine = index + 1 === currentChunk.length;
1447
+ y += text.height() + yOffset;
1448
+ groupHeight += text.height() + (isLastLine ? 0 : yOffset);
1449
+ if (groupWidth > maxGroupWidth) {
1450
+ maxGroupWidth = groupWidth;
1451
+ }
1452
+ groupWidth = 0;
1453
+ line = new Konva4.Group();
1454
+ currentSymbolsLength = 0;
1455
+ } else {
1456
+ currentSymbolsLength += caption.word.length;
1457
+ }
1458
+ });
1459
+ alignLinesInGroup(group, maxGroupWidth, xOffset);
1460
+ const progress = Math.min(
1461
+ 1,
1462
+ (currentTime - currentChunk[0].startTime) / 0.2
1463
+ );
1464
+ group.offsetX(maxGroupWidth / 2);
1465
+ group.offsetY(groupHeight / 2);
1466
+ group.x(width / 2);
1467
+ group.y(
1468
+ getCaptionsGroupY(
1469
+ groupHeight,
1470
+ width,
1471
+ height,
1472
+ position?.type ?? captionsSettings.position,
1473
+ position?.positionTopOffset ?? captionsSettings.positionTopOffset ?? 0,
1474
+ toCoef ?? 1
1475
+ )
1476
+ );
1477
+ animate(
1478
+ captionsSettings,
1479
+ progress,
1480
+ {
1481
+ group,
1482
+ width: maxGroupWidth,
1483
+ height: groupHeight
1484
+ },
1485
+ current
1486
+ );
1487
+ if (current?.text && captionsSettings.animation === "box-word") {
1488
+ current.text?.zIndex(10);
1489
+ }
1490
+ layer.add(group);
1491
+ }
1492
+ layer.draw();
1493
+ };
1494
+
1495
+ // src/captions/Captions.ts
1496
+ var Captions = class {
1497
+ /**
1498
+ * Create a controller bound to the provided video element and preset.
1499
+ *
1500
+ * @param options - Complete configuration for the controller.
1501
+ */
1502
+ constructor(options) {
1503
+ this.enabled = false;
1504
+ this.ownsContainer = false;
1505
+ this.stage = null;
1506
+ this.layer = null;
1507
+ this.animationFrameId = null;
1508
+ this.videoWidth = 0;
1509
+ this.videoHeight = 0;
1510
+ this.handleResize = () => {
1511
+ this.syncStageDimensions();
1512
+ };
1513
+ this.handleMetadata = () => {
1514
+ this.syncStageDimensions();
1515
+ };
1516
+ this.animationLoop = () => {
1517
+ this.updateFrame();
1518
+ this.animationFrameId = requestAnimationFrame(this.animationLoop);
1519
+ };
1520
+ if (!options.video) {
1521
+ throw new Error("captionsjs requires a video element");
1522
+ }
1523
+ this.video = options.video;
1524
+ this.providedContainer = options.container;
1525
+ this.presetState = options.preset;
1526
+ this.captionsState = options.captions ?? null;
1527
+ if (options.autoEnable ?? true) {
1528
+ this.enable();
1529
+ }
1530
+ }
1531
+ /**
1532
+ * Mount caption overlays onto the configured video if they are not active yet.
1533
+ */
1534
+ enable() {
1535
+ if (this.enabled) {
1536
+ return;
1537
+ }
1538
+ this.containerElement = this.providedContainer ?? this.createOverlay();
1539
+ this.ownsContainer = !this.providedContainer;
1540
+ this.stage = new Konva5.Stage({
1541
+ container: this.containerElement
1542
+ });
1543
+ this.layer = new Konva5.Layer();
1544
+ this.stage.add(this.layer);
1545
+ this.videoWidth = this.video.videoWidth;
1546
+ this.videoHeight = this.video.videoHeight;
1547
+ window.addEventListener("resize", this.handleResize);
1548
+ if (typeof ResizeObserver !== "undefined") {
1549
+ this.resizeObserver = new ResizeObserver(this.handleResize);
1550
+ this.resizeObserver.observe(this.video);
1551
+ }
1552
+ this.video.addEventListener("loadedmetadata", this.handleMetadata);
1553
+ this.syncStageDimensions();
1554
+ this.animationFrameId = requestAnimationFrame(this.animationLoop);
1555
+ this.enabled = true;
1556
+ void this.refreshFrame();
1557
+ }
1558
+ /**
1559
+ * Tear down overlays, observers and animation loops to free resources.
1560
+ */
1561
+ disable() {
1562
+ if (!this.enabled) {
1563
+ return;
1564
+ }
1565
+ if (this.animationFrameId !== null) {
1566
+ cancelAnimationFrame(this.animationFrameId);
1567
+ this.animationFrameId = null;
1568
+ }
1569
+ window.removeEventListener("resize", this.handleResize);
1570
+ this.video.removeEventListener("loadedmetadata", this.handleMetadata);
1571
+ this.resizeObserver?.disconnect();
1572
+ this.resizeObserver = void 0;
1573
+ if (this.ownsContainer && this.containerElement?.parentElement) {
1574
+ this.containerElement.parentElement.removeChild(this.containerElement);
1575
+ }
1576
+ this.stage?.destroy();
1577
+ this.stage = null;
1578
+ this.layer = null;
1579
+ this.containerElement = void 0;
1580
+ this.ownsContainer = false;
1581
+ this.enabled = false;
1582
+ }
1583
+ /**
1584
+ * Alias for {@link Captions.disable | disable()} to match typical imperative controller APIs.
1585
+ */
1586
+ destroy() {
1587
+ this.disable();
1588
+ }
1589
+ /**
1590
+ * Swap the active preset and re-render with updated typography/colors.
1591
+ *
1592
+ * @param nextPreset - Preset that becomes the new render baseline.
1593
+ */
1594
+ preset(nextPreset) {
1595
+ this.presetState = nextPreset;
1596
+ if (!this.enabled) {
1597
+ return;
1598
+ }
1599
+ void this.refreshFrame();
1600
+ }
1601
+ /**
1602
+ * Replace the current caption track and repaint without reloading fonts.
1603
+ *
1604
+ * @param nextCaptions - Timed words that should drive the overlay.
1605
+ */
1606
+ captions(nextCaptions) {
1607
+ this.captionsState = nextCaptions;
1608
+ if (!this.enabled) {
1609
+ return;
1610
+ }
1611
+ void this.refreshFrame(false);
1612
+ }
1613
+ /**
1614
+ * Whether the Konva overlay is currently attached to the video element.
1615
+ *
1616
+ * @returns `true` when the overlay is mounted on top of the video.
1617
+ */
1618
+ isEnabled() {
1619
+ return this.enabled;
1620
+ }
1621
+ async refreshFrame(loadFont = true) {
1622
+ if (!this.layer || !this.stage) {
1623
+ return;
1624
+ }
1625
+ if (loadFont) {
1626
+ await this.loadFontForCurrentPreset();
1627
+ }
1628
+ this.updateFrame();
1629
+ }
1630
+ async loadFontForCurrentPreset() {
1631
+ const fontFamily = this.presetState.captionsSettings.style.font.fontFamily;
1632
+ await loadGoogleFont2(fontFamily);
1633
+ }
1634
+ updateFrame() {
1635
+ if (!this.layer || !this.stage) {
1636
+ return;
1637
+ }
1638
+ if (!this.videoWidth || !this.videoHeight) {
1639
+ return;
1640
+ }
1641
+ this.layer.destroyChildren();
1642
+ const captionsSettings = this.presetState.captionsSettings;
1643
+ renderFrame(
1644
+ captionsSettings,
1645
+ void 0,
1646
+ this.captionsState || [],
1647
+ this.video.currentTime,
1648
+ [this.videoWidth, this.videoHeight],
1649
+ this.layer,
1650
+ 2,
1651
+ {
1652
+ type: captionsSettings.position ?? "bottom",
1653
+ positionTopOffset: captionsSettings.positionTopOffset ?? 0
1654
+ }
1655
+ );
1656
+ }
1657
+ syncStageDimensions() {
1658
+ if (!this.stage) {
1659
+ return;
1660
+ }
1661
+ const currentVideoWidth = this.video.videoWidth || this.videoWidth;
1662
+ const currentVideoHeight = this.video.videoHeight || this.videoHeight;
1663
+ if (!currentVideoWidth || !currentVideoHeight) {
1664
+ return;
1665
+ }
1666
+ this.videoWidth = currentVideoWidth;
1667
+ this.videoHeight = currentVideoHeight;
1668
+ this.stage.width(this.videoWidth);
1669
+ this.stage.height(this.videoHeight);
1670
+ const rect = this.video.getBoundingClientRect();
1671
+ const stageContainer = this.stage.container();
1672
+ const displayWidth = rect.width || stageContainer.offsetWidth || this.videoWidth;
1673
+ const displayHeight = rect.height || stageContainer.offsetHeight || this.videoHeight;
1674
+ if (displayWidth && displayHeight) {
1675
+ stageContainer.style.width = `${displayWidth}px`;
1676
+ stageContainer.style.height = `${displayHeight}px`;
1677
+ const scaleX = displayWidth / this.videoWidth;
1678
+ const scaleY = displayHeight / this.videoHeight;
1679
+ this.stage.scale({ x: scaleX, y: scaleY });
1680
+ } else {
1681
+ this.stage.scale({ x: 1, y: 1 });
1682
+ stageContainer.style.width = `${this.videoWidth}px`;
1683
+ stageContainer.style.height = `${this.videoHeight}px`;
1684
+ }
1685
+ this.stage.batchDraw();
1686
+ }
1687
+ createOverlay() {
1688
+ const container = document.createElement("div");
1689
+ container.style.position = "absolute";
1690
+ container.style.top = "0";
1691
+ container.style.left = "0";
1692
+ container.style.width = "100%";
1693
+ container.style.height = "100%";
1694
+ container.style.pointerEvents = "none";
1695
+ this.video.parentElement?.appendChild(container);
1696
+ return container;
1697
+ }
1698
+ };
1699
+ function captionsjs(options) {
1700
+ return new Captions(options);
1701
+ }
1702
+
1
1703
  // src/index.ts
2
1704
  function renderCaptions(ctx, text) {
3
- ctx.font = "24px sans-serif";
4
- ctx.fillStyle = "#17c499ff";
1705
+ ctx.font = "48px sans-serif";
1706
+ ctx.fillStyle = "red";
5
1707
  ctx.fillText(text, 150, 50);
6
1708
  return true;
7
1709
  }
1710
+ var index_default = captionsjs;
8
1711
  export {
9
- renderCaptions
1712
+ Captions,
1713
+ captionsjs,
1714
+ index_default as default,
1715
+ googleFontsList,
1716
+ renderCaptions,
1717
+ renderString,
1718
+ stylePresets
10
1719
  };