@phont-ai/subtitles-core 0.1.10 → 0.2.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.d.mts CHANGED
@@ -45,6 +45,125 @@ interface PhontClientOptions {
45
45
  apiBaseUrl?: string;
46
46
  }
47
47
 
48
+ /**
49
+ * Animation Types
50
+ *
51
+ * Type definitions for animation parameter states, curves, and animation state
52
+ */
53
+ interface CurvePoint {
54
+ time: number;
55
+ value: number | string;
56
+ }
57
+ interface ParameterState {
58
+ points: CurvePoint[];
59
+ currentValue?: number | string;
60
+ }
61
+ interface ParameterStates {
62
+ [key: string]: ParameterState;
63
+ }
64
+ interface AnimationParameterStates {
65
+ parameterStates: ParameterStates;
66
+ duration?: number;
67
+ format?: 'normalized' | 'absolute';
68
+ fontData?: {
69
+ style?: {
70
+ fontFamily?: string;
71
+ [key: string]: unknown;
72
+ };
73
+ config?: unknown;
74
+ fontId?: string | null;
75
+ fontName?: string | null;
76
+ };
77
+ text?: string;
78
+ name?: string;
79
+ }
80
+ interface AnimationState {
81
+ fontSize: number;
82
+ scale: number;
83
+ opacity: number;
84
+ slant: number;
85
+ weight: number;
86
+ width: number;
87
+ textColor: string;
88
+ translateX: number;
89
+ translateY: number;
90
+ stretchY: number;
91
+ rotation?: number;
92
+ skewX?: number;
93
+ fontVariationAxes?: Record<string, number>;
94
+ letterShake?: number;
95
+ shadowColor?: string;
96
+ }
97
+ interface SentenceAnimationState extends AnimationState {
98
+ text: string;
99
+ emotion: string;
100
+ emotionIntensity: number;
101
+ fontFamily: string;
102
+ startTime: number;
103
+ endTime: number;
104
+ duration: number;
105
+ isActive: boolean;
106
+ }
107
+ interface WordAnimationState {
108
+ text: string;
109
+ words: Array<{
110
+ word: string;
111
+ start: number;
112
+ end: number;
113
+ animationEnd: number;
114
+ isActive: boolean;
115
+ emotion: string;
116
+ emotionIntensity: number;
117
+ originalEmotionIntensity?: number;
118
+ fontFamily: string;
119
+ emphasis: number;
120
+ emphasisEffect?: any;
121
+ strongEmphasis?: any;
122
+ animationParameters: AnimationState;
123
+ joyAnimationMode?: 'letter' | 'letter-bulge' | 'word' | null;
124
+ joyProgress?: number | null;
125
+ }>;
126
+ currentWordIndex: number;
127
+ emotion: string;
128
+ emotionIntensity: number;
129
+ fontFamily: string;
130
+ startTime: number;
131
+ endTime: number;
132
+ isActive: boolean;
133
+ }
134
+ interface SubtitleSegment {
135
+ start_time: number;
136
+ end_time: number;
137
+ text?: string;
138
+ subtitle?: string;
139
+ emotion?: string;
140
+ emotion_intensity?: number;
141
+ animation_url?: string;
142
+ words?: Array<{
143
+ word: string;
144
+ start: number;
145
+ end: number;
146
+ emphasis?: number;
147
+ emotion?: string;
148
+ emotion_intensity?: number;
149
+ animation_url?: string;
150
+ animations?: Record<string, number>;
151
+ }>;
152
+ animations?: Record<string, number>;
153
+ volume?: number;
154
+ speech_rate?: number;
155
+ merged_subtitles?: SubtitleSegment[];
156
+ }
157
+ interface AnimationOptions {
158
+ maxExpression?: number;
159
+ threshold?: number;
160
+ isRTL?: boolean;
161
+ volume?: number;
162
+ speechRate?: number;
163
+ nextSegmentStartTime?: number;
164
+ extendedEndTime?: number;
165
+ }
166
+
48
167
  /**
49
168
  * ============================================
50
169
  * SUBTITLE STATE MANAGER
@@ -164,12 +283,12 @@ declare class SubtitleStateManager {
164
283
  *
165
284
  * STATUS: Phase 2 Complete - All 8 classes extracted, clean architecture, no duplication
166
285
  */
