@phont-ai/subtitles-core 0.1.10
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/client/PhontClient.d.ts +16 -0
- package/dist/index.d.mts +1346 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +5414 -0
- package/dist/index.mjs +5347 -0
- package/dist/types/registration.d.ts +46 -0
- package/dist/utils/video-handling.d.ts +33 -0
- package/dist/validation/registration.d.ts +64 -0
- package/package.json +37 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,1346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types for PHONT expressive subtitles
|
|
3
|
+
* Framework-agnostic, pure TypeScript
|
|
4
|
+
*/
|
|
5
|
+
type Emotion = "joy" | "anger" | "sadness" | "fear" | "disgust" | "surprise" | "none";
|
|
6
|
+
interface SubtitleWord {
|
|
7
|
+
text: string;
|
|
8
|
+
start: number;
|
|
9
|
+
end: number;
|
|
10
|
+
emotion?: Emotion;
|
|
11
|
+
emphasis?: number;
|
|
12
|
+
}
|
|
13
|
+
interface SubtitleLine {
|
|
14
|
+
speaker?: string;
|
|
15
|
+
start: number;
|
|
16
|
+
end: number;
|
|
17
|
+
words: SubtitleWord[];
|
|
18
|
+
emotion?: Emotion;
|
|
19
|
+
emotion_intensity?: number;
|
|
20
|
+
}
|
|
21
|
+
interface SubtitleTrack {
|
|
22
|
+
vodId: string;
|
|
23
|
+
language: string;
|
|
24
|
+
lines: SubtitleLine[];
|
|
25
|
+
}
|
|
26
|
+
interface EmotionStyle {
|
|
27
|
+
fontWeight?: number;
|
|
28
|
+
skew?: number;
|
|
29
|
+
jitter?: number;
|
|
30
|
+
color?: string;
|
|
31
|
+
glow?: boolean;
|
|
32
|
+
scale?: number;
|
|
33
|
+
}
|
|
34
|
+
interface SubtitleEngineState {
|
|
35
|
+
activeLine: SubtitleLine | null;
|
|
36
|
+
activeWords: SubtitleWord[];
|
|
37
|
+
currentWordIndex: number;
|
|
38
|
+
emotion: Emotion;
|
|
39
|
+
emotionIntensity: number;
|
|
40
|
+
}
|
|
41
|
+
interface PhontClientOptions {
|
|
42
|
+
apiKey?: string;
|
|
43
|
+
authToken?: string;
|
|
44
|
+
sessionId?: string;
|
|
45
|
+
apiBaseUrl?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* ============================================
|
|
50
|
+
* SUBTITLE STATE MANAGER
|
|
51
|
+
* ============================================
|
|
52
|
+
* Ported from app/components/subtitle/state/SubtitleStateManager.js
|
|
53
|
+
*/
|
|
54
|
+
interface SubtitleState$1 {
|
|
55
|
+
videoTimeSeed: number | null;
|
|
56
|
+
isVisible: boolean;
|
|
57
|
+
isKaraokeMode: boolean;
|
|
58
|
+
isSpeaker: boolean;
|
|
59
|
+
animationMode: "Sentence" | "Word";
|
|
60
|
+
currentSubtitle: string;
|
|
61
|
+
currentSequence: any | null;
|
|
62
|
+
subtitles: any[];
|
|
63
|
+
currentSubtitleData: any | null;
|
|
64
|
+
lastEndTime: number;
|
|
65
|
+
processedSequences: Set<number>;
|
|
66
|
+
initialSequenceOffset: number | null;
|
|
67
|
+
segmentDurations: Map<number, number>;
|
|
68
|
+
soundByteAll: any[];
|
|
69
|
+
soundByteImportant: any[];
|
|
70
|
+
soundByteFiltered: any[];
|
|
71
|
+
showAllSoundbites: boolean;
|
|
72
|
+
showImportantSoundbites: boolean;
|
|
73
|
+
currentTime: number;
|
|
74
|
+
liveStartTime: number | null;
|
|
75
|
+
liveCurrentTime: number;
|
|
76
|
+
soundbiteAnimations: any[];
|
|
77
|
+
showSoundbiteAnimations: boolean;
|
|
78
|
+
isClosedCaptionsEnabled: boolean;
|
|
79
|
+
}
|
|
80
|
+
interface VodState$1 {
|
|
81
|
+
subtitles: any[] | null;
|
|
82
|
+
soundByteAll: any[];
|
|
83
|
+
soundByteImportant: any[];
|
|
84
|
+
soundByteFiltered: any[];
|
|
85
|
+
currentLanguage: string | null;
|
|
86
|
+
videoId: string | null;
|
|
87
|
+
}
|
|
88
|
+
type StateCallback = (state: SubtitleState$1) => void;
|
|
89
|
+
declare class SubtitleStateManager {
|
|
90
|
+
subscribers: Set<StateCallback>;
|
|
91
|
+
state: SubtitleState$1;
|
|
92
|
+
vodState: VodState$1;
|
|
93
|
+
constructor();
|
|
94
|
+
/**
|
|
95
|
+
* Subscribe to state changes
|
|
96
|
+
*/
|
|
97
|
+
subscribe(callback: StateCallback): () => void;
|
|
98
|
+
/**
|
|
99
|
+
* Notify all subscribers of state changes
|
|
100
|
+
*/
|
|
101
|
+
notify(): void;
|
|
102
|
+
/**
|
|
103
|
+
* Get current state (immutable copy)
|
|
104
|
+
*/
|
|
105
|
+
getState(): SubtitleState$1;
|
|
106
|
+
/**
|
|
107
|
+
* Get VOD state (immutable copy)
|
|
108
|
+
*/
|
|
109
|
+
getVodState(): VodState$1;
|
|
110
|
+
toggleSubtitles(isVisible: boolean): void;
|
|
111
|
+
toggleClosedCaptions(isEnabled: boolean): void;
|
|
112
|
+
toggleKaraoke(isKaraokeMode: boolean): void;
|
|
113
|
+
toggleSpeaker(isSpeaker: boolean): void;
|
|
114
|
+
toggleSoundbites(type: "all" | "important", isVisible: boolean): void;
|
|
115
|
+
toggleSoundbiteAnimations(isVisible: boolean): void;
|
|
116
|
+
setAnimationMode(mode: "Sentence" | "Word"): void;
|
|
117
|
+
updateSubtitle(text: string): void;
|
|
118
|
+
updateCurrentTime(time: number): void;
|
|
119
|
+
updateSubtitles(subtitles: any[]): void;
|
|
120
|
+
updateCurrentSubtitleData(data: any): void;
|
|
121
|
+
updateSoundbites(all?: any[], important?: any[], filtered?: any[]): void;
|
|
122
|
+
updateSoundbiteAnimations(animations: any[]): void;
|
|
123
|
+
updateVodSubtitles(subtitles: any[]): void;
|
|
124
|
+
updateVodLanguage(language: string | null): void;
|
|
125
|
+
updateVodVideoId(videoId: string | null): void;
|
|
126
|
+
updateVodSoundbites(all?: any[], important?: any[], filtered?: any[]): void;
|
|
127
|
+
updateLiveStartTime(time: number | null): void;
|
|
128
|
+
updateLiveCurrentTime(time: number): void;
|
|
129
|
+
updateVideoTimeSeed(seed: number | null): void;
|
|
130
|
+
markSequenceProcessed(sequenceNumber: number): void;
|
|
131
|
+
isSequenceProcessed(sequenceNumber: number): boolean;
|
|
132
|
+
setInitialSequenceOffset(offset: number): void;
|
|
133
|
+
setSegmentDuration(sequenceNumber: number, duration: number): void;
|
|
134
|
+
getSegmentDuration(sequenceNumber: number): number | undefined;
|
|
135
|
+
updateCurrentSequence(sequence: any): void;
|
|
136
|
+
reset(): void;
|
|
137
|
+
resetControls(): void;
|
|
138
|
+
clearLiveState(): void;
|
|
139
|
+
clearVodState(): void;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* ============================================
|
|
144
|
+
* SUBTITLE MANAGER (Orchestrator)
|
|
145
|
+
* ============================================
|
|
146
|
+
*
|
|
147
|
+
* PURPOSE:
|
|
148
|
+
* Central coordinator for subtitle system. Delegates to specialized classes.
|
|
149
|
+
*
|
|
150
|
+
* USED BY:
|
|
151
|
+
* - PhontSubtitles.jsx: Gets subtitle state and data
|
|
152
|
+
* - Player components: Controls playback and timing
|
|
153
|
+
* - PhontControls.jsx: UI toggles and settings
|
|
154
|
+
*
|
|
155
|
+
* DELEGATES TO:
|
|
156
|
+
* - SubtitleStateManager: State management and subscriptions
|
|
157
|
+
* - SubtitleCache: Language caching and detection
|
|
158
|
+
* - SubtitleFetcher: API requests & data normalization
|
|
159
|
+
* - SoundbiteProcessor: Soundbite/animation processing & laughter merging
|
|
160
|
+
* - VodDataProcessor: VOD data processing, deduplication, soundbite coordination
|
|
161
|
+
* - LiveDataProcessor: LIVE data processing, timing offsets, soundbite coordination
|
|
162
|
+
* - LiveStreamCumulativeTimeGenerator: Generates cumulative time for LIVE streams
|
|
163
|
+
* - CurrentSubtitle: Gets subtitle for time (BOTH VOD & LIVE) + karaoke
|
|
164
|
+
*
|
|
165
|
+
* STATUS: Phase 2 Complete - All 8 classes extracted, clean architecture, no duplication
|
|
166
|
+
*/
|
|
167
|
+
type AnimationMode = "Sentence" | "Word" | string;
|
|
168
|
+
interface SubtitleState {
|
|
169
|
+
isVisible: boolean;
|
|
170
|
+
isKaraokeMode: boolean;
|
|
171
|
+
isSpeaker: boolean;
|
|
172
|
+
animationMode: AnimationMode;
|
|
173
|
+
currentSubtitle: string;
|
|
174
|
+
currentSequence: number | null;
|
|
175
|
+
subtitles: any[];
|
|
176
|
+
currentSubtitleData: any | null;
|
|
177
|
+
videoTimeSeed: number | null;
|
|
178
|
+
currentTime: number;
|
|
179
|
+
liveStartTime: number | null;
|
|
180
|
+
liveCurrentTime: number;
|
|
181
|
+
lastEndTime: number;
|
|
182
|
+
processedSequences: Set<number>;
|
|
183
|
+
initialSequenceOffset: number | null;
|
|
184
|
+
segmentDurations: Map<number, number>;
|
|
185
|
+
soundByteAll: any[];
|
|
186
|
+
soundByteImportant: any[];
|
|
187
|
+
soundByteFiltered: any[];
|
|
188
|
+
showAllSoundbites: boolean;
|
|
189
|
+
showImportantSoundbites: boolean;
|
|
190
|
+
soundbiteAnimations: any[];
|
|
191
|
+
showSoundbiteAnimations: boolean;
|
|
192
|
+
isClosedCaptionsEnabled: boolean;
|
|
193
|
+
isBackgroundEffectEnabled: boolean;
|
|
194
|
+
backgroundEffect: string;
|
|
195
|
+
backgroundOpacity: number;
|
|
196
|
+
transition: boolean;
|
|
197
|
+
[key: string]: any;
|
|
198
|
+
}
|
|
199
|
+
interface VodState {
|
|
200
|
+
subtitles: any[] | null;
|
|
201
|
+
url: string | null;
|
|
202
|
+
currentSubtitle: string;
|
|
203
|
+
currentSubtitleData: any | null;
|
|
204
|
+
currentSequence: number | null;
|
|
205
|
+
soundByteAll: any[];
|
|
206
|
+
soundByteImportant: any[];
|
|
207
|
+
soundByteFiltered: any[];
|
|
208
|
+
currentLanguage?: string | null;
|
|
209
|
+
videoId?: string | null;
|
|
210
|
+
translation_provider?: string | null;
|
|
211
|
+
translation_model?: string | null;
|
|
212
|
+
}
|
|
213
|
+
type SubtitleSubscriber = (state: SubtitleState) => void;
|
|
214
|
+
declare class SubtitleManager {
|
|
215
|
+
private stateManager;
|
|
216
|
+
private cache;
|
|
217
|
+
private fetcher;
|
|
218
|
+
private soundbiteProcessor;
|
|
219
|
+
private vodDataProcessor;
|
|
220
|
+
private liveTimeGenerator;
|
|
221
|
+
private liveDataProcessor;
|
|
222
|
+
private currentSubtitle;
|
|
223
|
+
constructor();
|
|
224
|
+
/**
|
|
225
|
+
* Set PhontClient for authenticated API requests
|
|
226
|
+
* This will be passed to SubtitleFetcher for use in API calls
|
|
227
|
+
*/
|
|
228
|
+
setPhontClient(phontClient: any): void;
|
|
229
|
+
get state(): SubtitleState;
|
|
230
|
+
set state(value: SubtitleState);
|
|
231
|
+
get vodState(): VodState;
|
|
232
|
+
set vodState(value: VodState);
|
|
233
|
+
get subscribers(): Set<SubtitleSubscriber>;
|
|
234
|
+
subscribe(callback: SubtitleSubscriber): () => void;
|
|
235
|
+
notify(): void;
|
|
236
|
+
toggleSubtitles(isVisible: boolean): void;
|
|
237
|
+
toggleClosedCaptions(isEnabled: boolean): void;
|
|
238
|
+
toggleKaraoke(isKaraokeMode: boolean): void;
|
|
239
|
+
toggleSpeaker(isSpeaker: boolean): void;
|
|
240
|
+
toggleBackgroundEffect(isEnabled: boolean, effect?: string): void;
|
|
241
|
+
toggleSoundbites(type: "all" | "important", isVisible: boolean): void;
|
|
242
|
+
toggleSoundbiteAnimations(isVisible: boolean): void;
|
|
243
|
+
mapEventLabelToAnimation(eventLabel: string): string | null;
|
|
244
|
+
processSoundbiteAnimations(soundbites: any[]): any[];
|
|
245
|
+
setAnimationMode(mode: AnimationMode): void;
|
|
246
|
+
toggleTransition(enabled: boolean): void;
|
|
247
|
+
updateSubtitle(text: string): void;
|
|
248
|
+
updateLiveTime(videoTime?: number | null): number;
|
|
249
|
+
startLiveTiming(): void;
|
|
250
|
+
stopLiveTiming(): void;
|
|
251
|
+
pauseLiveTiming(): void;
|
|
252
|
+
resumeLiveTiming(): void;
|
|
253
|
+
resetLiveStream(videoElement: HTMLVideoElement): void;
|
|
254
|
+
getLiveTime(): number;
|
|
255
|
+
getState(): SubtitleState;
|
|
256
|
+
reset(): void;
|
|
257
|
+
resetControls(): void;
|
|
258
|
+
getCumulativeDuration(upToSequenceNumber: number): number;
|
|
259
|
+
normalizeSubtitles(data: any): any;
|
|
260
|
+
normalizeSoundbites(arr: any[]): any[];
|
|
261
|
+
getAudioSegmentDuration(sequenceNumber: number): Promise<number>;
|
|
262
|
+
getInitialLiveSequenceNumber(): Promise<number>;
|
|
263
|
+
fetchSubtitles(sequenceNumber: number): Promise<any | null>;
|
|
264
|
+
loadVodSubtitles(urlOrVodId: string, languageCode?: string | null): Promise<void>;
|
|
265
|
+
_processVodData(data: any, url: string, languageCode: string | null): void;
|
|
266
|
+
getSubtitleForTime(time: number): any;
|
|
267
|
+
getLiveSubtitleForTime(): any;
|
|
268
|
+
getCurrentSubtitleData(): any | null;
|
|
269
|
+
updateBackgroundOpacity(opacity: number): void;
|
|
270
|
+
clearOldSubtitles(currentTime: number, bufferSeconds?: number): void;
|
|
271
|
+
getQueueStatus(): {
|
|
272
|
+
totalSubtitles: number;
|
|
273
|
+
lastEndTime: number;
|
|
274
|
+
processedSequences: number[];
|
|
275
|
+
currentSequence: number | null;
|
|
276
|
+
};
|
|
277
|
+
setCurrentTime(time: number): void;
|
|
278
|
+
getActiveSoundbites(isVodMode?: boolean, vodTime?: number | null): any[];
|
|
279
|
+
getAllSoundbiteData(isVodMode?: boolean): any;
|
|
280
|
+
getActiveSoundbiteAnimations(isVodMode?: boolean): any[];
|
|
281
|
+
hasActiveAnimations(): boolean;
|
|
282
|
+
clearSoundbiteAnimations(): void;
|
|
283
|
+
clearOldAnimations(currentTime: number, bufferSeconds?: number): void;
|
|
284
|
+
getCurrentSpeaker(isVodMode?: boolean, vodTime?: number | null): string | null;
|
|
285
|
+
fetchSubtitleData(url: string, languageCode?: string | null, model?: string | null): Promise<void>;
|
|
286
|
+
switchSubtitleLanguage(languageCode: string | null, videoId: string, model?: string | null): Promise<void>;
|
|
287
|
+
_loadCachedSubtitles(data: any, url: string, languageCode: string | null): void;
|
|
288
|
+
getCurrentSubtitleLanguage(): string | null;
|
|
289
|
+
clearSubtitleCache(): void;
|
|
290
|
+
clearAudioPlaylistCache(): void;
|
|
291
|
+
updateState(): void;
|
|
292
|
+
}
|
|
293
|
+
declare const subtitleManager: SubtitleManager;
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Animation Types
|
|
297
|
+
*
|
|
298
|
+
* Type definitions for animation parameter states, curves, and animation state
|
|
299
|
+
*/
|
|
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;
|
|
318
|
+
scale: number;
|
|
319
|
+
opacity: number;
|
|
320
|
+
slant: number;
|
|
321
|
+
weight: number;
|
|
322
|
+
width: number;
|
|
323
|
+
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 {
|
|
335
|
+
text: string;
|
|
336
|
+
emotion: string;
|
|
337
|
+
emotionIntensity: number;
|
|
338
|
+
fontFamily: string;
|
|
339
|
+
startTime: number;
|
|
340
|
+
endTime: number;
|
|
341
|
+
duration: number;
|
|
342
|
+
isActive: boolean;
|
|
343
|
+
}
|
|
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;
|
|
364
|
+
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[];
|
|
386
|
+
}
|
|
387
|
+
interface AnimationOptions {
|
|
388
|
+
maxExpression?: number;
|
|
389
|
+
threshold?: number;
|
|
390
|
+
isRTL?: boolean;
|
|
391
|
+
volume?: number;
|
|
392
|
+
speechRate?: number;
|
|
393
|
+
nextSegmentStartTime?: number;
|
|
394
|
+
extendedEndTime?: number;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Emotion Selector
|
|
399
|
+
*
|
|
400
|
+
* Pure function version of useEmotionSelector (no React)
|
|
401
|
+
* Selects the highest-value emotion from backend animations object
|
|
402
|
+
* Core emotions (anger, fear, sadness, joy) receive ×1.5 importance multiplier
|
|
403
|
+
*/
|
|
404
|
+
interface EmotionSelectionResult {
|
|
405
|
+
emotion: string;
|
|
406
|
+
intensity: number;
|
|
407
|
+
allEmotions: Array<[string, number, number, number, boolean]>;
|
|
408
|
+
importanceFactor: number;
|
|
409
|
+
isCore: boolean;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Find the highest emotion value from animations object
|
|
413
|
+
*
|
|
414
|
+
* Core emotions (anger, fear, sadness, joy, disgust) are multiplied by 1.5 before selection
|
|
415
|
+
* to prioritize fundamental emotions over secondary ones.
|
|
416
|
+
*
|
|
417
|
+
* @param animationsObject - Object with emotion keys and values (0-1)
|
|
418
|
+
* @param threshold - Minimum value to consider (GTS-controlled: 0.7 at GTS=0, 0.2 at GTS=1)
|
|
419
|
+
* @returns Emotion selection result
|
|
420
|
+
*/
|
|
421
|
+
declare function selectEmotion(animationsObject: Record<string, number> | null | undefined, threshold?: number): EmotionSelectionResult;
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Animation Engine
|
|
425
|
+
*
|
|
426
|
+
* Pure functions that calculate animation state from emotion curves
|
|
427
|
+
* Uses function-based EMOTION_ANIMATIONS (identical to monorepo)
|
|
428
|
+
*/
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Calculate sentence animation state
|
|
432
|
+
*
|
|
433
|
+
* Pure function version of useSentenceAnimation - uses function-based EMOTION_ANIMATIONS (identical to monorepo)
|
|
434
|
+
*/
|
|
435
|
+
declare function calculateSentenceAnimation(segment: SubtitleSegment | null, currentTime: number, options?: AnimationOptions): SentenceAnimationState;
|
|
436
|
+
/**
|
|
437
|
+
* Calculate word animation state
|
|
438
|
+
*
|
|
439
|
+
* Pure function version of useWordAnimation - uses function-based EMOTION_ANIMATIONS (identical to monorepo)
|
|
440
|
+
*/
|
|
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
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Animation Defaults - Visual Styling Layer
|
|
506
|
+
*
|
|
507
|
+
* All subtitle animation VISUAL defaults in one place
|
|
508
|
+
* This is where you edit colors, shadows, font names, and CSS values
|
|
509
|
+
*
|
|
510
|
+
* 🎯 HOW TO CONFIGURE:
|
|
511
|
+
* - Change default font size: Edit ANIMATION_STYLING.fontSize
|
|
512
|
+
* - Change default colors/shadows: Edit ANIMATION_STYLING.textColor, shadow, etc.
|
|
513
|
+
*
|
|
514
|
+
* 🔧 FOR BEHAVIOR/TIMING:
|
|
515
|
+
* - Change when Rakkas (angry) font appears: Edit RENDERING_CONTROL.emotion.angryFontThreshold
|
|
516
|
+
* - Change effect timing/intensity: Edit renderingControl.ts
|
|
517
|
+
*/
|
|
518
|
+
declare const ANIMATION_STYLING: {
|
|
519
|
+
fontSize: number;
|
|
520
|
+
opacity: number;
|
|
521
|
+
weight: number;
|
|
522
|
+
slant: number;
|
|
523
|
+
textColor: string;
|
|
524
|
+
translateX: number;
|
|
525
|
+
translateY: number;
|
|
526
|
+
defaultFont: string;
|
|
527
|
+
angryFont: string;
|
|
528
|
+
joyFont: string;
|
|
529
|
+
sadnessFont: string;
|
|
530
|
+
shadow: {
|
|
531
|
+
offsetX: number;
|
|
532
|
+
offsetY: number;
|
|
533
|
+
blur: number;
|
|
534
|
+
color: string;
|
|
535
|
+
};
|
|
536
|
+
angryFontStyle: {
|
|
537
|
+
color: string;
|
|
538
|
+
strokeColor: string;
|
|
539
|
+
strokeWidth: number;
|
|
540
|
+
shadowOffsetX: number;
|
|
541
|
+
shadowOffsetY: number;
|
|
542
|
+
shadowBlur: number;
|
|
543
|
+
shadowBlurMin: number;
|
|
544
|
+
shadowBlurMax: number;
|
|
545
|
+
shadowOpacityMin: number;
|
|
546
|
+
shadowOpacityMax: number;
|
|
547
|
+
shadowColor: string;
|
|
548
|
+
};
|
|
549
|
+
disgustEmotion: {
|
|
550
|
+
shadowOffsetX: number;
|
|
551
|
+
shadowOffsetY: number;
|
|
552
|
+
shadowBlur: number;
|
|
553
|
+
shadowColor: string;
|
|
554
|
+
};
|
|
555
|
+
transition: {
|
|
556
|
+
duration: number;
|
|
557
|
+
easing: string;
|
|
558
|
+
};
|
|
559
|
+
lineHeight: number;
|
|
560
|
+
letterSpacing: string;
|
|
561
|
+
wordSpacing: {
|
|
562
|
+
min: string;
|
|
563
|
+
max: string;
|
|
564
|
+
};
|
|
565
|
+
fontSpacingAdjustments: {
|
|
566
|
+
'Roboto Flex': {
|
|
567
|
+
letterSpacing: string;
|
|
568
|
+
wordSpacingMultiplier: number;
|
|
569
|
+
};
|
|
570
|
+
Parkinsans: {
|
|
571
|
+
letterSpacing: string;
|
|
572
|
+
wordSpacingMultiplier: number;
|
|
573
|
+
fontSizeOffset: number;
|
|
574
|
+
};
|
|
575
|
+
Rakkas: {
|
|
576
|
+
letterSpacing: string;
|
|
577
|
+
wordSpacingMultiplier: number;
|
|
578
|
+
};
|
|
579
|
+
Cormorant: {
|
|
580
|
+
letterSpacing: string;
|
|
581
|
+
wordSpacingMultiplier: number;
|
|
582
|
+
};
|
|
583
|
+
};
|
|
584
|
+
position: {
|
|
585
|
+
bottom: string;
|
|
586
|
+
horizontalAlign: string;
|
|
587
|
+
};
|
|
588
|
+
wordAnimation: {
|
|
589
|
+
minDisplayTime: number;
|
|
590
|
+
allowOverlap: boolean;
|
|
591
|
+
};
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Rendering Configuration
|
|
596
|
+
*
|
|
597
|
+
* Central configuration for animation system timing, thresholds, and behavior
|
|
598
|
+
* This is the single source of truth for non-visual animation parameters
|
|
599
|
+
*/
|
|
600
|
+
declare const RENDERING_CONTROL: {
|
|
601
|
+
modes: {
|
|
602
|
+
word: string;
|
|
603
|
+
sentence: string;
|
|
604
|
+
};
|
|
605
|
+
timing: {
|
|
606
|
+
minWordDisplayTime: number;
|
|
607
|
+
breathingRoomDuration: number;
|
|
608
|
+
breathingRoomMinGap: number;
|
|
609
|
+
breathingRoomLargeGap: number;
|
|
610
|
+
timeRangeTolerance: number;
|
|
611
|
+
};
|
|
612
|
+
emotion: {
|
|
613
|
+
defaultThreshold: number;
|
|
614
|
+
maxThreshold: number;
|
|
615
|
+
angryFontThreshold: number;
|
|
616
|
+
angryEmotions: string[];
|
|
617
|
+
joyFontThreshold: number;
|
|
618
|
+
joyEmotions: string[];
|
|
619
|
+
sadnessFontThreshold: number;
|
|
620
|
+
sadnessEmotions: string[];
|
|
621
|
+
};
|
|
622
|
+
emphasis: {
|
|
623
|
+
minThreshold: number;
|
|
624
|
+
maxThreshold: number;
|
|
625
|
+
scaleMultiplier: number;
|
|
626
|
+
scaleUpFrames: number;
|
|
627
|
+
scaleDownFrames: number;
|
|
628
|
+
fps: number;
|
|
629
|
+
};
|
|
630
|
+
strongEmphasis: {
|
|
631
|
+
minThreshold: number;
|
|
632
|
+
maxScale: number;
|
|
633
|
+
maxRotation: number;
|
|
634
|
+
maxTranslateY: number;
|
|
635
|
+
maxTranslateX: number;
|
|
636
|
+
maxSkew: number;
|
|
637
|
+
maxBrightness: number;
|
|
638
|
+
maxContrast: number;
|
|
639
|
+
maxShadowBlur: number;
|
|
640
|
+
shadowOpacity: number;
|
|
641
|
+
shadowOffsetX: number;
|
|
642
|
+
shadowOffsetY: number;
|
|
643
|
+
maxZIndex: number;
|
|
644
|
+
outwardPushTranslateX: number;
|
|
645
|
+
outwardPushRotation: number;
|
|
646
|
+
outwardPushSkew: number;
|
|
647
|
+
fadeOutTailDuration: number;
|
|
648
|
+
};
|
|
649
|
+
fear: {};
|
|
650
|
+
joy: {
|
|
651
|
+
maxWordsForLetterAnimation: number;
|
|
652
|
+
minWordsForWordAnimation: number;
|
|
653
|
+
letterWave: {
|
|
654
|
+
innerWidthRatio: number;
|
|
655
|
+
outerWidthRatio: number;
|
|
656
|
+
maxScale: number;
|
|
657
|
+
maxRotation: number;
|
|
658
|
+
maxTranslateY: number;
|
|
659
|
+
maxTranslateX: number;
|
|
660
|
+
maxSkew: number;
|
|
661
|
+
maxBrightness: number;
|
|
662
|
+
maxContrast: number;
|
|
663
|
+
maxShadowBlur: number;
|
|
664
|
+
shadowOpacity: number;
|
|
665
|
+
maxZIndex: number;
|
|
666
|
+
};
|
|
667
|
+
letterBulge: {
|
|
668
|
+
innerWidthRatio: number;
|
|
669
|
+
outerWidthRatio: number;
|
|
670
|
+
maxScale: number;
|
|
671
|
+
maxStretchY: number;
|
|
672
|
+
maxCompressionX: number;
|
|
673
|
+
maxTranslateY: number;
|
|
674
|
+
maxTranslateX: number;
|
|
675
|
+
maxSkew: number;
|
|
676
|
+
maxRotation: number;
|
|
677
|
+
maxBrightness: number;
|
|
678
|
+
maxContrast: number;
|
|
679
|
+
maxShadowBlur: number;
|
|
680
|
+
shadowOpacity: number;
|
|
681
|
+
maxZIndex: number;
|
|
682
|
+
};
|
|
683
|
+
wordLevel: {
|
|
684
|
+
duration: number;
|
|
685
|
+
easeType: string;
|
|
686
|
+
maxScale: number;
|
|
687
|
+
maxRotation: number;
|
|
688
|
+
maxTranslateY: number;
|
|
689
|
+
maxTranslateX: number;
|
|
690
|
+
maxSkew: number;
|
|
691
|
+
maxBrightness: number;
|
|
692
|
+
maxContrast: number;
|
|
693
|
+
maxShadowBlur: number;
|
|
694
|
+
shadowOpacity: number;
|
|
695
|
+
maxZIndex: number;
|
|
696
|
+
transitionDuration: number;
|
|
697
|
+
};
|
|
698
|
+
};
|
|
699
|
+
debug: {
|
|
700
|
+
showBorders: boolean;
|
|
701
|
+
showTimings: boolean;
|
|
702
|
+
logRendering: boolean;
|
|
703
|
+
};
|
|
704
|
+
};
|
|
705
|
+
|
|
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
|
+
/**
|
|
767
|
+
* Shadow Generator
|
|
768
|
+
*
|
|
769
|
+
* Generates CSS text-shadow strings from shadow colors and emotion-specific styling
|
|
770
|
+
*/
|
|
771
|
+
/**
|
|
772
|
+
* Generate CSS text-shadow string from shadow color
|
|
773
|
+
*
|
|
774
|
+
* @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
|
|
779
|
+
*/
|
|
780
|
+
declare function generateTextShadow(shadowColor: string | undefined, fontFamily?: string, emotion?: string, intensity?: number): string;
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Dynamic Word Spacing Calculator
|
|
784
|
+
*
|
|
785
|
+
* Calculates word spacing that grows with animation scale and GTS intensity
|
|
786
|
+
* Ported from app/config/animation/styling.js
|
|
787
|
+
*/
|
|
788
|
+
/**
|
|
789
|
+
* Calculate dynamic word spacing that grows with scale
|
|
790
|
+
*
|
|
791
|
+
* @param currentScale - Current scale value from animation (e.g., 1.0 to 1.5)
|
|
792
|
+
* @param fontFamily - Font family name for spacing adjustments
|
|
793
|
+
* @param gtsIntensity - GTS intensity (0-1) - currently unused for layout preservation
|
|
794
|
+
* @param emotion - Current emotion type (for anger-specific spacing)
|
|
795
|
+
* @returns CSS em value for marginRight
|
|
796
|
+
*/
|
|
797
|
+
declare function calculateDynamicWordSpacing(currentScale?: number, fontFamily?: string, gtsIntensity?: number, emotion?: string): string;
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* Joy Animation Effects
|
|
801
|
+
*
|
|
802
|
+
* Per-letter joy pressure effects for wave and bulge animations
|
|
803
|
+
* Ported from app/utils/animation/joy.js
|
|
804
|
+
*/
|
|
805
|
+
/**
|
|
806
|
+
* Determine which joy animation mode to use based on word count
|
|
807
|
+
*/
|
|
808
|
+
declare function getJoyAnimationMode(wordCount: number): 'letter' | 'letter-bulge' | 'word';
|
|
809
|
+
interface JoyEffect {
|
|
810
|
+
pressure: number;
|
|
811
|
+
scale: number;
|
|
812
|
+
rotation: number;
|
|
813
|
+
translateX: number;
|
|
814
|
+
translateY: number;
|
|
815
|
+
skewX: number;
|
|
816
|
+
stretchY: number;
|
|
817
|
+
stretchX?: number;
|
|
818
|
+
brightness: number;
|
|
819
|
+
contrast: number;
|
|
820
|
+
shadowBlur: number;
|
|
821
|
+
shadowOpacity: number;
|
|
822
|
+
zIndex: number;
|
|
823
|
+
shadowOffsetX?: number;
|
|
824
|
+
shadowOffsetY?: number;
|
|
825
|
+
bulgeIntensity?: number;
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* Calculate per-letter joy pressure based on word progress and letter position
|
|
829
|
+
*/
|
|
830
|
+
declare function calculateJoy(progress: number, letterIndex: number, totalLetters: number, gtsMultiplier?: number): JoyEffect | null;
|
|
831
|
+
/**
|
|
832
|
+
* Calculate joy bulge effect (for multi-word subtitles)
|
|
833
|
+
*/
|
|
834
|
+
declare function calculateJoyBulge(progress: number, letterIndex: number, totalLetters: number, gtsMultiplier?: number): JoyEffect | null;
|
|
835
|
+
/**
|
|
836
|
+
* Generate CSS transform string from joy effect
|
|
837
|
+
*/
|
|
838
|
+
declare function getJoyTransform(joyEffect: JoyEffect | null): string;
|
|
839
|
+
/**
|
|
840
|
+
* Generate CSS filter string from joy effect
|
|
841
|
+
*/
|
|
842
|
+
declare function getJoyFilter(joyEffect: JoyEffect | null): string;
|
|
843
|
+
|
|
844
|
+
/**
|
|
845
|
+
* GTS (Global Text Style) Calculations
|
|
846
|
+
*
|
|
847
|
+
* Centralized logic for GTS-derived values and emotion threshold calculations
|
|
848
|
+
*/
|
|
849
|
+
/**
|
|
850
|
+
* Calculate all GTS-derived values from slider position
|
|
851
|
+
*
|
|
852
|
+
* GTS slider range: 0 to 1
|
|
853
|
+
* - GTS = 0 → maxExpression = 0.2, threshold = 0.7 (conservative)
|
|
854
|
+
* - GTS = 1 → maxExpression = 1.0, threshold = 0.2 (expressive)
|
|
855
|
+
*
|
|
856
|
+
* @param gts - GTS slider value (0-1)
|
|
857
|
+
* @returns All derived GTS values
|
|
858
|
+
*/
|
|
859
|
+
declare function calculateGTSValues(gts: number): {
|
|
860
|
+
gts: number;
|
|
861
|
+
maxExpression: number;
|
|
862
|
+
threshold: number;
|
|
863
|
+
shouldEnableAngryFont: boolean;
|
|
864
|
+
};
|
|
865
|
+
/**
|
|
866
|
+
* Check if emotion intensity meets the threshold
|
|
867
|
+
*
|
|
868
|
+
* @param intensity - Raw emotion intensity from backend (0-1)
|
|
869
|
+
* @param threshold - GTS-calculated threshold (0-1)
|
|
870
|
+
* @returns True if intensity is above threshold
|
|
871
|
+
*/
|
|
872
|
+
declare function meetsEmotionThreshold(intensity: number, threshold: number): boolean;
|
|
873
|
+
/**
|
|
874
|
+
* Calculate capped emotion intensity based on GTS maxExpression
|
|
875
|
+
*
|
|
876
|
+
* @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)
|
|
879
|
+
*/
|
|
880
|
+
declare function capEmotionIntensity(rawIntensity: number, maxExpression: number): number;
|
|
881
|
+
/**
|
|
882
|
+
* Calculate emphasis multiplier within valid emphasis range
|
|
883
|
+
*
|
|
884
|
+
* Maps emphasis value within [minThreshold, maxThreshold] to [0, 1]
|
|
885
|
+
* Used for scaling emphasis effects based on position in range
|
|
886
|
+
*
|
|
887
|
+
* @param emphasis - Word emphasis value (0-1)
|
|
888
|
+
* @returns Emphasis multiplier (0-1), or 0 if outside range
|
|
889
|
+
*/
|
|
890
|
+
declare function calculateEmphasisMultiplier(emphasis: number): number;
|
|
891
|
+
/**
|
|
892
|
+
* Check if emphasis value is in valid range for emphasis animation
|
|
893
|
+
*
|
|
894
|
+
* @param emphasis - Word emphasis value (0-1)
|
|
895
|
+
* @returns True if in emphasis range [0.5, 0.7)
|
|
896
|
+
*/
|
|
897
|
+
declare function isInEmphasisRange(emphasis: number): boolean;
|
|
898
|
+
/**
|
|
899
|
+
* Check if emphasis value is in valid range for strong emphasis animation
|
|
900
|
+
*
|
|
901
|
+
* @param emphasis - Word emphasis value (0-1)
|
|
902
|
+
* @returns True if in strong emphasis range [0.7, 1.0]
|
|
903
|
+
*/
|
|
904
|
+
declare function isInStrongEmphasisRange(emphasis: number): boolean;
|
|
905
|
+
|
|
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
|
+
/**
|
|
915
|
+
* Font Selection Utilities
|
|
916
|
+
*
|
|
917
|
+
* Centralized logic for selecting fonts based on emotion and intensity
|
|
918
|
+
* Eliminates duplicate font selection code across controllers
|
|
919
|
+
*/
|
|
920
|
+
interface Stylesheet {
|
|
921
|
+
name?: string;
|
|
922
|
+
fonts?: Record<string, string>;
|
|
923
|
+
}
|
|
924
|
+
/**
|
|
925
|
+
* Select font family based on emotion and GTS intensity
|
|
926
|
+
*
|
|
927
|
+
* @param emotion - Emotion name (lowercase, e.g., 'anger', 'joy', 'sadness')
|
|
928
|
+
* @param maxExpression - GTS-derived max expression (0-1)
|
|
929
|
+
* @param emotionCategory - Emotion category for children stylesheet (shout, whisper, anger, fear, neutral)
|
|
930
|
+
* @param stylesheet - Active stylesheet config (optional)
|
|
931
|
+
* @returns Font family name
|
|
932
|
+
*/
|
|
933
|
+
declare function selectFontFamily(emotion: string, maxExpression: number, emotionCategory?: string | null, stylesheet?: Stylesheet | null): string;
|
|
934
|
+
/**
|
|
935
|
+
* Get CSS-ready font-family value
|
|
936
|
+
*
|
|
937
|
+
* @param emotion - Emotion name (lowercase)
|
|
938
|
+
* @param maxExpression - GTS-derived max expression (0-1)
|
|
939
|
+
* @param emotionCategory - Emotion category for children stylesheet
|
|
940
|
+
* @param stylesheet - Active stylesheet config (optional)
|
|
941
|
+
* @returns CSS font-family value
|
|
942
|
+
*/
|
|
943
|
+
declare function getFontFamilyCSS(emotion: string, maxExpression: number, emotionCategory?: string | null, stylesheet?: Stylesheet | null): string;
|
|
944
|
+
/**
|
|
945
|
+
* Check if a given emotion and intensity should use Rakkas (angry) font
|
|
946
|
+
*
|
|
947
|
+
* @param emotion - Emotion name (lowercase)
|
|
948
|
+
* @param maxExpression - GTS-derived max expression (0-1)
|
|
949
|
+
* @returns True if Rakkas font should be used
|
|
950
|
+
*/
|
|
951
|
+
declare function shouldUseAngryFont(emotion: string, maxExpression: number): boolean;
|
|
952
|
+
/**
|
|
953
|
+
* Check if a given emotion and intensity should use Parkinsans (joy) font
|
|
954
|
+
*
|
|
955
|
+
* @param emotion - Emotion name (lowercase)
|
|
956
|
+
* @param maxExpression - GTS-derived max expression (0-1)
|
|
957
|
+
* @returns True if Parkinsans font should be used
|
|
958
|
+
*/
|
|
959
|
+
declare function shouldUseJoyFont(emotion: string, maxExpression: number): boolean;
|
|
960
|
+
/**
|
|
961
|
+
* Check if a given emotion and intensity should use Cormorant (sadness) font
|
|
962
|
+
*
|
|
963
|
+
* @param emotion - Emotion name (lowercase)
|
|
964
|
+
* @param maxExpression - GTS-derived max expression (0-1)
|
|
965
|
+
* @returns True if Cormorant font should be used
|
|
966
|
+
*/
|
|
967
|
+
declare function shouldUseSadnessFont(emotion: string, maxExpression: number): boolean;
|
|
968
|
+
|
|
969
|
+
/**
|
|
970
|
+
* Letter Splitting Utilities
|
|
971
|
+
*
|
|
972
|
+
* Reusable utilities for splitting text into individual letters for per-letter animations
|
|
973
|
+
*/
|
|
974
|
+
interface Letter {
|
|
975
|
+
char: string;
|
|
976
|
+
isSpace: boolean;
|
|
977
|
+
index: number;
|
|
978
|
+
}
|
|
979
|
+
/**
|
|
980
|
+
* Split text into individual letters for per-letter animation
|
|
981
|
+
*
|
|
982
|
+
* Preserves spaces as non-breaking spaces to maintain layout.
|
|
983
|
+
* Each letter gets metadata for animation calculations.
|
|
984
|
+
*/
|
|
985
|
+
declare function splitTextIntoLetters(text: string): Letter[];
|
|
986
|
+
|
|
987
|
+
/**
|
|
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
|
|
1047
|
+
*
|
|
1048
|
+
* @param params - Emphasis calculation parameters
|
|
1049
|
+
* @returns Emphasis effects { emphasisEffect, strongEmphasisData }
|
|
1050
|
+
*/
|
|
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
|
+
/**
|
|
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
|
|
1086
|
+
*
|
|
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
|
|
1106
|
+
*
|
|
1107
|
+
* @param params - Spacing calculation parameters
|
|
1108
|
+
* @returns Array of translateX offsets in pixels (one per letter)
|
|
1109
|
+
*/
|
|
1110
|
+
declare function calculateWordLetterSpacing({ strongEmphasisData, emphasisEffect, wordLetterShakeIntensity, wordFontFamily, currentTime, word, emotionAnimationDuration, wordEmotion, totalLetters, fontSize, }: WordLetterSpacingParams): number[];
|
|
1111
|
+
|
|
1112
|
+
/**
|
|
1113
|
+
* Backend Data Accessors
|
|
1114
|
+
*
|
|
1115
|
+
* Type-safe helpers for accessing backend subtitle data
|
|
1116
|
+
* Provides consistent interface and handles edge cases
|
|
1117
|
+
* Identical to monorepo app/utils/data/backendDataAccessors.js
|
|
1118
|
+
*/
|
|
1119
|
+
|
|
1120
|
+
/**
|
|
1121
|
+
* Get subtitle words array
|
|
1122
|
+
*/
|
|
1123
|
+
declare function getSubtitleWords(subtitle: SubtitleSegment | null): any[];
|
|
1124
|
+
/**
|
|
1125
|
+
* Get subtitle animations/emotions
|
|
1126
|
+
*/
|
|
1127
|
+
declare function getSubtitleAnimations(subtitle: SubtitleSegment | null): Record<string, number>;
|
|
1128
|
+
/**
|
|
1129
|
+
* Check if subtitle has merged subtitles
|
|
1130
|
+
*/
|
|
1131
|
+
declare function hasMergedSubtitles(subtitle: SubtitleSegment | null): boolean;
|
|
1132
|
+
/**
|
|
1133
|
+
* Get merged subtitles array
|
|
1134
|
+
*/
|
|
1135
|
+
declare function getMergedSubtitles(subtitle: SubtitleSegment | null): SubtitleSegment[];
|
|
1136
|
+
/**
|
|
1137
|
+
* Find subtitle containing a specific word based on timing
|
|
1138
|
+
*
|
|
1139
|
+
* Used for merged_subtitles to find which subtitle a word belongs to
|
|
1140
|
+
*/
|
|
1141
|
+
declare function findSubtitleForWord(subtitles: SubtitleSegment[], word: any): SubtitleSegment | null;
|
|
1142
|
+
|
|
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
|
+
/**
|
|
1162
|
+
* Variable Font Calculations
|
|
1163
|
+
*
|
|
1164
|
+
* Pure functions for calculating font weight/width from volume/speechRate
|
|
1165
|
+
* Extracted from app/utils/font/variableFontCalculations.js
|
|
1166
|
+
*/
|
|
1167
|
+
interface FontAxisConfig {
|
|
1168
|
+
min: number;
|
|
1169
|
+
max: number;
|
|
1170
|
+
default: number;
|
|
1171
|
+
}
|
|
1172
|
+
interface FontConfig {
|
|
1173
|
+
axes?: {
|
|
1174
|
+
weight?: FontAxisConfig;
|
|
1175
|
+
width?: FontAxisConfig;
|
|
1176
|
+
};
|
|
1177
|
+
mapping?: {
|
|
1178
|
+
volume?: {
|
|
1179
|
+
min: number;
|
|
1180
|
+
max: number;
|
|
1181
|
+
};
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Calculate font weight from volume
|
|
1186
|
+
* Maps volume (0-1) to weight range
|
|
1187
|
+
*
|
|
1188
|
+
* @param volume - Volume value (0-1)
|
|
1189
|
+
* @param weightAxis - Weight axis config from font
|
|
1190
|
+
* @param fontConfig - Font configuration object (optional)
|
|
1191
|
+
* @param baseWeight - Optional base weight from URL (if provided, volume variation is applied on top)
|
|
1192
|
+
* @returns Calculated font weight
|
|
1193
|
+
*/
|
|
1194
|
+
declare function calculateWeightFromVolume(volume: number | undefined, weightAxis: FontAxisConfig | undefined, fontConfig?: FontConfig | null, baseWeight?: number): number;
|
|
1195
|
+
/**
|
|
1196
|
+
* Calculate font width from speech rate
|
|
1197
|
+
* Uses inverse relationship: slower speech = wider font
|
|
1198
|
+
* Maps speech rate (0-1) to width range
|
|
1199
|
+
*
|
|
1200
|
+
* @param speechRate - Speech rate value (0-1)
|
|
1201
|
+
* @param widthAxis - Width axis config from font
|
|
1202
|
+
* @param baseWidth - Optional base width from URL (if provided, speechRate variation is applied on top)
|
|
1203
|
+
* @returns Calculated font width
|
|
1204
|
+
*/
|
|
1205
|
+
declare function calculateWidthFromSpeechRate(speechRate: number | undefined, widthAxis: FontAxisConfig | undefined, baseWidth?: number): number;
|
|
1206
|
+
|
|
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;
|
|
1235
|
+
|
|
1236
|
+
/**
|
|
1237
|
+
* PHONT API Client
|
|
1238
|
+
*
|
|
1239
|
+
* Supports both authentication methods:
|
|
1240
|
+
* - API Keys: For server-side/programmatic access (POST/DELETE /vods, GET /vods/status)
|
|
1241
|
+
* - Session Tokens: For frontend/user access (GET /vods, GET /vods/{id}, GET /vod-subtitles/{id})
|
|
1242
|
+
*
|
|
1243
|
+
* Tenant isolation is handled automatically by the backend based on credentials.
|
|
1244
|
+
*/
|
|
1245
|
+
|
|
1246
|
+
interface LoginResponse {
|
|
1247
|
+
tenant_id: string;
|
|
1248
|
+
username: string;
|
|
1249
|
+
email: string;
|
|
1250
|
+
session_id: string;
|
|
1251
|
+
auth_token: string;
|
|
1252
|
+
}
|
|
1253
|
+
interface RegisterResponse {
|
|
1254
|
+
tenant_id: string;
|
|
1255
|
+
username: string;
|
|
1256
|
+
email: string;
|
|
1257
|
+
}
|
|
1258
|
+
interface VodMetadata {
|
|
1259
|
+
_id: string;
|
|
1260
|
+
tenant_id: string;
|
|
1261
|
+
manifest: string;
|
|
1262
|
+
thumbnail?: string;
|
|
1263
|
+
audio_url?: string;
|
|
1264
|
+
name: string;
|
|
1265
|
+
subtitle_available: boolean;
|
|
1266
|
+
created_at: string;
|
|
1267
|
+
}
|
|
1268
|
+
declare class PhontClient {
|
|
1269
|
+
private apiKey?;
|
|
1270
|
+
private authToken?;
|
|
1271
|
+
private sessionId?;
|
|
1272
|
+
readonly apiBaseUrl: string;
|
|
1273
|
+
constructor(options: PhontClientOptions);
|
|
1274
|
+
/**
|
|
1275
|
+
* Get authentication headers based on configured auth method
|
|
1276
|
+
*/
|
|
1277
|
+
getAuthHeaders(): Record<string, string>;
|
|
1278
|
+
/**
|
|
1279
|
+
* Make an authenticated request
|
|
1280
|
+
*/
|
|
1281
|
+
private request;
|
|
1282
|
+
/**
|
|
1283
|
+
* Login with credentials (for frontend/user access)
|
|
1284
|
+
* Returns session_id and auth_token for subsequent requests
|
|
1285
|
+
*/
|
|
1286
|
+
login(identifier: string, password: string): Promise<LoginResponse>;
|
|
1287
|
+
/**
|
|
1288
|
+
* Register a new user
|
|
1289
|
+
*/
|
|
1290
|
+
register(username: string, email: string, password: string): Promise<RegisterResponse>;
|
|
1291
|
+
/**
|
|
1292
|
+
* Get subtitle track for a VOD
|
|
1293
|
+
* Requires: Session token authentication
|
|
1294
|
+
* @param vodId - VOD ID
|
|
1295
|
+
* @param lang - Language code (optional). If not provided, returns original language subtitles.
|
|
1296
|
+
* Use null/undefined for original, or a valid language code for translations.
|
|
1297
|
+
* @param model - Model name for LLM translation (optional)
|
|
1298
|
+
*/
|
|
1299
|
+
getSubtitleTrack(vodId: string, lang?: string | null, model?: string | null): Promise<any>;
|
|
1300
|
+
/**
|
|
1301
|
+
* Get VOD metadata
|
|
1302
|
+
* Requires: Session token authentication
|
|
1303
|
+
*/
|
|
1304
|
+
getVod(vodId: string): Promise<VodMetadata>;
|
|
1305
|
+
/**
|
|
1306
|
+
* List user's VODs (tenant-isolated)
|
|
1307
|
+
* Requires: Session token authentication
|
|
1308
|
+
*/
|
|
1309
|
+
listVods(skip?: number, limit?: number): Promise<VodMetadata[]>;
|
|
1310
|
+
/**
|
|
1311
|
+
* Create a new VOD
|
|
1312
|
+
* Requires: API key authentication
|
|
1313
|
+
*/
|
|
1314
|
+
createVod(data: {
|
|
1315
|
+
manifest: string;
|
|
1316
|
+
thumbnail?: string;
|
|
1317
|
+
name: string;
|
|
1318
|
+
}): Promise<VodMetadata>;
|
|
1319
|
+
/**
|
|
1320
|
+
* Delete a VOD
|
|
1321
|
+
* Requires: API key authentication
|
|
1322
|
+
*/
|
|
1323
|
+
deleteVod(vodId: string): Promise<void>;
|
|
1324
|
+
/**
|
|
1325
|
+
* Get VOD processing status
|
|
1326
|
+
* Requires: API key authentication
|
|
1327
|
+
*/
|
|
1328
|
+
getVodStatus(vodId: string): Promise<{
|
|
1329
|
+
vod_id: string;
|
|
1330
|
+
status: string;
|
|
1331
|
+
}>;
|
|
1332
|
+
/**
|
|
1333
|
+
* Update credentials (useful after login)
|
|
1334
|
+
*/
|
|
1335
|
+
setCredentials(options: {
|
|
1336
|
+
apiKey?: string;
|
|
1337
|
+
authToken?: string;
|
|
1338
|
+
sessionId?: string;
|
|
1339
|
+
}): void;
|
|
1340
|
+
/**
|
|
1341
|
+
* Clear credentials (for logout)
|
|
1342
|
+
*/
|
|
1343
|
+
clearCredentials(): void;
|
|
1344
|
+
}
|
|
1345
|
+
|
|
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 };
|