167
- type AnimationMode = "Sentence" | "Word" | string;
286
+ type AnimationMode$1 = "Sentence" | "Word" | string;
168
287
  interface SubtitleState {
169
288
  isVisible: boolean;
170
289
  isKaraokeMode: boolean;
171
290
  isSpeaker: boolean;
172
- animationMode: AnimationMode;
291
+ animationMode: AnimationMode$1;
173
292
  currentSubtitle: string;
174
293
  currentSequence: number | null;
175
294
  subtitles: any[];
@@ -242,7 +361,7 @@ declare class SubtitleManager {
242
361
  toggleSoundbiteAnimations(isVisible: boolean): void;
243
362
  mapEventLabelToAnimation(eventLabel: string): string | null;
244
363
  processSoundbiteAnimations(soundbites: any[]): any[];
245
- setAnimationMode(mode: AnimationMode): void;
364
+ setAnimationMode(mode: AnimationMode$1): void;
246
365
  toggleTransition(enabled: boolean): void;
247
366
  updateSubtitle(text: string): void;
248
367
  updateLiveTime(videoTime?: number | null): number;
@@ -262,7 +381,7 @@ declare class SubtitleManager {
262
381
  getInitialLiveSequenceNumber(): Promise<number>;
263
382
  fetchSubtitles(sequenceNumber: number): Promise<any | null>;
264
383
  loadVodSubtitles(urlOrVodId: string, languageCode?: string | null): Promise<void>;
265
- _processVodData(data: any, url: string, languageCode: string | null): void;
384
+ _processVodData(data: any, url: string, languageCode: string | null, originalSubtitles?: any[]): void;
266
385
  getSubtitleForTime(time: number): any;
267
386
  getLiveSubtitleForTime(): any;
268
387
  getCurrentSubtitleData(): any | null;
@@ -293,106 +412,186 @@ declare class SubtitleManager {
293
412
  declare const subtitleManager: SubtitleManager;
294
413
 
295
414
  /**
296
- * Animation Types
415
+ * URL Decoder for Animation Parameters
297
416
  *
298
- * Type definitions for animation parameter states, curves, and animation state
417
+ * Extracted from app/playground/utils/urlEncoding.js
418
+ * Decodes animation URLs into parameter states
419
+ *
420
+ * Supports both full URLs and query strings:
421
+ * - Full URL: https://stage-dev.phont.ai/playground/shared?name=...&scale=0,1|1,1.2
422
+ * - Query string: ?name=...&scale=0,1|1,1.2
299
423
  */
300
- interface CurvePoint {
301
- time: number;
302
- value: number | string;
303
- }
304
- interface ParameterState {
305
- points: CurvePoint[];
306
- currentValue?: number | string;
307
- }
308
- interface ParameterStates {
309
- [key: string]: ParameterState;
310
- }
311
- interface AnimationParameterStates {
312
- parameterStates: ParameterStates;
313
- duration?: number;
314
- format?: 'normalized' | 'absolute';
315
- }
316
- interface AnimationState {
317
- fontSize: number;
424
+
425
+ /**
426
+ * Decode animation data from URL or query string
427
+ * @param urlOrQuery - Full URL (https://...) or query string (?name=... or name=...)
428
+ * @returns Decoded animation data object with parameterStates
429
+ */
430
+ declare function decodeAnimationUrl(urlOrQuery: string): AnimationParameterStates;
431
+
432
+ /**
433
+ * Animation parameter calculation -- the unified rendering pipeline.
434
+ * TypeScript port of app/utils/animation/animationParameters.js.
435
+ *
436
+ * Samples authored URL curves with linear interpolation, then scales deviations
437
+ * proportionally from a reference point (REFERENCE_INTENSITY × REFERENCE_GTS).
438
+ * At the reference point the authored curve is rendered 1:1.
439
+ */
440
+
441
+ /**
442
+ * Exponential variance curve (hockey stick)
443
+ *
444
+ * Creates an exponential curve that accelerates dramatically after 0.7 intensity.
445
+ * Low intensities (0.0-0.7): Subtle effects (gradual rise)
446
+ * High intensities (0.7-1.0): Dramatic effects (exponential acceleration)
447
+ *
448
+ * @param i - Input intensity (0-1)
449
+ * @returns Transformed intensity (0-1) with exponential variance
450
+ */
451
+ declare function hockeyStickIntensity(i: number): number;
452
+ /**
453
+ * Sample a parameter curve at a given time
454
+ *
455
+ * Interpolates between keyframe points to get the value at a specific time.
456
+ * Supports both normalized (0-1) and absolute time formats.
457
+ * For color parameters, uses RGB interpolation for smooth color transitions.
458
+ *
459
+ * @param points - Array of {time, value} points or [time, value] arrays
460
+ * @param t - Normalized time (0-1)
461
+ * @param duration - Animation duration in seconds
462
+ * @param isNormalized - Whether points are in normalized (0-1) or absolute time
463
+ * @param parameterName - Name of the parameter (e.g., 'color', 'shadowColor', 'outlineColor') for color interpolation
464
+ * @returns Sampled value or null if no points
465
+ */
466
+ declare function sampleParameterCurve(points: Array<{
467
+ time?: number;
468
+ value?: number | string;
469
+ } | [number, number | string]> | undefined | null, t: number, duration: number, isNormalized?: boolean, parameterName?: string | null): number | string | null;
470
+ interface AnimationParameterState {
471
+ rawIntensity: number;
472
+ scaleFactor: number;
318
473
  scale: number;
319
- opacity: number;
320
474
  slant: number;
475
+ stretchY: number;
476
+ translateX: number;
477
+ translateY: number;
321
478
  weight: number;
322
479
  width: number;
480
+ fontFamily: string;
323
481
  textColor: string;
324
- translateX: number;
325
- translateY: number;
326
- stretchY: number;
327
- rotation?: number;
328
- skewX?: number;
329
- fontVariationAxes?: Record<string, number>;
330
- letterShake?: number;
331
- letterSpacingOffsets?: number[];
332
- shadowColor?: string;
333
- }
334
- interface SentenceAnimationState extends AnimationState {
482
+ opacity: number;
483
+ textShadow: string;
484
+ blur: number;
485
+ outlineWidth: number;
486
+ outlineColor: string;
487
+ outline2Width?: number;
488
+ outline2Color?: string;
489
+ outline3Width?: number;
490
+ outline3Color?: string;
491
+ outlineShadowWidth?: number;
492
+ outlineShadowColor?: string;
493
+ outlineShadowBlur?: number;
494
+ glowIntensity?: number;
495
+ glowColor?: string;
496
+ snakeWave?: number;
497
+ karaoke?: number;
498
+ stretchX?: number;
499
+ letterSpacing: string;
500
+ fontVariationAxes: Record<string, number>;
335
501
  text: string;
336
- emotion: string;
337
- emotionIntensity: number;
338
- fontFamily: string;
339
- startTime: number;
340
- endTime: number;
341
- duration: number;
342
- isActive: boolean;
502
+ joy: number;
503
+ fear: number;
504
+ standardEmphasis: number;
505
+ strongEmphasis: number;
506
+ joyWaveProgress: number;
343
507
  }
344
- interface WordAnimationState {
345
- text: string;
346
- words: Array<{
347
- word: string;
348
- start: number;
349
- end: number;
350
- animationEnd: number;
351
- isActive: boolean;
352
- emotion: string;
353
- emotionIntensity: number;
354
- originalEmotionIntensity?: number;
355
- fontFamily: string;
356
- emphasis: number;
357
- emphasisEffect?: any;
358
- strongEmphasis?: any;
359
- animationParameters: AnimationState;
360
- joyAnimationMode?: 'letter' | 'letter-bulge' | 'word' | null;
361
- joyProgress?: number | null;
362
- }>;
363
- currentWordIndex: number;
508
+ declare const REFERENCE_INTENSITY = 0.7;
509
+ declare const REFERENCE_GTS = 0.7;
510
+ /**
511
+ * Sample all animation parameters at time `t` with proportional intensity scaling.
512
+ *
513
+ * The authored curve represents the animation at REFERENCE_INTENSITY × REFERENCE_GTS.
514
+ * At those values you see exactly what was authored. Other intensity × GTS values
515
+ * scale linearly from there.
516
+ */
517
+ declare function calculateAnimationParameters(animationData: AnimationParameterStates | null, rawIntensity: number, t: number, gts: number, subtitleDuration?: number | null, { rawMode }?: {
518
+ rawMode?: boolean;
519
+ }): AnimationParameterState | null;
520
+
521
+ type AnimationMode = 'sentence' | 'word';
522
+ type AnimationStateOptions = AnimationOptions & {
523
+ transparentUntilSpoken?: boolean;
524
+ };
525
+ declare function calculateAnimationState(segment: SubtitleSegment | null, currentTime: number, modeOrOptions?: AnimationMode | AnimationStateOptions, maybeOptions?: AnimationStateOptions): SentenceAnimationState | WordAnimationState;
526
+
527
+ /**
528
+ * Emotion Animation URLs
529
+ *
530
+ * Config mapping emotion → animation URL
531
+ * Uses full playground URLs from app/gallery/config/animations.js
532
+ *
533
+ * SYNCED FROM: app/gallery/config/emotionMapping.js
534
+ *
535
+ * To update these URLs:
536
+ * 1. Update app/gallery/config/animations.js with new URLs
537
+ * 2. Update app/gallery/config/emotionMapping.js to map emotions to indices
538
+ * 3. Run: node scripts/sync-animation-urls.js
539
+ * OR manually copy the URLs based on the mapping
540
+ *
541
+ * The decodeAnimationUrl() function now supports both full URLs and query strings.
542
+ */
543
+ declare const ANIMATION_URLS: string[];
544
+ /**
545
+ * Emotion to Animation URL mapping
546
+ * Based on app/gallery/config/emotionMapping.js
547
+ *
548
+ * Maps each emotion to an index in ANIMATION_URLS array
549
+ */
550
+ declare const EMOTION_ANIMATION_URLS: Record<string, string>;
551
+ /**
552
+ * Get animation URL for an emotion
553
+ * @param emotion - Emotion name (case-insensitive)
554
+ * @returns Full animation URL or query string fallback
555
+ */
556
+ declare function getAnimationUrlForEmotion(emotion: string): string;
557
+
558
+ /**
559
+ * Published Animation Resolver (framework-agnostic)
560
+ *
561
+ * Fetches the active published animation URL for each emotion from the backend,
562
+ * caches the results, and provides sync/async accessors.
563
+ *
564
+ * Any consumer (app, SDK, extension) creates an instance by supplying a fetcher
565
+ * that returns an array of animation objects for a given stylesheet.
566
+ *
567
+ * USAGE:
568
+ * import { createPublishedAnimationResolver } from '@phont-ai/subtitles-core';
569
+ *
570
+ * const resolver = createPublishedAnimationResolver(
571
+ * async (stylesheet) => fetch(`/animations?stylesheet_name=${stylesheet}&is_active=true`).then(r => r.json())
572
+ * );
573
+ *
574
+ * await resolver.prefetch('default'); // warm the cache
575
+ * const url = resolver.getSync('lust'); // sync (returns null if not cached)
576
+ * const url = await resolver.get('lust'); // async (fetches if needed)
577
+ * resolver.invalidate(); // bust after publishing
578
+ */
579
+ interface AnimationRecord {
364
580
  emotion: string;
365
- emotionIntensity: number;
366
- fontFamily: string;
367
- startTime: number;
368
- endTime: number;
369
- isActive: boolean;
370
- }
371
- interface SubtitleSegment {
372
- start_time: number;
373
- end_time: number;
374
- text?: string;
375
- subtitle?: string;
376
- words?: Array<{
377
- word: string;
378
- start: number;
379
- end: number;
380
- emphasis?: number;
381
- }>;
382
- animations?: Record<string, number>;
383
- volume?: number;
384
- speech_rate?: number;
385
- merged_subtitles?: SubtitleSegment[];
581
+ url: string;
582
+ is_active: boolean;
583
+ [key: string]: unknown;
386
584
  }
387
- interface AnimationOptions {
388
- maxExpression?: number;
389
- threshold?: number;
390
- isRTL?: boolean;
391
- volume?: number;
392
- speechRate?: number;
393
- nextSegmentStartTime?: number;
394
- extendedEndTime?: number;
585
+ type AnimationFetcher = (stylesheetName: string) => Promise<AnimationRecord[]>;
586
+ interface PublishedAnimationResolver {
587
+ prefetch: (stylesheetName?: string) => Promise<Map<string, string>>;
588
+ get: (emotion: string, stylesheetName?: string) => Promise<string | null>;
589
+ getSync: (emotion: string, stylesheetName?: string) => string | null;
590
+ invalidate: () => void;
395
591
  }
592
+ declare function createPublishedAnimationResolver(fetcher: AnimationFetcher, { ttlMs }?: {
593
+ ttlMs?: number;
594
+ }): PublishedAnimationResolver;
396
595
 
397
596
  /**
398
597
  * Emotion Selector
@@ -421,86 +620,24 @@ interface EmotionSelectionResult {
421
620
  declare function selectEmotion(animationsObject: Record<string, number> | null | undefined, threshold?: number): EmotionSelectionResult;
422
621
 
423
622
  /**
424
- * Animation Engine
623
+ * Timing Utilities
425
624
  *
426
- * Pure functions that calculate animation state from emotion curves
427
- * Uses function-based EMOTION_ANIMATIONS (identical to monorepo)
625
+ * Pure functions for calculating subtitle timing
428
626
  */
429
627
 
430
628
  /**
431
- * Calculate sentence animation state
432
- *
433
- * Pure function version of useSentenceAnimation - uses function-based EMOTION_ANIMATIONS (identical to monorepo)
629
+ * Get subtitle timing information
434
630
  */
435
- declare function calculateSentenceAnimation(segment: SubtitleSegment | null, currentTime: number, options?: AnimationOptions): SentenceAnimationState;
631
+ declare function getSubtitleTiming(subtitle: SubtitleSegment | null): {
632
+ startTime: number;
633
+ endTime: number;
634
+ duration: number;
635
+ };
436
636
  /**
437
- * Calculate word animation state
438
- *
439
- * Pure function version of useWordAnimation - uses function-based EMOTION_ANIMATIONS (identical to monorepo)
637
+ * Calculate normalized time (t: 0→1) through subtitle duration
440
638
  */
441
- declare function calculateWordAnimation(segment: SubtitleSegment | null, currentTime: number, options?: AnimationOptions): WordAnimationState;
442
- /**
443
- * Main function: Calculate animation state from segment and emotion
444
- *
445
- * This is the main entry point that uses function-based EMOTION_ANIMATIONS (identical to monorepo)
446
- */
447
- declare function calculateAnimationState(segment: SubtitleSegment | null, currentTime: number, mode: 'sentence' | 'word', options?: AnimationOptions): SentenceAnimationState | WordAnimationState;
448
-
449
- /**
450
- * Timing Utilities
451
- *
452
- * Pure functions for calculating subtitle timing
453
- */
454
-
455
- /**
456
- * Get subtitle timing information
457
- */
458
- declare function getSubtitleTiming(subtitle: SubtitleSegment | null): {
459
- startTime: number;
460
- endTime: number;
461
- duration: number;
462
- };
463
- /**
464
- * Get subtitle text content
465
- */
466
- declare function getSubtitleText(subtitle: SubtitleSegment | null): string;
467
- /**
468
- * Calculate normalized time (t: 0→1) through subtitle duration
469
- */
470
- declare function calculateNormalizedTime(currentTime: number, startTime: number, duration: number): number;
471
-
472
- /**
473
- * **EMOTION_CURVES_DEFINITION** - Animation DNA
474
- *
475
- * Emotion Curves - Animation Parameter Definitions
476
- *
477
- * These curves define how subtitle text animates over time based on emotion.
478
- * Each emotion has time-based functions that return values for visual parameters.
479
- *
480
- * PARAMETERS:
481
- * - fontSize: Always constant (ANIMATION_STYLING.fontSize) for layout stability
482
- * - scale: Size multiplier applied via CSS transform (prevents text wrapping)
483
- * - slant: Italic/skew effect in degrees (applied as CSS skewX)
484
- * - weight: Font weight (100-900) - overridden by VariableFontContext in practice
485
- * - translateX/Y: Movement in pixels (direct CSS values)
486
- * - textColor: Text color (rgba)
487
- * - stretchY: Vertical stretch multiplier (CSS scaleY)
488
- * - letterShakeIntensity: Per-letter shake amount in pixels (fear)
489
- *
490
- * WHY SCALE INSTEAD OF FONTSIZE:
491
- * Using transform: scale() instead of fontSize changes allows the layout engine
492
- * to calculate word positions ONCE at the base fontSize, preventing words from
493
- * wrapping to new lines mid-animation. Scale is GPU-accelerated and doesn't trigger reflow.
494
- *
495
- * ⚠️ Parameters NOT included (handled elsewhere):
496
- * - opacity: Always 1.0 (fade in/out handled by controllers)
497
- * - shadows: Handled by styling.js ANIMATION_STYLING.shadow (emotion-specific for disgust/angry)
498
- * - font family: Handled by fontSelection.js based on emotion + intensity
499
- * - transitions: Handled by styling.js ANIMATION_STYLING.transition
500
- * - marginRight: Handled by calculateDynamicWordSpacing() based on current scale
501
- */
502
- declare const EMOTION_ANIMATIONS: Record<string, any>;
503
-
639
+ declare function calculateNormalizedTime(currentTime: number, startTime: number, duration: number): number;
640
+
504
641
  /**
505
642
  * Animation Defaults - Visual Styling Layer
506
643
  *
@@ -572,6 +709,11 @@ declare const ANIMATION_STYLING: {
572
709
  wordSpacingMultiplier: number;
573
710
  fontSizeOffset: number;
574
711
  };
712
+ 'Bricolage Grotesque': {
713
+ letterSpacing: string;
714
+ wordSpacingMultiplier: number;
715
+ fontSizeOffset: number;
716
+ };
575
717
  Rakkas: {
576
718
  letterSpacing: string;
577
719
  wordSpacingMultiplier: number;
@@ -703,81 +845,22 @@ declare const RENDERING_CONTROL: {
703
845
  };
704
846
  };
705
847
 
706
- /**
707
- * Shared Animation Parameter Calculation Utility
708
- *
709
- * Calculates animation parameters from emotion curves.
710
- * Shared by calculateWordAnimation and calculateSentenceAnimation to eliminate duplication.
711
- *
712
- * This utility extracts all animation parameters defined in EMOTION_ANIMATIONS
713
- * including variation axes (YOPQ, YTAS) that are separate from voice axes (wght, wdth).
714
- *
715
- * TERMINOLOGY:
716
- * - **Voice Axes**: Font axes driven by audio analysis (volume→wght, speech_rate→wdth)
717
- * - **Variation Axes**: Font axes driven by emotion animations (YOPQ, YTAS from emotion curves)
718
- */
719
- interface VariableFontStyle {
720
- fontWeight?: number;
721
- fontStretch?: string;
722
- }
723
- interface AnimationParameters {
724
- fontSize: number;
725
- scale: number;
726
- opacity: number;
727
- slant: number;
728
- weight: number;
729
- width: number;
730
- textColor: string;
731
- translateX: number;
732
- translateY: number;
733
- stretchY: number;
734
- letterShake?: number;
735
- fontVariationAxes?: Record<string, number>;
736
- shadowColor?: string | ((t: number, intensity: number) => string);
737
- }
738
- interface EmotionCurve {
739
- fontSize?: number | ((t: number, intensity: number) => number);
740
- scale?: number | ((t: number, intensity: number) => number);
741
- opacity?: number | ((t: number, intensity: number) => number);
742
- slant?: number | ((t: number, intensity?: number) => number);
743
- weight?: number | ((t: number, intensity?: number) => number);
744
- translateX?: number | ((t: number, intensity: number) => number);
745
- translateY?: number | ((t: number, intensity: number) => number);
746
- stretchY?: number | ((t: number, intensity: number) => number);
747
- textColor?: string | ((t: number, intensity: number) => string);
748
- shadowColor?: string | ((t: number, intensity: number) => string);
749
- thinStroke?: (t: number, intensity: number, gtsValue: number) => number;
750
- ascenderHeight?: (t: number, intensity: number, gtsValue: number) => number;
751
- letterShake?: (t: number, intensity: number, gtsValue: number) => number;
752
- }
753
- /**
754
- * Calculate animation parameters from emotion curve
755
- *
756
- * @param emotionCurve - Emotion curve from EMOTION_ANIMATIONS
757
- * @param t - Normalized time (0-1) through animation
758
- * @param intensity - Emotion intensity (0-1), capped by GTS (maxExpression)
759
- * @param variableFontStyle - Font style from variable font calculations
760
- * @param gtsValue - GTS maxExpression value (0.2-1.0) for scaling ranges
761
- * @param selectedFontFamily - The selected font family (e.g., 'Cormorant', 'Roboto Flex')
762
- * @returns Complete animation parameters including fontVariationAxes (variation axes, not voice axes)
763
- */
764
- declare function calculateAnimationParameters(emotionCurve: EmotionCurve, t: number, intensity: number, variableFontStyle?: VariableFontStyle | null, gtsValue?: number, selectedFontFamily?: string): AnimationParameters;
765
-
766
848
  /**
767
849
  * Shadow Generator
768
850
  *
769
- * Generates CSS text-shadow strings from shadow colors and emotion-specific styling
851
+ * Generates CSS text-shadow strings from shadow colors
852
+ * All emotion-specific shadows are now controlled by URL animations
770
853
  */
771
854
  /**
772
855
  * Generate CSS text-shadow string from shadow color
773
856
  *
774
857
  * @param shadowColor - Shadow color in hex format (e.g., '#ff3232')
775
- * @param fontFamily - Font family to determine shadow style
776
- * @param emotion - Current emotion to determine shadow style
777
- * @param intensity - Emotion intensity (0-1) to scale glow effects
778
- * @returns CSS text-shadow value
858
+ * @param _fontFamily - Unused (kept for API compatibility)
859
+ * @param _emotion - Unused (kept for API compatibility)
860
+ * @param _intensity - Unused (kept for API compatibility)
861
+ * @returns CSS text-shadow value or empty string if no shadow
779
862
  */
780
- declare function generateTextShadow(shadowColor: string | undefined, fontFamily?: string, emotion?: string, intensity?: number): string;
863
+ declare function generateTextShadow(shadowColor: string | undefined, _fontFamily?: string, _emotion?: string, _intensity?: number): string;
781
864
 
782
865
  /**
783
866
  * Dynamic Word Spacing Calculator
@@ -796,6 +879,27 @@ declare function generateTextShadow(shadowColor: string | undefined, fontFamily?
796
879
  */
797
880
  declare function calculateDynamicWordSpacing(currentScale?: number, fontFamily?: string, gtsIntensity?: number, emotion?: string): string;
798
881
 
882
+ /**
883
+ * Prosody Weight — Natural Voice Intonation for Animations
884
+ *
885
+ * Only ~20% of words get motion animation, mimicking how natural speech
886
+ * stresses only a few key words per phrase. Font styling (color, weight,
887
+ * slant) is unaffected — this only gates movement.
888
+ *
889
+ * Selection criteria:
890
+ * 1. Function words (the, a, is, and…) → always quiet
891
+ * 2. Content words are scored by length + deterministic hash
892
+ * 3. Only the top ~35% of content words animate
893
+ * (since function/short words are ~55% of text,
894
+ * 35% of remaining 45% ≈ 16-20% of all words)
895
+ */
896
+ /**
897
+ * Compute a prosody importance weight for a single word.
898
+ *
899
+ * @returns 0 (no motion) or 1 (full motion).
900
+ */
901
+ declare function computeProsodyWeight(word: any, _emotionIntensity: number, _gts: number): number;
902
+
799
903
  /**
800
904
  * Joy Animation Effects
801
905
  *
@@ -841,6 +945,131 @@ declare function getJoyTransform(joyEffect: JoyEffect | null): string;
841
945
  */
842
946
  declare function getJoyFilter(joyEffect: JoyEffect | null): string;
843
947
 
948
+ /**
949
+ * Word Emphasis Effects
950
+ *
951
+ * Calculates emphasis effects (standard and strong) for words based on confidence levels.
952
+ *
953
+ * USED BY:
954
+ * - calculateWordAnimation: Main word animation orchestrator
955
+ *
956
+ * HOW IT WORKS:
957
+ * 1. Standard Emphasis (50-70%): Quick "pop" effect at word start
958
+ * 2. Strong Emphasis (70%+): Per-letter dramatic effects throughout word
959
+ * 3. Both scale with GTS (expressiveness level) and word confidence
960
+ *
961
+ * KEY FEATURES:
962
+ * - Confidence-based thresholds (50-70% vs 70%+)
963
+ * - GTS-scaled intensity
964
+ * - Emotion slant inheritance
965
+ * - Smooth transitions
966
+ */
967
+ interface Word {
968
+ emphasis?: number;
969
+ start: number;
970
+ end: number;
971
+ animationEnd?: number;
972
+ }
973
+ interface EmphasisEffect {
974
+ scaleMultiplier: number;
975
+ slantAdditive: number;
976
+ weightBoost: number;
977
+ scaleProgress: number;
978
+ gtsMultiplier: number;
979
+ emphasis: number;
980
+ emphasisMultiplier: number;
981
+ elapsed: number;
982
+ scaleActive: boolean;
983
+ }
984
+ interface StrongEmphasisData {
985
+ emphasis: number;
986
+ rawEmphasis: number;
987
+ scale: number;
988
+ rotation: number;
989
+ translateX: number;
990
+ translateY: number;
991
+ skewX: number;
992
+ stretchY: number;
993
+ brightness: number;
994
+ contrast: number;
995
+ shadowBlur: number;
996
+ shadowOpacity: number;
997
+ zIndex: number;
998
+ weightBoost: number;
999
+ shadowOffsetX: number;
1000
+ shadowOffsetY: number;
1001
+ gtsMultiplier: number;
1002
+ emphasisMultiplier: number;
1003
+ fadeFactor: number;
1004
+ isInTail: boolean;
1005
+ }
1006
+ /**
1007
+ * Calculate emphasis effects for a word
1008
+ *
1009
+ * @param params - Emphasis calculation parameters
1010
+ * @returns Emphasis effects { emphasisEffect, strongEmphasisData }
1011
+ */
1012
+ declare function calculateWordEmphasisEffects({ word, currentTime, maxExpression, emotionAnimationDuration, wordBaseSlant, isActive, wordEmotion, }: {
1013
+ word: Word;
1014
+ currentTime: number;
1015
+ maxExpression: number;
1016
+ emotionAnimationDuration: number;
1017
+ wordBaseSlant: number;
1018
+ isActive: boolean;
1019
+ wordEmotion?: string;
1020
+ }): {
1021
+ emphasisEffect: EmphasisEffect | null;
1022
+ strongEmphasisData: StrongEmphasisData | null;
1023
+ };
1024
+
1025
+ /**
1026
+ * ============================================
1027
+ * WORD LETTER SPACING
1028
+ * ============================================
1029
+ *
1030
+ * PURPOSE:
1031
+ * Calculates per-letter translateX offsets for GPU-accelerated spacing (no layout reflow).
1032
+ * Extracted from animationEngine for better maintainability.
1033
+ *
1034
+ * USED BY:
1035
+ * - animationEngine: Main word animation orchestrator
1036
+ *
1037
+ * HOW IT WORKS:
1038
+ * 1. Detects active effects (fear shake only - emphasis spacing is disabled)
1039
+ * 2. Calculates per-letter translateX offsets to create spacing between letters
1040
+ * 3. Returns array of translateX values in pixels (one per letter)
1041
+ *
1042
+ * KEY FEATURES:
1043
+ * - Transform-based spacing (GPU-accelerated, no layout reflow)
1044
+ * - Letter spacing disabled for emphasis effects (standard and strong)
1045
+ * - Only fear shake effects get letter spacing (if needed)
1046
+ * - Zero baseline for clean transitions
1047
+ *
1048
+ * PERFORMANCE BENEFITS:
1049
+ * - Uses translateX (compositor property) instead of letter-spacing (layout property)
1050
+ * - Smooth CSS transitions without triggering layout reflow
1051
+ * - All spacing animations run on GPU compositor layer
1052
+ */
1053
+ interface WordLetterSpacingParams {
1054
+ strongEmphasisData?: any;
1055
+ emphasisEffect?: any;
1056
+ wordLetterShakeIntensity: number | null;
1057
+ wordFontFamily: string;
1058
+ currentTime: number;
1059
+ word: any;
1060
+ emotionAnimationDuration: number;
1061
+ wordEmotion?: string;
1062
+ totalLetters: number;
1063
+ fontSize: number;
1064
+ }
1065
+ /**
1066
+ * Calculate per-letter translateX offsets for GPU-accelerated spacing
1067
+ *
1068
+ * @param params - Spacing calculation parameters
1069
+ * @returns Array of translateX offsets in pixels (one per letter)
1070
+ */
1071
+ declare function calculateWordLetterSpacing({ strongEmphasisData, emphasisEffect, wordLetterShakeIntensity, wordFontFamily, currentTime, word, emotionAnimationDuration, wordEmotion, totalLetters, fontSize, }: WordLetterSpacingParams): number[];
1072
+
844
1073
  /**
845
1074
  * GTS (Global Text Style) Calculations
846
1075
  *
@@ -871,11 +1100,16 @@ declare function calculateGTSValues(gts: number): {
871
1100
  */
872
1101
  declare function meetsEmotionThreshold(intensity: number, threshold: number): boolean;
873
1102
  /**
874
- * Calculate capped emotion intensity based on GTS maxExpression
1103
+ * Calculate scaled emotion intensity based on GTS maxExpression
1104
+ *
1105
+ * GTS acts as a scaling multiplier (final layer) to preserve variance in emotion values
1106
+ * while controlling overall expressiveness.
1107
+ *
1108
+ * When GTS=0.0 (maxExpression=0.2), animations are completely disabled.
875
1109
  *
876
1110
  * @param rawIntensity - Raw emotion intensity from backend (0-1)
877
- * @param maxExpression - GTS-derived max expression cap (0-1)
878
- * @returns Capped emotion intensity (0-1)
1111
+ * @param maxExpression - GTS-derived max expression multiplier (0.2-1.0)
1112
+ * @returns Scaled emotion intensity (0-1), or 0 if GTS=0.0
879
1113
  */
880
1114
  declare function capEmotionIntensity(rawIntensity: number, maxExpression: number): number;
881
1115
  /**
@@ -903,14 +1137,6 @@ declare function isInEmphasisRange(emphasis: number): boolean;
903
1137
  */
904
1138
  declare function isInStrongEmphasisRange(emphasis: number): boolean;
905
1139
 
906
- /**
907
- * Emotion Animation URLs
908
- *
909
- * Config mapping emotion → animation URL
910
- * Replaces hardcoded EMOTION_ANIMATIONS config with URL-based parameters
911
- */
912
- declare const EMOTION_ANIMATION_URLS: Record<string, string>;
913
-
914
1140
  /**
915
1141
  * Font Selection Utilities
916
1142
  *
@@ -985,129 +1211,22 @@ interface Letter {
985
1211
  declare function splitTextIntoLetters(text: string): Letter[];
986
1212
 
987
1213
  /**
988
- * Word Emphasis Effects
989
- *
990
- * Calculates emphasis effects (standard and strong) for words based on confidence levels.
991
- *
992
- * USED BY:
993
- * - calculateWordAnimation: Main word animation orchestrator
994
- *
995
- * HOW IT WORKS:
996
- * 1. Standard Emphasis (50-70%): Quick "pop" effect at word start
997
- * 2. Strong Emphasis (70%+): Per-letter dramatic effects throughout word
998
- * 3. Both scale with GTS (expressiveness level) and word confidence
999
- *
1000
- * KEY FEATURES:
1001
- * - Confidence-based thresholds (50-70% vs 70%+)
1002
- * - GTS-scaled intensity
1003
- * - Emotion slant inheritance
1004
- * - Smooth transitions
1005
- */
1006
- interface Word {
1007
- emphasis?: number;
1008
- start: number;
1009
- end: number;
1010
- animationEnd?: number;
1011
- }
1012
- interface EmphasisEffect {
1013
- scaleMultiplier: number;
1014
- slantAdditive: number;
1015
- weightBoost: number;
1016
- scaleProgress: number;
1017
- gtsMultiplier: number;
1018
- emphasis: number;
1019
- emphasisMultiplier: number;
1020
- elapsed: number;
1021
- scaleActive: boolean;
1022
- }
1023
- interface StrongEmphasisData {
1024
- emphasis: number;
1025
- rawEmphasis: number;
1026
- scale: number;
1027
- rotation: number;
1028
- translateX: number;
1029
- translateY: number;
1030
- skewX: number;
1031
- stretchY: number;
1032
- brightness: number;
1033
- contrast: number;
1034
- shadowBlur: number;
1035
- shadowOpacity: number;
1036
- zIndex: number;
1037
- weightBoost: number;
1038
- shadowOffsetX: number;
1039
- shadowOffsetY: number;
1040
- gtsMultiplier: number;
1041
- emphasisMultiplier: number;
1042
- fadeFactor: number;
1043
- isInTail: boolean;
1044
- }
1045
- /**
1046
- * Calculate emphasis effects for a word
1214
+ * Emotion Importance Processing
1047
1215
  *
1048
- * @param params - Emphasis calculation parameters
1049
- * @returns Emphasis effects { emphasisEffect, strongEmphasisData }
1216
+ * Core emotions (anger, fear, sadness, joy) are prioritized over secondary emotions
1217
+ * by multiplying their intensity by 1.5 before selection.
1218
+ * Identical to monorepo app/utils/data/emotionImportance.js
1050
1219
  */
1051
- declare function calculateWordEmphasisEffects({ word, currentTime, maxExpression, emotionAnimationDuration, wordBaseSlant, isActive, wordEmotion, }: {
1052
- word: Word;
1053
- currentTime: number;
1054
- maxExpression: number;
1055
- emotionAnimationDuration: number;
1056
- wordBaseSlant: number;
1057
- isActive: boolean;
1058
- wordEmotion?: string;
1059
- }): {
1060
- emphasisEffect: EmphasisEffect | null;
1061
- strongEmphasisData: StrongEmphasisData | null;
1062
- };
1063
-
1064
1220
  /**
1065
- * ============================================
1066
- * WORD LETTER SPACING
1067
- * ============================================
1068
- *
1069
- * PURPOSE:
1070
- * Calculates per-letter translateX offsets for GPU-accelerated spacing (no layout reflow).
1071
- * Extracted from animationEngine for better maintainability.
1072
- *
1073
- * USED BY:
1074
- * - animationEngine: Main word animation orchestrator
1075
- *
1076
- * HOW IT WORKS:
1077
- * 1. Detects active effects (fear shake only - emphasis spacing is disabled)
1078
- * 2. Calculates per-letter translateX offsets to create spacing between letters
1079
- * 3. Returns array of translateX values in pixels (one per letter)
1080
- *
1081
- * KEY FEATURES:
1082
- * - Transform-based spacing (GPU-accelerated, no layout reflow)
1083
- * - Letter spacing disabled for emphasis effects (standard and strong)
1084
- * - Only fear shake effects get letter spacing (if needed)
1085
- * - Zero baseline for clean transitions
1221
+ * Process emotions with importance factors
1086
1222
  *
1087
- * PERFORMANCE BENEFITS:
1088
- * - Uses translateX (compositor property) instead of letter-spacing (layout property)
1089
- * - Smooth CSS transitions without triggering layout reflow
1090
- * - All spacing animations run on GPU compositor layer
1091
- */
1092
- interface WordLetterSpacingParams {
1093
- strongEmphasisData?: any;
1094
- emphasisEffect?: any;
1095
- wordLetterShakeIntensity: number | null;
1096
- wordFontFamily: string;
1097
- currentTime: number;
1098
- word: any;
1099
- emotionAnimationDuration: number;
1100
- wordEmotion?: string;
1101
- totalLetters: number;
1102
- fontSize: number;
1103
- }
1104
- /**
1105
- * Calculate per-letter translateX offsets for GPU-accelerated spacing
1223
+ * Core emotions (anger, fear, sadness, joy) get ×1.5 multiplier
1224
+ * Secondary emotions get ×1.0 multiplier
1106
1225
  *
1107
- * @param params - Spacing calculation parameters
1108
- * @returns Array of translateX offsets in pixels (one per letter)
1226
+ * @param emotions - Array of [emotion, intensity] tuples
1227
+ * @returns Array of [emotion, originalIntensity, adjustedIntensity, importanceFactor, isCore] tuples
1109
1228
  */
1110
- declare function calculateWordLetterSpacing({ strongEmphasisData, emphasisEffect, wordLetterShakeIntensity, wordFontFamily, currentTime, word, emotionAnimationDuration, wordEmotion, totalLetters, fontSize, }: WordLetterSpacingParams): number[];
1229
+ declare function processEmotionsWithImportance(emotions: Array<[string, number]>): Array<[string, number, number, number, boolean]>;
1111
1230
 
1112
1231
  /**
1113
1232
  * Backend Data Accessors
@@ -1117,6 +1236,21 @@ declare function calculateWordLetterSpacing({ strongEmphasisData, emphasisEffect
1117
1236
  * Identical to monorepo app/utils/data/backendDataAccessors.js
1118
1237
  */
1119
1238
 
1239
+ /**
1240
+ * Get word emphasis data
1241
+ */
1242
+ declare function getWordEmphasis(word: any): {
1243
+ confidence: any;
1244
+ emphasis: any;
1245
+ hasEmphasis: boolean;
1246
+ hasStrongEmphasis: boolean;
1247
+ };
1248
+ /**
1249
+ * Get subtitle text content
1250
+ *
1251
+ * Handles both 'subtitle' and 'text' properties
1252
+ */
1253
+ declare function getSubtitleText(subtitle: SubtitleSegment | null): string;
1120
1254
  /**
1121
1255
  * Get subtitle words array
1122
1256
  */
@@ -1140,24 +1274,6 @@ declare function getMergedSubtitles(subtitle: SubtitleSegment | null): SubtitleS
1140
1274
  */
1141
1275
  declare function findSubtitleForWord(subtitles: SubtitleSegment[], word: any): SubtitleSegment | null;
1142
1276
 
1143
- /**
1144
- * Emotion Importance Processing
1145
- *
1146
- * Core emotions (anger, fear, sadness, joy) are prioritized over secondary emotions
1147
- * by multiplying their intensity by 1.5 before selection.
1148
- * Identical to monorepo app/utils/data/emotionImportance.js
1149
- */
1150
- /**
1151
- * Process emotions with importance factors
1152
- *
1153
- * Core emotions (anger, fear, sadness, joy) get ×1.5 multiplier
1154
- * Secondary emotions get ×1.0 multiplier
1155
- *
1156
- * @param emotions - Array of [emotion, intensity] tuples
1157
- * @returns Array of [emotion, originalIntensity, adjustedIntensity, importanceFactor, isCore] tuples
1158
- */
1159
- declare function processEmotionsWithImportance(emotions: Array<[string, number]>): Array<[string, number, number, number, boolean]>;
1160
-
1161
1277
  /**
1162
1278
  * Variable Font Calculations
1163
1279
  *
@@ -1204,34 +1320,8 @@ declare function calculateWeightFromVolume(volume: number | undefined, weightAxi
1204
1320
  */
1205
1321
  declare function calculateWidthFromSpeechRate(speechRate: number | undefined, widthAxis: FontAxisConfig | undefined, baseWidth?: number): number;
1206
1322
 
1207
- /**
1208
- * Subtitle Engine
1209
- *
1210
- * TODO: Extract from app/hooks/subtitle/useSentenceAnimation.js and useWordAnimation.js
1211
- *
1212
- * This module should provide:
1213
- * - createSubtitleEngine(track) - creates engine instance
1214
- * - engine.at(time) - returns SubtitleEngineState for given time
1215
- * - Handle karaoke mode (word-by-word) and sentence mode
1216
- * - Handle edge cases: gaps, overlaps, end-of-video
1217
- */
1218
-
1219
- declare function createSubtitleEngine(track: SubtitleTrack): {
1220
- at(time: number): SubtitleEngineState;
1221
- };
1222
-
1223
- /**
1224
- * Emotion → Style Mapper
1225
- *
1226
- * TODO: Extract from app/config/animation/ directory
1227
- *
1228
- * This module should provide:
1229
- * - getEmotionStyle(emotion, intensity) - maps emotion to CSS styles
1230
- * - Handle all 6 emotions: joy, anger, sadness, fear, disgust, surprise
1231
- * - Support intensity scaling (0-1)
1232
- */
1233
-
1234
- declare function getEmotionStyle(emotion: Emotion, intensity: number): EmotionStyle;
1323
+ declare function ensureFont(fontFamily: string | undefined | null): void;
1324
+ declare function preloadAnimationFonts(): void;
1235
1325
 
1236
1326
  /**
1237
1327
  * PHONT API Client
@@ -1287,7 +1377,11 @@ declare class PhontClient {
1287
1377
  /**
1288
1378
  * Register a new user
1289
1379
  */
1290
- register(username: string, email: string, password: string): Promise<RegisterResponse>;
1380
+ register(username: string, email: string, password: string, profile: {
1381
+ company: string;
1382
+ first_name: string;
1383
+ last_name: string;
1384
+ }): Promise<RegisterResponse>;
1291
1385
  /**
1292
1386
  * Get subtitle track for a VOD
1293
1387
  * Requires: Session token authentication
@@ -1343,4 +1437,4 @@ declare class PhontClient {
1343
1437
  clearCredentials(): void;
1344
1438
  }
1345
1439
 
1346
- export { ANIMATION_STYLING, type AnimationOptions, type AnimationParameterStates, type AnimationParameters, type AnimationState, type CurvePoint, EMOTION_ANIMATIONS, EMOTION_ANIMATION_URLS, type Emotion, type EmotionCurve, type EmotionSelectionResult, type EmotionStyle, type EmphasisEffect, type FontAxisConfig, type FontConfig, type JoyEffect, type Letter, type LoginResponse, type ParameterState, type ParameterStates, PhontClient, type PhontClientOptions, RENDERING_CONTROL, type RegisterResponse, type SentenceAnimationState, type StateCallback, type StrongEmphasisData, type Stylesheet, type SubtitleEngineState, type SubtitleLine, SubtitleManager, type SubtitleSegment, type SubtitleState$1 as SubtitleState, SubtitleStateManager, type SubtitleTrack, type SubtitleWord, type VariableFontStyle, type VodMetadata, type VodState$1 as VodState, type Word, type WordAnimationState, type WordLetterSpacingParams, calculateAnimationParameters, calculateAnimationState, calculateDynamicWordSpacing, calculateEmphasisMultiplier, calculateGTSValues, calculateJoy, calculateJoyBulge, calculateNormalizedTime, calculateSentenceAnimation, calculateWeightFromVolume, calculateWidthFromSpeechRate, calculateWordAnimation, calculateWordEmphasisEffects, calculateWordLetterSpacing, capEmotionIntensity, createSubtitleEngine, findSubtitleForWord, generateTextShadow, getEmotionStyle, getFontFamilyCSS, getJoyAnimationMode, getJoyFilter, getJoyTransform, getMergedSubtitles, getSubtitleAnimations, getSubtitleText, getSubtitleTiming, getSubtitleWords, hasMergedSubtitles, isInEmphasisRange, isInStrongEmphasisRange, meetsEmotionThreshold, processEmotionsWithImportance, selectEmotion, selectFontFamily, shouldUseAngryFont, shouldUseJoyFont, shouldUseSadnessFont, splitTextIntoLetters, subtitleManager };
1440
+ export { ANIMATION_STYLING, ANIMATION_URLS, type AnimationFetcher, type AnimationOptions, type AnimationParameterState, type AnimationParameterStates, type AnimationRecord, type AnimationState, type CurvePoint, EMOTION_ANIMATION_URLS, type Emotion, type EmotionSelectionResult, type EmotionStyle, type EmphasisEffect, type FontAxisConfig, type FontConfig, type JoyEffect, type Letter, type LoginResponse, type ParameterState, type ParameterStates, PhontClient, type PhontClientOptions, type PublishedAnimationResolver, REFERENCE_GTS, REFERENCE_INTENSITY, RENDERING_CONTROL, type RegisterResponse, type SentenceAnimationState, type StateCallback, type StrongEmphasisData, type Stylesheet, type SubtitleEngineState, type SubtitleLine, SubtitleManager, type SubtitleSegment, type SubtitleState$1 as SubtitleState, SubtitleStateManager, type SubtitleTrack, type SubtitleWord, type VodMetadata, type VodState$1 as VodState, type Word, type WordAnimationState, type WordLetterSpacingParams, calculateAnimationParameters, calculateAnimationState, calculateDynamicWordSpacing, calculateEmphasisMultiplier, calculateGTSValues, calculateJoy, calculateJoyBulge, calculateNormalizedTime, calculateWeightFromVolume, calculateWidthFromSpeechRate, calculateWordEmphasisEffects, calculateWordLetterSpacing, capEmotionIntensity, computeProsodyWeight, createPublishedAnimationResolver, decodeAnimationUrl, ensureFont, findSubtitleForWord, generateTextShadow, getAnimationUrlForEmotion, getFontFamilyCSS, getJoyAnimationMode, getJoyFilter, getJoyTransform, getMergedSubtitles, getSubtitleAnimations, getSubtitleText, getSubtitleTiming, getSubtitleWords, getWordEmphasis, hasMergedSubtitles, hockeyStickIntensity, isInEmphasisRange, isInStrongEmphasisRange, meetsEmotionThreshold, preloadAnimationFonts, processEmotionsWithImportance, sampleParameterCurve, selectEmotion, selectFontFamily, shouldUseAngryFont, shouldUseJoyFont, shouldUseSadnessFont, splitTextIntoLetters, subtitleManager };