@meframe/core 0.0.43 → 0.0.45

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.
Files changed (90) hide show
  1. package/dist/Meframe.d.ts.map +1 -1
  2. package/dist/Meframe.js +1 -0
  3. package/dist/Meframe.js.map +1 -1
  4. package/dist/cache/CacheManager.d.ts +5 -2
  5. package/dist/cache/CacheManager.d.ts.map +1 -1
  6. package/dist/cache/CacheManager.js +8 -3
  7. package/dist/cache/CacheManager.js.map +1 -1
  8. package/dist/cache/l1/AudioL1Cache.d.ts +5 -1
  9. package/dist/cache/l1/AudioL1Cache.d.ts.map +1 -1
  10. package/dist/cache/l1/AudioL1Cache.js +19 -2
  11. package/dist/cache/l1/AudioL1Cache.js.map +1 -1
  12. package/dist/cache/storage/opfs/OPFSManager.d.ts +7 -3
  13. package/dist/cache/storage/opfs/OPFSManager.d.ts.map +1 -1
  14. package/dist/cache/storage/opfs/OPFSManager.js +29 -14
  15. package/dist/cache/storage/opfs/OPFSManager.js.map +1 -1
  16. package/dist/config/defaults.d.ts.map +1 -1
  17. package/dist/config/defaults.js +1 -6
  18. package/dist/config/defaults.js.map +1 -1
  19. package/dist/config/types.d.ts +2 -8
  20. package/dist/config/types.d.ts.map +1 -1
  21. package/dist/controllers/PlaybackController.d.ts +1 -1
  22. package/dist/controllers/PlaybackController.d.ts.map +1 -1
  23. package/dist/controllers/PlaybackController.js +3 -4
  24. package/dist/controllers/PlaybackController.js.map +1 -1
  25. package/dist/model/CompositionModel.d.ts.map +1 -1
  26. package/dist/model/CompositionModel.js +0 -4
  27. package/dist/model/CompositionModel.js.map +1 -1
  28. package/dist/orchestrator/ExportScheduler.d.ts +1 -0
  29. package/dist/orchestrator/ExportScheduler.d.ts.map +1 -1
  30. package/dist/orchestrator/ExportScheduler.js +12 -18
  31. package/dist/orchestrator/ExportScheduler.js.map +1 -1
  32. package/dist/orchestrator/GlobalAudioSession.d.ts.map +1 -1
  33. package/dist/orchestrator/GlobalAudioSession.js +1 -0
  34. package/dist/orchestrator/GlobalAudioSession.js.map +1 -1
  35. package/dist/orchestrator/OnDemandVideoSession.d.ts +5 -0
  36. package/dist/orchestrator/OnDemandVideoSession.d.ts.map +1 -1
  37. package/dist/orchestrator/OnDemandVideoSession.js +78 -0
  38. package/dist/orchestrator/OnDemandVideoSession.js.map +1 -1
  39. package/dist/orchestrator/Orchestrator.d.ts.map +1 -1
  40. package/dist/orchestrator/Orchestrator.js +5 -6
  41. package/dist/orchestrator/Orchestrator.js.map +1 -1
  42. package/dist/orchestrator/VideoClipSession.d.ts +8 -9
  43. package/dist/orchestrator/VideoClipSession.d.ts.map +1 -1
  44. package/dist/orchestrator/VideoClipSession.js +112 -175
  45. package/dist/orchestrator/VideoClipSession.js.map +1 -1
  46. package/dist/stages/compose/FrameRateConverter.d.ts +4 -4
  47. package/dist/stages/compose/FrameRateConverter.d.ts.map +1 -1
  48. package/dist/stages/compose/LayerRenderer.d.ts +9 -0
  49. package/dist/stages/compose/LayerRenderer.d.ts.map +1 -1
  50. package/dist/stages/compose/LayerRenderer.js +41 -35
  51. package/dist/stages/compose/LayerRenderer.js.map +1 -1
  52. package/dist/stages/compose/font-system/font-templates.js +1 -1
  53. package/dist/stages/compose/font-system/font-templates.js.map +1 -1
  54. package/dist/stages/load/ResourceLoader.d.ts +5 -4
  55. package/dist/stages/load/ResourceLoader.d.ts.map +1 -1
  56. package/dist/stages/load/ResourceLoader.js +14 -59
  57. package/dist/stages/load/ResourceLoader.js.map +1 -1
  58. package/dist/worker/WorkerChannel.d.ts.map +1 -1
  59. package/dist/worker/WorkerChannel.js +11 -2
  60. package/dist/worker/WorkerChannel.js.map +1 -1
  61. package/dist/worker/WorkerPool.d.ts.map +1 -1
  62. package/dist/worker/WorkerPool.js +5 -2
  63. package/dist/worker/WorkerPool.js.map +1 -1
  64. package/dist/worker/transferable-helper.js +22 -0
  65. package/dist/worker/transferable-helper.js.map +1 -1
  66. package/dist/worker/types.d.ts +1 -1
  67. package/dist/worker/types.d.ts.map +1 -1
  68. package/dist/worker/types.js.map +1 -1
  69. package/dist/workers/{WorkerChannel.CE5euh3R.js → WorkerChannel.DjBEVvEA.js} +31 -2
  70. package/dist/workers/WorkerChannel.DjBEVvEA.js.map +1 -0
  71. package/dist/workers/stages/compose/{audio-compose.worker.rW63uN6z.js → audio-compose.worker.CiM_KP27.js} +2 -2
  72. package/dist/workers/stages/compose/{audio-compose.worker.rW63uN6z.js.map → audio-compose.worker.CiM_KP27.js.map} +1 -1
  73. package/dist/workers/stages/compose/{video-compose.worker.D_542rY_.js → video-compose.worker.CeT5le4s.js} +55 -63
  74. package/dist/workers/stages/compose/video-compose.worker.CeT5le4s.js.map +1 -0
  75. package/dist/workers/stages/decode/{audio-decode.worker.B__6tqsy.js → audio-decode.worker.CpjkrZtT.js} +2 -2
  76. package/dist/workers/stages/decode/{audio-decode.worker.B__6tqsy.js.map → audio-decode.worker.CpjkrZtT.js.map} +1 -1
  77. package/dist/workers/stages/decode/{video-decode.worker.tOv-QR2f.js → video-decode.worker.BQtw6eWn.js} +2 -2
  78. package/dist/workers/stages/decode/video-decode.worker.BQtw6eWn.js.map +1 -0
  79. package/dist/workers/stages/demux/{audio-demux.worker.DgvvQVXU.js → audio-demux.worker.C4V11GQi.js} +2 -2
  80. package/dist/workers/stages/demux/{audio-demux.worker.DgvvQVXU.js.map → audio-demux.worker.C4V11GQi.js.map} +1 -1
  81. package/dist/workers/stages/demux/{video-demux.worker.DhG3CRix.js → video-demux.worker.5pJr0Ij-.js} +2 -2
  82. package/dist/workers/stages/demux/video-demux.worker.5pJr0Ij-.js.map +1 -0
  83. package/dist/workers/stages/encode/{video-encode.worker.D8pfFber.js → video-encode.worker.CX2_3YhQ.js} +2 -2
  84. package/dist/workers/stages/encode/{video-encode.worker.D8pfFber.js.map → video-encode.worker.CX2_3YhQ.js.map} +1 -1
  85. package/dist/workers/worker-manifest.json +7 -7
  86. package/package.json +1 -1
  87. package/dist/workers/WorkerChannel.CE5euh3R.js.map +0 -1
  88. package/dist/workers/stages/compose/video-compose.worker.D_542rY_.js.map +0 -1
  89. package/dist/workers/stages/decode/video-decode.worker.tOv-QR2f.js.map +0 -1
  90. package/dist/workers/stages/demux/video-demux.worker.DhG3CRix.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video-compose.worker.CeT5le4s.js","sources":["../../../../src/stages/compose/text-utils/text-metrics.ts","../../../../src/stages/compose/text-utils/text-wrapper.ts","../../../../src/stages/compose/text-renderers/animation-utils.ts","../../../../src/stages/compose/text-utils/locale-detector.ts","../../../../src/stages/compose/text-renderers/basic-text-renderer.ts","../../../../src/stages/compose/text-renderers/word-by-word-renderer.ts","../../../../src/stages/compose/text-renderers/character-ktv-renderer.ts","../../../../src/stages/compose/text-renderers/word-fancy-renderer.ts","../../../../src/stages/compose/LayerRenderer.ts","../../../../src/stages/compose/TransitionProcessor.ts","../../../../src/stages/compose/FilterProcessor.ts","../../../../src/stages/compose/VideoComposer.ts","../../../../src/utils/time-utils.ts","../../../../src/utils/animation-utils.ts","../../../../src/stages/compose/FrameRateConverter.ts","../../../../src/stages/compose/video-compose.worker.ts"],"sourcesContent":["export function measureTextWidth(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n text: string,\n fontSize: number,\n fontFamily: string,\n fontWeight: string | number = 400\n): number {\n ctx.save();\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n const metrics = ctx.measureText(text);\n ctx.restore();\n return metrics.width;\n}\n\nexport function getLetterCaseText(text: string, letterCase?: 'upper' | 'lower' | 'none'): string {\n if (letterCase === 'upper') {\n return text.toUpperCase();\n }\n if (letterCase === 'lower') {\n return text.toLowerCase();\n }\n return text;\n}\n","import { measureTextWidth } from './text-metrics';\n\nfunction findAllBreakPoints(text: string): number[] {\n const breakPoints = [0];\n const chars = Array.from(text);\n\n for (let i = 1; i < chars.length - 1; i++) {\n if (/[、。!?,,!?;:]/.test(chars[i]!)) {\n breakPoints.push(i + 1);\n } else if (\n /[\\u3040-\\u309F\\u30A0-\\u30FF\\u4E00-\\u9FAF]/.test(chars[i]!) &&\n /[\\u3040-\\u309F\\u30A0-\\u30FF\\u4E00-\\u9FAF]/.test(chars[i + 1]!)\n ) {\n breakPoints.push(i + 1);\n } else if (/[\\s\\-–—,.!?;:]/.test(chars[i]!)) {\n breakPoints.push(i + 1);\n } else if (/\\s/.test(chars[i]!) && /[a-zA-Z]/.test(chars[i + 1]!)) {\n breakPoints.push(i + 1);\n }\n }\n\n breakPoints.push(chars.length);\n return breakPoints;\n}\n\nfunction evaluateBalance(\n lines: string[],\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n fontSize: number,\n fontFamily: string,\n fontWeight: string | number\n): number {\n if (lines.length <= 1) return 0;\n const lengths = lines.map((line) =>\n measureTextWidth(ctx, line, fontSize, fontFamily, fontWeight)\n );\n const avgLength = lengths.reduce((a, b) => a + b, 0) / lengths.length;\n return lengths.reduce((sum, len) => sum + Math.abs(len - avgLength), 0);\n}\n\nfunction tryBreakPointsForMultipleLines(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n text: string,\n start: number,\n remainingLines: number,\n currentLines: string[],\n maxWidth: number,\n fontSize: number,\n fontFamily: string,\n fontWeight: string | number,\n breakPoints: number[]\n): {\n bestLines: string[];\n bestBalance: number;\n} {\n let bestLines: string[] = [];\n let bestBalance = Infinity;\n\n if (remainingLines === 1) {\n const lastLine = text.slice(start).trim();\n const lastLineWidth = measureTextWidth(ctx, lastLine, fontSize, fontFamily, fontWeight);\n\n if (lastLineWidth <= maxWidth) {\n const allLines = [...currentLines, lastLine];\n const balance = evaluateBalance(allLines, ctx, fontSize, fontFamily, fontWeight);\n\n if (balance < bestBalance) {\n bestBalance = balance;\n bestLines = allLines;\n }\n } else {\n const words = lastLine.split(/\\s+/);\n let currentLine = '';\n let tempLines = [...currentLines];\n\n for (const word of words) {\n const testLine = currentLine ? `${currentLine} ${word}` : word;\n const lineWidth = measureTextWidth(ctx, testLine, fontSize, fontFamily, fontWeight);\n\n if (lineWidth <= maxWidth) {\n currentLine = testLine;\n } else {\n if (currentLine) {\n tempLines.push(currentLine);\n currentLine = word;\n } else {\n tempLines.push(word);\n currentLine = '';\n }\n }\n }\n\n if (currentLine) {\n tempLines.push(currentLine);\n }\n\n const balance = evaluateBalance(tempLines, ctx, fontSize, fontFamily, fontWeight);\n if (balance < bestBalance) {\n bestBalance = balance;\n bestLines = tempLines;\n }\n }\n return { bestLines, bestBalance };\n }\n\n let foundValidBreak = false;\n\n for (let i = 0; i < breakPoints.length; i++) {\n const bp = breakPoints[i]!;\n if (bp <= start || bp >= text.length) continue;\n\n const line = text.slice(start, bp).trim();\n const lineWidth = measureTextWidth(ctx, line, fontSize, fontFamily, fontWeight);\n\n if (lineWidth <= maxWidth) {\n foundValidBreak = true;\n const result = tryBreakPointsForMultipleLines(\n ctx,\n text,\n bp,\n remainingLines - 1,\n [...currentLines, line],\n maxWidth,\n fontSize,\n fontFamily,\n fontWeight,\n breakPoints\n );\n if (result.bestBalance < bestBalance) {\n bestBalance = result.bestBalance;\n bestLines = result.bestLines;\n }\n }\n }\n\n if (!foundValidBreak) {\n const textPortion = text.slice(start);\n const words = textPortion.split(/\\s+/);\n let currentLine = '';\n let tempLines = [...currentLines];\n\n for (const word of words) {\n const testLine = currentLine ? `${currentLine} ${word}` : word;\n const lineWidth = measureTextWidth(ctx, testLine, fontSize, fontFamily, fontWeight);\n\n if (lineWidth <= maxWidth) {\n currentLine = testLine;\n } else {\n if (currentLine) {\n tempLines.push(currentLine);\n currentLine = word;\n } else {\n tempLines.push(word);\n }\n }\n }\n\n if (currentLine) {\n tempLines.push(currentLine);\n }\n\n bestLines = tempLines;\n }\n\n return { bestLines, bestBalance };\n}\n\nexport function wrapText(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n text: string,\n maxWidth: number,\n fontSize: number,\n fontFamily: string,\n fontWeight: string | number = 400\n): string[] {\n const textWidth = measureTextWidth(ctx, text, fontSize, fontFamily, fontWeight);\n if (textWidth <= maxWidth) {\n return [text];\n }\n\n const estimatedLines = Math.ceil(textWidth / maxWidth);\n const breakPoints = findAllBreakPoints(text);\n\n const { bestLines } = tryBreakPointsForMultipleLines(\n ctx,\n text,\n 0,\n estimatedLines,\n [],\n maxWidth,\n fontSize,\n fontFamily,\n fontWeight,\n breakPoints\n );\n\n return bestLines.length > 0 ? bestLines : [text];\n}\n\nexport function formLinesWithWords(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n words: string[],\n maxWidth: number,\n fontSize: number,\n needsSpace: boolean,\n fontFamily: string,\n fontWeight: string | number = 400\n): string[] {\n const result: string[] = [];\n let accumulatedWidth = 0;\n const spaceWidth = measureTextWidth(ctx, ' ', fontSize, fontFamily, fontWeight);\n let currentLine = '';\n\n for (const word of words) {\n let wordWidth = measureTextWidth(ctx, word, fontSize, fontFamily, fontWeight);\n if (needsSpace) {\n wordWidth += spaceWidth;\n }\n if (wordWidth + accumulatedWidth <= maxWidth) {\n currentLine += word + (needsSpace ? ' ' : '');\n accumulatedWidth += wordWidth;\n } else {\n if (currentLine) {\n result.push(currentLine);\n }\n currentLine = word + (needsSpace ? ' ' : '');\n accumulatedWidth = wordWidth;\n }\n }\n if (currentLine !== '') {\n result.push(currentLine);\n }\n return result;\n}\n\nexport function formEvenLinesWithWords(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n words: string[],\n maxWidth: number,\n fontSize: number,\n needsSpace: boolean,\n fontFamily: string,\n fontWeight: string | number = 400\n): string[] {\n let minWidth = maxWidth / 2;\n for (const word of words) {\n const wordWidth = measureTextWidth(ctx, word, fontSize, fontFamily, fontWeight);\n if (wordWidth > minWidth) {\n minWidth = wordWidth;\n }\n }\n\n const leastLineNum = formLinesWithWords(\n ctx,\n words,\n maxWidth,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n ).length;\n\n let bestDelta = maxWidth;\n let bestWidth = minWidth;\n for (let width = maxWidth; width >= minWidth; width -= 1) {\n const lines = formLinesWithWords(\n ctx,\n words,\n width,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n );\n if (lines.length > leastLineNum) {\n break;\n }\n let minLineWidth = Infinity;\n let maxLineWidth = 0;\n for (const line of lines) {\n const lineWidth = measureTextWidth(ctx, line, fontSize, fontFamily, fontWeight);\n if (lineWidth < minLineWidth) {\n minLineWidth = lineWidth;\n }\n if (lineWidth > maxLineWidth) {\n maxLineWidth = lineWidth;\n }\n }\n const delta = maxLineWidth - minLineWidth;\n if (delta < bestDelta) {\n bestDelta = delta;\n bestWidth = width;\n }\n }\n\n return formLinesWithWords(ctx, words, bestWidth, fontSize, needsSpace, fontFamily, fontWeight);\n}\n","export interface SpringConfig {\n damping: number;\n mass: number;\n stiffness: number;\n overshootClamping?: boolean;\n}\n\nexport function springEasing(frame: number, config: SpringConfig): number {\n const { damping, mass, stiffness, overshootClamping = false } = config;\n\n if (frame <= 0) return 0;\n\n const zeta = damping / (2 * Math.sqrt(mass * stiffness));\n const omega = Math.sqrt(stiffness / mass);\n const t = frame / 60;\n\n let value: number;\n\n if (zeta < 1) {\n const omegaD = omega * Math.sqrt(1 - zeta * zeta);\n const A = 1;\n const B = (zeta * omega) / omegaD;\n value = 1 - Math.exp(-zeta * omega * t) * (A * Math.cos(omegaD * t) + B * Math.sin(omegaD * t));\n } else if (zeta === 1) {\n value = 1 - Math.exp(-omega * t) * (1 + omega * t);\n } else {\n const r1 = -omega * (zeta - Math.sqrt(zeta * zeta - 1));\n const r2 = -omega * (zeta + Math.sqrt(zeta * zeta - 1));\n const A = r2 / (r2 - r1);\n const B = 1 - A;\n value = 1 - A * Math.exp(r1 * t) - B * Math.exp(r2 * t);\n }\n\n if (overshootClamping && value > 1) {\n return 1;\n }\n\n return Math.max(0, value);\n}\n\nexport function interpolate(\n value: number,\n inputRange: [number, number],\n outputRange: [number, number],\n options?: {\n extrapolateLeft?: 'clamp' | 'extend';\n extrapolateRight?: 'clamp' | 'extend';\n }\n): number {\n const { extrapolateLeft = 'extend', extrapolateRight = 'extend' } = options || {};\n\n const [inputMin, inputMax] = inputRange;\n const [outputMin, outputMax] = outputRange;\n\n if (value < inputMin) {\n if (extrapolateLeft === 'clamp') {\n return outputMin;\n }\n }\n\n if (value > inputMax) {\n if (extrapolateRight === 'clamp') {\n return outputMax;\n }\n }\n\n const inputDelta = inputMax - inputMin;\n if (inputDelta === 0) {\n return outputMin;\n }\n\n const progress = (value - inputMin) / inputDelta;\n const outputDelta = outputMax - outputMin;\n\n return outputMin + progress * outputDelta;\n}\n\nfunction parseRgb(color: string): { r: number; g: number; b: number } | null {\n const match = color.match(/rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)/);\n if (match) {\n return {\n r: parseInt(match[1]!, 10),\n g: parseInt(match[2]!, 10),\n b: parseInt(match[3]!, 10),\n };\n }\n return null;\n}\n\nexport function interpolateColor(color1: string, color2: string, progress: number): string {\n const rgb1 = parseRgb(color1);\n const rgb2 = parseRgb(color2);\n\n if (!rgb1 || !rgb2) {\n return color1;\n }\n\n const r = Math.round(interpolate(progress, [0, 1], [rgb1.r, rgb2.r]));\n const g = Math.round(interpolate(progress, [0, 1], [rgb1.g, rgb2.g]));\n const b = Math.round(interpolate(progress, [0, 1], [rgb1.b, rgb2.b]));\n\n return `rgb(${r}, ${g}, ${b})`;\n}\n\nexport type EasingFunction = (t: number) => number;\n\nexport const easingFunctions: Record<string, EasingFunction> = {\n linear: (t) => t,\n 'ease-in': (t) => t * t,\n 'ease-out': (t) => t * (2 - t),\n 'ease-in-out': (t) => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t),\n};\n\nexport function calculateProgress(\n frame: number,\n startFrame: number,\n duration: number,\n easing: string = 'linear'\n): number {\n if (frame < startFrame) return 0;\n if (frame >= startFrame + duration) return 1;\n\n const rawProgress = (frame - startFrame) / duration;\n const easingFn = easingFunctions[easing] || easingFunctions.linear;\n return easingFn!(rawProgress);\n}\n","import type { LocaleCode } from '../font-system/types';\n\nconst CJK_REGEX = /[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\u3400-\\u4dbf\\uac00-\\ud7af]/g;\n\nexport function needsSpaceBetweenWords(locale: LocaleCode | string, text?: string): boolean {\n if (text) {\n const cjkMatches = text.match(CJK_REGEX);\n const cjkCount = cjkMatches ? cjkMatches.length : 0;\n\n if (cjkCount > 0 && cjkCount / text.length >= 0.6) {\n return false;\n }\n return true;\n }\n\n return !['zh-CN', 'ja-JP', 'ko-KR'].includes(locale);\n}\n\nexport function detectLocaleFromText(text: string): LocaleCode {\n const cjkMatches = text.match(CJK_REGEX);\n const cjkCount = cjkMatches ? cjkMatches.length : 0;\n\n if (cjkCount > 0 && cjkCount / text.length >= 0.6) {\n const chineseCount = (text.match(/[\\u4e00-\\u9fff]/g) || []).length;\n const japaneseCount = (text.match(/[\\u3040-\\u309f\\u30a0-\\u30ff]/g) || []).length;\n const koreanCount = (text.match(/[\\uac00-\\ud7af]/g) || []).length;\n\n if (chineseCount >= japaneseCount && chineseCount >= koreanCount) {\n return 'zh-CN';\n }\n if (japaneseCount >= koreanCount) {\n return 'ja-JP';\n }\n return 'ko-KR';\n }\n\n const arabicCount = (text.match(/[\\u0600-\\u06FF]/g) || []).length;\n if (arabicCount > 0 && arabicCount / text.length >= 0.5) {\n return 'ar-SA';\n }\n\n return 'en-US';\n}\n","import type { TextLayer } from '../types';\nimport { wrapText, formEvenLinesWithWords } from '../text-utils/text-wrapper';\nimport { getLetterCaseText } from '../text-utils/text-metrics';\nimport { springEasing, interpolate } from './animation-utils';\nimport { needsSpaceBetweenWords } from '../text-utils/locale-detector';\n\nfunction calculateYPosition(\n canvasHeight: number,\n totalHeight: number,\n globalPosition?: {\n position?: 'absolute';\n top?: string;\n bottom?: string;\n left?: string;\n right?: string;\n display?: string;\n alignItems?: string;\n justifyContent?: string;\n }\n): number {\n if (!globalPosition) {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n // Handle percentage-based positioning\n if (globalPosition.top) {\n const topPercent = parseFloat(globalPosition.top) / 100;\n return canvasHeight * topPercent;\n }\n\n if (globalPosition.bottom) {\n const bottomPercent = parseFloat(globalPosition.bottom) / 100;\n return canvasHeight * (1 - bottomPercent) - totalHeight;\n }\n\n // Handle center alignment\n if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n // Default to center\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nexport function renderBasicText(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n _relativeFrame: number\n): void {\n const fontConfig = layer.fontConfig?.textStyle;\n if (!fontConfig) return;\n\n const fontSize = fontConfig.fontSize;\n const fontFamily = fontConfig.fontFamily;\n const fontWeight = fontConfig.fontWeight;\n const fill = fontConfig.fill;\n const stroke = fontConfig.stroke;\n const strokeWidth = fontConfig.strokeWidth || 0;\n const lineHeight = fontConfig.lineHeight || 1.2;\n\n const maxWidth = canvasWidth * 0.64;\n const text = getLetterCaseText(layer.text, layer.letterCase);\n\n let lines: string[];\n if (layer.wordTimings && layer.wordTimings.length > 0) {\n const needsSpace = needsSpaceBetweenWords(layer.localeCode || 'en-US', text);\n const words = text.split(needsSpace ? /\\s+/ : '');\n lines = formEvenLinesWithWords(\n ctx,\n words,\n maxWidth,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n );\n } else {\n lines = wrapText(ctx, text, maxWidth, fontSize, fontFamily, fontWeight);\n }\n\n ctx.save();\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.lineJoin = 'round';\n ctx.lineCap = 'round';\n\n const totalHeight = lines.length * fontSize * lineHeight;\n const startY = calculateYPosition(canvasHeight, totalHeight, layer.fontConfig?.globalPosition);\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const y = startY + i * fontSize * lineHeight + fontSize / 2;\n\n if (stroke && strokeWidth > 0) {\n ctx.strokeStyle = stroke;\n ctx.lineWidth = strokeWidth;\n ctx.strokeText(line, canvasWidth / 2, y);\n }\n ctx.fillStyle = fill;\n ctx.fillText(line, canvasWidth / 2, y);\n }\n\n ctx.restore();\n}\n\nexport function renderTextWithEntrance(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n relativeFrame: number\n): void {\n const fontConfig = layer.fontConfig?.textStyle;\n if (!fontConfig) return;\n\n const entrance = springEasing(relativeFrame, {\n damping: 200,\n mass: 1,\n stiffness: 300,\n });\n\n const opacity = interpolate(entrance, [0, 1], [0, 1]);\n const scale = interpolate(entrance, [0, 1], [0.9, 1]);\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.translate(canvasWidth / 2, canvasHeight / 2);\n ctx.scale(scale, scale);\n ctx.translate(-canvasWidth / 2, -canvasHeight / 2);\n\n renderBasicText(ctx, layer, canvasWidth, canvasHeight, relativeFrame);\n\n ctx.restore();\n}\n","import type { TextLayer } from '../types';\nimport { formEvenLinesWithWords } from '../text-utils/text-wrapper';\nimport { getLetterCaseText, measureTextWidth } from '../text-utils/text-metrics';\nimport { interpolate, interpolateColor } from './animation-utils';\nimport { needsSpaceBetweenWords } from '../text-utils/locale-detector';\n\ninterface WordPosition {\n text: string;\n x: number;\n y: number;\n lineIndex: number;\n wordIndex: number;\n timing?: { startFrame: number; endFrame: number };\n}\n\nfunction usToFrame(us: number, fps: number): number {\n return Math.floor(us / (1000000 / fps));\n}\n\nfunction calculateYPosition(\n canvasHeight: number,\n totalHeight: number,\n globalPosition?: {\n position?: 'absolute';\n top?: string;\n bottom?: string;\n left?: string;\n right?: string;\n display?: string;\n alignItems?: string;\n justifyContent?: string;\n }\n): number {\n if (!globalPosition) {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n if (globalPosition.top) {\n const topPercent = parseFloat(globalPosition.top) / 100;\n return canvasHeight * topPercent;\n }\n\n if (globalPosition.bottom) {\n const bottomPercent = parseFloat(globalPosition.bottom) / 100;\n return canvasHeight * (1 - bottomPercent) - totalHeight;\n }\n\n if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nexport function renderWordByWord(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n relativeFrame: number,\n fps: number = 30\n): void {\n const fontConfig = layer.fontConfig?.textStyle;\n if (!fontConfig) return;\n\n const fontSize = fontConfig.fontSize;\n const fontFamily = fontConfig.fontFamily;\n const fontWeight = fontConfig.fontWeight;\n const fill = fontConfig.fill;\n const stroke = fontConfig.stroke;\n const strokeWidth = fontConfig.strokeWidth || 0;\n const lineHeight = fontConfig.lineHeight || 1.2;\n\n const highlightFill = layer.animation?.highlightTextStyle?.fill || 'rgb(255, 215, 0)';\n const highlightStroke = layer.animation?.highlightTextStyle?.stroke || stroke;\n\n const maxWidth = canvasWidth * 0.64;\n const text = getLetterCaseText(layer.text, layer.letterCase);\n const needsSpace = needsSpaceBetweenWords(layer.localeCode || 'en-US', text);\n const words = text.split(needsSpace ? /\\s+/ : '');\n const lines = formEvenLinesWithWords(\n ctx,\n words,\n maxWidth,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n );\n\n const wordPositions: WordPosition[] = [];\n let wordIndex = 0;\n\n const totalHeight = lines.length * fontSize * lineHeight;\n const startY = calculateYPosition(canvasHeight, totalHeight, layer.fontConfig?.globalPosition);\n\n for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {\n const line = lines[lineIndex]!;\n const lineWords = line.split(needsSpace ? /\\s+/ : '');\n const y = startY + lineIndex * fontSize * lineHeight + fontSize / 2;\n\n const lineWidth = measureTextWidth(ctx, line, fontSize, fontFamily, fontWeight);\n let currentX = canvasWidth / 2 - lineWidth / 2;\n\n for (const word of lineWords) {\n const wordWidth = measureTextWidth(ctx, word, fontSize, fontFamily, fontWeight);\n const wordTimingUs = layer.wordTimings?.[wordIndex];\n\n const wordTiming = wordTimingUs\n ? {\n startFrame: usToFrame(wordTimingUs.startUs, fps),\n endFrame: usToFrame(wordTimingUs.endUs, fps),\n }\n : undefined;\n\n wordPositions.push({\n text: word,\n x: currentX + wordWidth / 2,\n y,\n lineIndex,\n wordIndex,\n timing: wordTiming,\n });\n\n currentX +=\n wordWidth + (needsSpace ? measureTextWidth(ctx, ' ', fontSize, fontFamily, fontWeight) : 0);\n wordIndex++;\n }\n }\n\n ctx.save();\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.lineJoin = 'round';\n ctx.lineCap = 'round';\n\n for (const wordPos of wordPositions) {\n let currentFill = fill;\n let currentStroke = stroke;\n\n if (wordPos.timing) {\n const { startFrame, endFrame } = wordPos.timing;\n\n if (relativeFrame >= startFrame && relativeFrame <= endFrame) {\n const transitionProgressIn = interpolate(\n relativeFrame,\n [startFrame, startFrame + 3],\n [0, 1],\n {\n extrapolateLeft: 'clamp',\n extrapolateRight: 'clamp',\n }\n );\n\n currentFill = interpolateColor(fill, highlightFill, transitionProgressIn);\n if (stroke && highlightStroke) {\n currentStroke = interpolateColor(stroke, highlightStroke, transitionProgressIn);\n }\n } else if (relativeFrame > endFrame) {\n const transitionProgressOut = interpolate(relativeFrame, [endFrame, endFrame + 3], [1, 0], {\n extrapolateLeft: 'clamp',\n extrapolateRight: 'clamp',\n });\n\n currentFill = interpolateColor(fill, highlightFill, transitionProgressOut);\n if (stroke && highlightStroke) {\n currentStroke = interpolateColor(stroke, highlightStroke, transitionProgressOut);\n }\n }\n }\n\n if (currentStroke && strokeWidth > 0) {\n ctx.strokeStyle = currentStroke;\n ctx.lineWidth = strokeWidth;\n ctx.strokeText(wordPos.text, wordPos.x, wordPos.y);\n }\n ctx.fillStyle = currentFill;\n ctx.fillText(wordPos.text, wordPos.x, wordPos.y);\n }\n\n ctx.restore();\n}\n","import type { TextLayer } from '../types';\nimport { wrapText } from '../text-utils/text-wrapper';\nimport { getLetterCaseText, measureTextWidth } from '../text-utils/text-metrics';\nimport { needsSpaceBetweenWords } from '../text-utils/locale-detector';\n\ninterface CharacterTiming {\n char: string;\n index: number;\n startFrame: number;\n}\n\nfunction usToFrame(us: number, fps: number): number {\n return Math.floor(us / (1000000 / fps));\n}\n\nfunction calculateYPosition(\n canvasHeight: number,\n totalHeight: number,\n globalPosition?: {\n position?: 'absolute';\n top?: string;\n bottom?: string;\n left?: string;\n right?: string;\n display?: string;\n alignItems?: string;\n justifyContent?: string;\n }\n): number {\n if (!globalPosition) {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n if (globalPosition.top) {\n const topPercent = parseFloat(globalPosition.top) / 100;\n return canvasHeight * topPercent;\n }\n\n if (globalPosition.bottom) {\n const bottomPercent = parseFloat(globalPosition.bottom) / 100;\n return canvasHeight * (1 - bottomPercent) - totalHeight;\n }\n\n if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nexport function renderCharacterKTV(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n relativeFrame: number,\n fps: number = 30\n): void {\n const fontConfig = layer.fontConfig?.textStyle;\n if (!fontConfig) return;\n\n const fontSize = fontConfig.fontSize;\n const fontFamily = fontConfig.fontFamily;\n const fontWeight = fontConfig.fontWeight;\n const baseFill = fontConfig.fill;\n const stroke = fontConfig.stroke;\n const strokeWidth = fontConfig.strokeWidth || 0;\n const lineHeight = fontConfig.lineHeight || 1.2;\n\n const highlightFill = layer.animation?.highlightTextStyle?.fill || 'rgb(255, 215, 0)';\n const glowColor = layer.animation?.glowColor || '#ffffff';\n const glowIntensity = layer.animation?.glowIntensity || 3;\n const transitionFrames = layer.animation?.transitionFrames || 10;\n\n const maxWidth = canvasWidth * 0.9;\n const text = getLetterCaseText(layer.text, layer.letterCase);\n const needsSpace = needsSpaceBetweenWords(layer.localeCode || 'en-US', text);\n const characterTimings: CharacterTiming[] = [];\n\n if (layer.wordTimings && layer.wordTimings.length > 0) {\n let charIndex = 0;\n\n for (let wordIndex = 0; wordIndex < layer.wordTimings.length; wordIndex++) {\n const word = layer.wordTimings[wordIndex]!;\n const wordChars = word.text.split('');\n const wordStartFrame = usToFrame(word.startUs, fps);\n const wordEndFrame = usToFrame(word.endUs, fps);\n const framesPerChar =\n wordChars.length > 0 ? (wordEndFrame - wordStartFrame) / wordChars.length : 0;\n\n for (let i = 0; i < wordChars.length; i++) {\n const charStartFrame = Math.floor(wordStartFrame + i * framesPerChar);\n characterTimings.push({\n char: wordChars[i]!,\n index: charIndex,\n startFrame: charStartFrame,\n });\n charIndex++;\n }\n\n if (needsSpace && wordIndex < layer.wordTimings.length - 1) {\n const nextWord = layer.wordTimings[wordIndex + 1];\n const nextWordFirstChar = nextWord?.text?.[0] || '';\n const isPunctuation = /[.,!?;:)]/.test(nextWordFirstChar);\n\n if (!isPunctuation) {\n const spaceStartFrame = characterTimings[characterTimings.length - 1]?.startFrame || 0;\n characterTimings.push({\n char: ' ',\n index: charIndex,\n startFrame: spaceStartFrame,\n });\n charIndex++;\n }\n }\n }\n } else {\n const totalFrames = 100;\n const chars = text.split('');\n const framesPerChar = chars.length > 0 ? totalFrames / chars.length : 0;\n\n for (let i = 0; i < chars.length; i++) {\n characterTimings.push({\n char: chars[i]!,\n index: i,\n startFrame: Math.floor(i * framesPerChar),\n });\n }\n }\n\n const fullText = characterTimings.map((ct) => ct.char).join('');\n const fullTextLines = wrapText(ctx, fullText, maxWidth, fontSize, fontFamily, fontWeight);\n\n ctx.save();\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.lineJoin = 'round';\n ctx.lineCap = 'round';\n\n const totalHeight = fullTextLines.length * fontSize * lineHeight;\n const startY = calculateYPosition(canvasHeight, totalHeight, layer.fontConfig?.globalPosition);\n\n let charIndexInText = 0;\n\n for (let lineIndex = 0; lineIndex < fullTextLines.length; lineIndex++) {\n const line = fullTextLines[lineIndex]!;\n const y = startY + lineIndex * fontSize * lineHeight + fontSize / 2;\n const lineWidth = measureTextWidth(ctx, line, fontSize, fontFamily, fontWeight);\n let currentX = canvasWidth / 2 - lineWidth / 2;\n\n for (let i = 0; i < line.length; i++) {\n const char = line[i]!;\n const timing = characterTimings[charIndexInText];\n\n if (timing) {\n const hasScanned = relativeFrame >= timing.startFrame;\n const isCurrentlySinging =\n hasScanned && relativeFrame < timing.startFrame + transitionFrames;\n\n ctx.fillStyle = hasScanned ? highlightFill : baseFill;\n\n if (isCurrentlySinging) {\n ctx.shadowColor = glowColor;\n ctx.shadowBlur = glowIntensity * 10;\n } else {\n ctx.shadowBlur = 0;\n }\n\n if (stroke && strokeWidth > 0) {\n ctx.strokeStyle = stroke;\n ctx.lineWidth = strokeWidth;\n ctx.strokeText(char, currentX, y);\n }\n ctx.fillText(char, currentX, y);\n ctx.shadowBlur = 0;\n }\n\n currentX += measureTextWidth(ctx, char, fontSize, fontFamily, fontWeight);\n charIndexInText++;\n }\n }\n\n ctx.restore();\n}\n","import type { TextLayer } from '../types';\nimport { formEvenLinesWithWords } from '../text-utils/text-wrapper';\nimport { getLetterCaseText, measureTextWidth } from '../text-utils/text-metrics';\nimport { springEasing, interpolate } from './animation-utils';\nimport { needsSpaceBetweenWords } from '../text-utils/locale-detector';\n\ninterface WordPosition {\n text: string;\n x: number;\n y: number;\n width: number;\n lineIndex: number;\n wordIndex: number;\n timing?: { startFrame: number; endFrame: number };\n}\n\nfunction usToFrame(us: number, fps: number): number {\n return Math.floor(us / (1000000 / fps));\n}\n\nfunction calculateYPosition(\n canvasHeight: number,\n totalHeight: number,\n globalPosition?: {\n position?: 'absolute';\n top?: string;\n bottom?: string;\n left?: string;\n right?: string;\n display?: string;\n alignItems?: string;\n justifyContent?: string;\n }\n): number {\n if (!globalPosition) {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n if (globalPosition.top) {\n const topPercent = parseFloat(globalPosition.top) / 100;\n return canvasHeight * topPercent;\n }\n\n if (globalPosition.bottom) {\n const bottomPercent = parseFloat(globalPosition.bottom) / 100;\n return canvasHeight * (1 - bottomPercent) - totalHeight;\n }\n\n if (globalPosition.justifyContent === 'center' || globalPosition.alignItems === 'center') {\n return canvasHeight / 2 - totalHeight / 2;\n }\n\n return canvasHeight / 2 - totalHeight / 2;\n}\n\nexport function renderWordByWordFancy(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n layer: TextLayer,\n canvasWidth: number,\n canvasHeight: number,\n relativeFrame: number,\n fps: number = 30\n): void {\n const fontConfig = layer.fontConfig?.textStyle;\n if (!fontConfig) return;\n\n const fontSize = fontConfig.fontSize;\n const fontFamily = fontConfig.fontFamily;\n const fontWeight = fontConfig.fontWeight;\n const fill = fontConfig.fill;\n const stroke = fontConfig.stroke;\n const strokeWidth = fontConfig.strokeWidth || 0;\n const lineHeight = fontConfig.lineHeight || 1.2;\n\n const highlightBackgroundColor = layer.animation?.highlightColor || 'rgb(255, 215, 0)';\n\n const maxWidth = canvasWidth * 0.64;\n const text = getLetterCaseText(layer.text, layer.letterCase);\n const needsSpace = needsSpaceBetweenWords(layer.localeCode || 'en-US', text);\n const words = text.split(needsSpace ? /\\s+/ : '');\n const lines = formEvenLinesWithWords(\n ctx,\n words,\n maxWidth,\n fontSize,\n needsSpace,\n fontFamily,\n fontWeight\n );\n\n const wordPositions: WordPosition[] = [];\n let wordIndex = 0;\n\n const totalHeight = lines.length * fontSize * lineHeight;\n const startY = calculateYPosition(canvasHeight, totalHeight, layer.fontConfig?.globalPosition);\n\n for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {\n const line = lines[lineIndex]!;\n const lineWords = line.split(needsSpace ? /\\s+/ : '');\n const y = startY + lineIndex * fontSize * lineHeight + fontSize / 2;\n\n const lineWidth = measureTextWidth(ctx, line, fontSize, fontFamily, fontWeight);\n let currentX = canvasWidth / 2 - lineWidth / 2;\n\n for (const word of lineWords) {\n const wordWidth = measureTextWidth(ctx, word, fontSize, fontFamily, fontWeight);\n const wordTimingUs = layer.wordTimings?.[wordIndex];\n\n const wordTiming = wordTimingUs\n ? {\n startFrame: usToFrame(wordTimingUs.startUs, fps),\n endFrame: usToFrame(wordTimingUs.endUs, fps),\n }\n : undefined;\n\n wordPositions.push({\n text: word,\n x: currentX + wordWidth / 2,\n y,\n width: wordWidth,\n lineIndex,\n wordIndex,\n timing: wordTiming,\n });\n\n currentX +=\n wordWidth + (needsSpace ? measureTextWidth(ctx, ' ', fontSize, fontFamily, fontWeight) : 0);\n wordIndex++;\n }\n }\n\n ctx.save();\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.lineJoin = 'round';\n ctx.lineCap = 'round';\n\n for (const wordPos of wordPositions) {\n let backgroundOpacity = 0;\n let backgroundScale = 0.8;\n\n if (wordPos.timing) {\n const { startFrame, endFrame } = wordPos.timing;\n const preStartFrames = 3;\n const isActive = relativeFrame >= startFrame && relativeFrame <= endFrame;\n\n if (isActive) {\n const scaleSpringIn = springEasing(relativeFrame - (startFrame - preStartFrames), {\n damping: 6,\n mass: 0.35,\n stiffness: 200,\n overshootClamping: false,\n });\n\n const inProgress = interpolate(relativeFrame, [startFrame, startFrame + 1], [0, 1], {\n extrapolateLeft: 'clamp',\n extrapolateRight: 'clamp',\n });\n\n backgroundOpacity = 0.9 * inProgress;\n backgroundScale = 0.8 + scaleSpringIn * 0.45;\n } else if (relativeFrame > endFrame) {\n backgroundOpacity = 0;\n backgroundScale = 0.8;\n }\n\n if (backgroundOpacity > 0) {\n const padding = 8;\n const bgWidth = (wordPos.width + padding * 2) * backgroundScale;\n const bgHeight = (fontSize + padding) * backgroundScale;\n\n ctx.save();\n ctx.globalAlpha = backgroundOpacity;\n ctx.fillStyle = highlightBackgroundColor;\n ctx.beginPath();\n ctx.roundRect(wordPos.x - bgWidth / 2, wordPos.y - bgHeight / 2, bgWidth, bgHeight, 8);\n ctx.fill();\n ctx.restore();\n }\n }\n\n if (stroke && strokeWidth > 0) {\n ctx.strokeStyle = stroke;\n ctx.lineWidth = strokeWidth;\n ctx.strokeText(wordPos.text, wordPos.x, wordPos.y);\n }\n ctx.fillStyle = fill;\n ctx.fillText(wordPos.text, wordPos.x, wordPos.y);\n }\n\n ctx.restore();\n}\n","import type { Layer, VideoLayer, ImageLayer, TextLayer, Transform2D, MaskConfig } from './types';\nimport { renderBasicText, renderTextWithEntrance } from './text-renderers/basic-text-renderer';\nimport { renderWordByWord } from './text-renderers/word-by-word-renderer';\nimport { renderCharacterKTV } from './text-renderers/character-ktv-renderer';\nimport { renderWordByWordFancy } from './text-renderers/word-fancy-renderer';\n\n/**\n * LayerRenderer - Handles rendering of individual layers\n * Single responsibility: Draw a single layer to the canvas context\n */\nexport class LayerRenderer {\n private ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D;\n private width: number;\n private height: number;\n private currentFrame: number = 0;\n private fps: number = 30;\n private readonly FILL_THRESHOLD = 0.9;\n\n constructor(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n width: number,\n height: number,\n fps: number = 30\n ) {\n this.ctx = ctx;\n this.width = width;\n this.height = height;\n this.fps = fps;\n this.ensureHighQualityRendering();\n }\n\n setCurrentFrame(frame: number): void {\n this.currentFrame = frame;\n }\n\n private ensureHighQualityRendering(): void {\n this.ctx.imageSmoothingEnabled = true;\n this.ctx.imageSmoothingQuality = 'high';\n }\n\n /**\n * Render a single layer with all its properties\n */\n async renderLayer(layer: Layer): Promise<void> {\n if (!layer.visible || layer.opacity <= 0) return;\n\n this.ctx.save();\n\n try {\n this.ensureHighQualityRendering();\n\n // Apply layer properties\n this.ctx.globalAlpha = layer.opacity;\n\n if (layer.blendMode) {\n this.ctx.globalCompositeOperation = layer.blendMode;\n }\n\n if (layer.transform) {\n // Get layer dimensions for transform anchor calculation\n const layerDimensions = this.getLayerDimensions(layer);\n this.applyTransform(layer.transform, layerDimensions);\n }\n // Render based on layer type\n switch (layer.type) {\n case 'video':\n await this.renderVideoLayer(layer as VideoLayer);\n break;\n case 'image':\n await this.renderImageLayer(layer as ImageLayer);\n break;\n case 'text':\n await this.renderTextLayer(layer as TextLayer);\n break;\n }\n\n // Apply mask if present\n if (layer.mask) {\n this.applyMask(layer.mask);\n }\n } finally {\n this.ctx.restore();\n }\n }\n\n private parseDimension(\n value: number | string | undefined,\n canvasSize: number\n ): number | undefined {\n if (value === undefined) return undefined;\n if (typeof value === 'number') return value;\n\n // value is string at this point\n const strValue = value as string;\n\n // Parse percentage string like \"5%\"\n if (strValue.includes('%')) {\n const numValue = parseFloat(strValue);\n return isNaN(numValue) ? undefined : (numValue / 100) * canvasSize;\n }\n\n // Parse as pixel value\n const parsed = parseFloat(strValue);\n return isNaN(parsed) ? undefined : parsed;\n }\n\n private getLayerDimensions(layer: Layer): { width: number; height: number } {\n if (layer.type === 'image') {\n const imageLayer = layer as ImageLayer;\n if (imageLayer.source) {\n const imgWidth = imageLayer.source.width;\n const imgHeight = imageLayer.source.height;\n\n // For attachment layers with target dimensions, calculate rendered size\n const isAttachment = !!imageLayer.attachmentId;\n if (isAttachment) {\n const targetWidthRaw = (imageLayer as any).targetWidth;\n const targetHeightRaw = (imageLayer as any).targetHeight;\n\n // Parse dimensions (supports both pixels and percentages)\n const targetWidth = this.parseDimension(targetWidthRaw, this.width);\n const targetHeight = this.parseDimension(targetHeightRaw, this.height);\n\n if (targetWidth && targetHeight) {\n return { width: targetWidth, height: targetHeight };\n } else if (targetWidth) {\n return {\n width: targetWidth,\n height: (imgHeight / imgWidth) * targetWidth,\n };\n } else if (targetHeight) {\n return {\n width: (imgWidth / imgHeight) * targetHeight,\n height: targetHeight,\n };\n }\n }\n\n // No scaling, return original dimensions\n return { width: imgWidth, height: imgHeight };\n }\n } else if (layer.type === 'video') {\n const videoLayer = layer as VideoLayer;\n const videoFrame = videoLayer.videoFrame;\n return {\n width: videoFrame.displayWidth || videoFrame.codedWidth,\n height: videoFrame.displayHeight || videoFrame.codedHeight,\n };\n }\n // Default to canvas dimensions\n return { width: this.width, height: this.height };\n }\n\n /**\n * Calculate render dimensions with smart fill logic\n * @param sourceWidth Source width\n * @param sourceHeight Source height\n * @param naturalScale Natural scale factor (scaleY for video, scaleX for image)\n * @returns Render dimensions and position\n */\n private calculateRenderDimensions(\n sourceWidth: number,\n sourceHeight: number,\n naturalScale: number\n ): { width: number; height: number; x: number; y: number } {\n const scaledWidth = sourceWidth * naturalScale;\n const scaledHeight = sourceHeight * naturalScale;\n\n // Smart fill: when scaled size is close to container (>90%), use cover mode\n const shouldFill =\n scaledWidth / this.width > this.FILL_THRESHOLD &&\n scaledHeight / this.height > this.FILL_THRESHOLD;\n\n let renderWidth: number;\n let renderHeight: number;\n\n if (shouldFill) {\n // Cover mode: use Math.max to ensure entire canvas is covered while maintaining aspect ratio\n const coverScale = Math.max(this.width / sourceWidth, this.height / sourceHeight);\n renderWidth = Math.round(sourceWidth * coverScale);\n renderHeight = Math.round(sourceHeight * coverScale);\n } else {\n // Natural scale mode: use scaled dimensions\n renderWidth = Math.round(scaledWidth);\n renderHeight = Math.round(scaledHeight);\n }\n\n // Center the content\n const renderX = Math.round((this.width - renderWidth) / 2);\n const renderY = Math.round((this.height - renderHeight) / 2);\n\n return { width: renderWidth, height: renderHeight, x: renderX, y: renderY };\n }\n\n private applyTransform(\n transform: Transform2D,\n layerDimensions: { width: number; height: number }\n ): void {\n // Use layer dimensions (not canvas dimensions) for anchor calculation\n const anchorX = transform.anchorX ?? 0.5;\n const anchorY = transform.anchorY ?? 0.5;\n const centerX = layerDimensions.width * anchorX;\n const centerY = layerDimensions.height * anchorY;\n\n // Move to the layer position + anchor offset\n this.ctx.translate(transform.x + centerX, transform.y + centerY);\n\n if (transform.rotation) {\n this.ctx.rotate(transform.rotation);\n }\n\n this.ctx.scale(transform.scaleX, transform.scaleY);\n\n if (transform.skewX || transform.skewY) {\n this.ctx.transform(1, transform.skewY ?? 0, transform.skewX ?? 0, 1, 0, 0);\n }\n\n // Move back by anchor offset\n this.ctx.translate(-centerX, -centerY);\n }\n\n private async renderVideoLayer(layer: VideoLayer): Promise<void> {\n const { videoFrame, crop } = layer;\n\n // Get video dimensions\n const videoWidth = videoFrame.displayWidth || videoFrame.codedWidth;\n const videoHeight = videoFrame.displayHeight || videoFrame.codedHeight;\n\n // Video uses scaleY (height-based scaling) to match legacy behavior\n const naturalScale = this.height / videoHeight;\n const dimensions = this.calculateRenderDimensions(videoWidth, videoHeight, naturalScale);\n\n if (crop) {\n this.ctx.drawImage(\n videoFrame,\n crop.x,\n crop.y,\n crop.width,\n crop.height,\n dimensions.x,\n dimensions.y,\n dimensions.width,\n dimensions.height\n );\n } else {\n this.ctx.drawImage(\n videoFrame,\n dimensions.x,\n dimensions.y,\n dimensions.width,\n dimensions.height\n );\n }\n videoFrame.close();\n }\n\n private async renderImageLayer(layer: ImageLayer): Promise<void> {\n const { source, crop } = layer;\n\n // Handle ImageData by putting it on canvas first\n if (source instanceof ImageData) {\n if (crop) {\n // For ImageData with crop, we need to extract the cropped region\n const tempCanvas = new OffscreenCanvas(crop.width, crop.height);\n const tempCtx = tempCanvas.getContext('2d')!;\n tempCtx.putImageData(source, -crop.x, -crop.y);\n this.ctx.drawImage(tempCanvas, 0, 0, this.width, this.height);\n } else {\n // Put ImageData directly\n this.ctx.putImageData(source, 0, 0);\n }\n } else {\n // ImageBitmap can be drawn directly\n if (!source) {\n return;\n }\n\n // Determine if this is an attachment layer (has attachmentId)\n const isAttachment = !!layer.attachmentId;\n const imgWidth = source.width;\n const imgHeight = source.height;\n\n let renderWidth: number;\n let renderHeight: number;\n\n if (isAttachment) {\n // Attachment images use original size (or targetWidth/targetHeight if specified)\n const targetWidthRaw = (layer as any).targetWidth;\n const targetHeightRaw = (layer as any).targetHeight;\n\n // Parse dimensions (supports both pixels and percentages)\n const targetWidth = this.parseDimension(targetWidthRaw, this.width);\n const targetHeight = this.parseDimension(targetHeightRaw, this.height);\n\n if (targetWidth && targetHeight) {\n // Both specified, use as-is\n renderWidth = targetWidth;\n renderHeight = targetHeight;\n } else if (targetWidth) {\n // Only width specified, maintain aspect ratio\n renderWidth = targetWidth;\n renderHeight = (imgHeight / imgWidth) * targetWidth;\n } else if (targetHeight) {\n // Only height specified, maintain aspect ratio\n renderHeight = targetHeight;\n renderWidth = (imgWidth / imgHeight) * targetHeight;\n } else {\n // No target size, use original\n renderWidth = imgWidth;\n renderHeight = imgHeight;\n }\n } else {\n // Main track images use scaleX (width-based scaling) to match legacy behavior\n const naturalScale = this.width / imgWidth;\n const dimensions = this.calculateRenderDimensions(imgWidth, imgHeight, naturalScale);\n renderWidth = dimensions.width;\n renderHeight = dimensions.height;\n }\n\n // Calculate render position (center for main track images, origin for attachments)\n const renderX = isAttachment ? 0 : Math.round((this.width - renderWidth) / 2);\n const renderY = isAttachment ? 0 : Math.round((this.height - renderHeight) / 2);\n\n if (crop) {\n this.ctx.drawImage(\n source,\n crop.x,\n crop.y,\n crop.width,\n crop.height,\n renderX,\n renderY,\n renderWidth,\n renderHeight\n );\n } else {\n this.ctx.drawImage(source, renderX, renderY, renderWidth, renderHeight);\n }\n }\n }\n\n private async renderTextLayer(layer: TextLayer): Promise<void> {\n const animationType = layer.animation?.type;\n const hasWordTimings = layer.wordTimings && layer.wordTimings.length > 0;\n\n const needsWordTimings = ['wordByWord', 'characterKTV', 'wordByWordFancy'].includes(\n animationType || ''\n );\n\n if (needsWordTimings && !hasWordTimings) {\n renderBasicText(this.ctx, layer, this.width, this.height, this.currentFrame);\n return;\n }\n\n switch (animationType) {\n case 'wordByWord':\n renderWordByWord(this.ctx, layer, this.width, this.height, this.currentFrame, this.fps);\n break;\n case 'characterKTV':\n renderCharacterKTV(this.ctx, layer, this.width, this.height, this.currentFrame, this.fps);\n break;\n case 'wordByWordFancy':\n renderWordByWordFancy(\n this.ctx,\n layer,\n this.width,\n this.height,\n this.currentFrame,\n this.fps\n );\n break;\n case 'fade':\n renderTextWithEntrance(this.ctx, layer, this.width, this.height, this.currentFrame);\n break;\n default:\n renderBasicText(this.ctx, layer, this.width, this.height, this.currentFrame);\n break;\n }\n }\n\n private applyMask(mask: MaskConfig): void {\n this.ctx.globalCompositeOperation = mask.invert ? 'source-out' : 'destination-in';\n\n if (mask.source) {\n this.ctx.drawImage(mask.source, 0, 0, this.width, this.height);\n } else if (mask.shape === 'circle') {\n this.ctx.beginPath();\n this.ctx.arc(\n this.width / 2,\n this.height / 2,\n Math.min(this.width, this.height) / 2,\n 0,\n Math.PI * 2\n );\n this.ctx.fill();\n }\n }\n\n updateDimensions(width: number, height: number): void {\n this.width = width;\n this.height = height;\n this.ensureHighQualityRendering();\n }\n}\n","import type { TransitionEffect } from './types';\n\n/**\n * TransitionProcessor - Handles transition effects between frames/scenes\n * Single responsibility: Apply transition transformations to canvas context\n */\nexport class TransitionProcessor {\n private width: number;\n private height: number;\n\n constructor(width: number, height: number) {\n this.width = width;\n this.height = height;\n }\n\n /**\n * Apply transition effect to the canvas context\n * Returns true if transition was applied, false if not needed\n */\n applyTransition(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n transition: TransitionEffect\n ): boolean {\n if (!transition || transition.progress <= 0) return false;\n\n const progress = this.calculateEasedProgress(transition.progress, transition.easing);\n\n switch (transition.type) {\n case 'fade':\n return this.applyFade(ctx, progress);\n case 'slide':\n return this.applySlide(ctx, progress, transition.direction);\n case 'wipe':\n return this.applyWipe(ctx, progress, transition.direction);\n case 'zoom':\n return this.applyZoom(ctx, progress, transition.direction);\n case 'rotate':\n return this.applyRotate(ctx, progress);\n case 'dissolve':\n return this.applyDissolve(ctx, progress);\n default:\n return false;\n }\n }\n\n private calculateEasedProgress(\n progress: number,\n easing?: 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out'\n ): number {\n switch (easing) {\n case 'ease-in':\n return progress * progress;\n case 'ease-out':\n return 1 - (1 - progress) * (1 - progress);\n case 'ease-in-out':\n return progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2;\n default:\n return progress;\n }\n }\n\n private applyFade(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n progress: number\n ): boolean {\n ctx.globalAlpha = progress;\n return true;\n }\n\n private applySlide(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n progress: number,\n direction?: 'left' | 'right' | 'up' | 'down' | 'in' | 'out'\n ): boolean {\n const distance = 1 - progress;\n\n switch (direction) {\n case 'left':\n ctx.translate(-this.width * distance, 0);\n break;\n case 'right':\n ctx.translate(this.width * distance, 0);\n break;\n case 'up':\n ctx.translate(0, -this.height * distance);\n break;\n case 'down':\n ctx.translate(0, this.height * distance);\n break;\n default:\n ctx.translate(-this.width * distance, 0);\n }\n\n return true;\n }\n\n private applyWipe(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n progress: number,\n direction?: 'left' | 'right' | 'up' | 'down' | 'in' | 'out'\n ): boolean {\n ctx.save();\n ctx.beginPath();\n\n switch (direction) {\n case 'left':\n ctx.rect(0, 0, this.width * progress, this.height);\n break;\n case 'right':\n ctx.rect(this.width * (1 - progress), 0, this.width * progress, this.height);\n break;\n case 'up':\n ctx.rect(0, 0, this.width, this.height * progress);\n break;\n case 'down':\n ctx.rect(0, this.height * (1 - progress), this.width, this.height * progress);\n break;\n default:\n ctx.rect(0, 0, this.width * progress, this.height);\n }\n\n ctx.clip();\n return true;\n }\n\n private applyZoom(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n progress: number,\n direction?: 'left' | 'right' | 'up' | 'down' | 'in' | 'out'\n ): boolean {\n const scale = direction === 'out' ? 1 + (1 - progress) : progress;\n const centerX = this.width / 2;\n const centerY = this.height / 2;\n\n ctx.translate(centerX, centerY);\n ctx.scale(scale, scale);\n ctx.translate(-centerX, -centerY);\n\n if (direction === 'out') {\n ctx.globalAlpha = progress;\n }\n\n return true;\n }\n\n private applyRotate(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n progress: number\n ): boolean {\n const rotation = (1 - progress) * Math.PI * 2;\n const centerX = this.width / 2;\n const centerY = this.height / 2;\n\n ctx.translate(centerX, centerY);\n ctx.rotate(rotation);\n ctx.translate(-centerX, -centerY);\n\n return true;\n }\n\n private applyDissolve(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n progress: number\n ): boolean {\n // Simple dissolve using alpha\n ctx.globalAlpha = progress;\n ctx.globalCompositeOperation = 'multiply';\n return true;\n }\n\n /**\n * Create a transition mask for advanced effects\n */\n createTransitionMask(transition: TransitionEffect, canvas: OffscreenCanvas): ImageData | null {\n const ctx = canvas.getContext('2d');\n if (!ctx) return null;\n\n const imageData = ctx.createImageData(this.width, this.height);\n const data = imageData.data;\n const progress = this.calculateEasedProgress(transition.progress, transition.easing);\n\n // Generate gradient mask based on transition type\n for (let y = 0; y < this.height; y++) {\n for (let x = 0; x < this.width; x++) {\n const index = (y * this.width + x) * 4;\n let alpha = 255;\n\n switch (transition.type) {\n case 'wipe':\n alpha = this.calculateWipeAlpha(x, y, progress, transition.direction);\n break;\n case 'dissolve':\n // Random noise dissolve\n alpha = Math.random() < progress ? 255 : 0;\n break;\n default:\n alpha = Math.floor(255 * progress);\n }\n\n data[index] = 255; // R\n data[index + 1] = 255; // G\n data[index + 2] = 255; // B\n data[index + 3] = alpha; // A\n }\n }\n\n return imageData;\n }\n\n private calculateWipeAlpha(\n x: number,\n y: number,\n progress: number,\n direction?: 'left' | 'right' | 'up' | 'down' | 'in' | 'out'\n ): number {\n let position = 0;\n\n switch (direction) {\n case 'left':\n position = x / this.width;\n break;\n case 'right':\n position = 1 - x / this.width;\n break;\n case 'up':\n position = y / this.height;\n break;\n case 'down':\n position = 1 - y / this.height;\n break;\n case 'in': {\n // Radial wipe from center\n const cx = x - this.width / 2;\n const cy = y - this.height / 2;\n const maxDist = Math.sqrt(this.width * this.width + this.height * this.height) / 2;\n position = Math.sqrt(cx * cx + cy * cy) / maxDist;\n break;\n }\n case 'out': {\n // Radial wipe to center\n const cx2 = x - this.width / 2;\n const cy2 = y - this.height / 2;\n const maxDist2 = Math.sqrt(this.width * this.width + this.height * this.height) / 2;\n position = 1 - Math.sqrt(cx2 * cx2 + cy2 * cy2) / maxDist2;\n break;\n }\n default:\n position = x / this.width;\n }\n\n return position < progress ? 255 : 0;\n }\n\n updateDimensions(width: number, height: number): void {\n this.width = width;\n this.height = height;\n }\n}\n","import type { VisualFilter } from './types';\n\n/**\n * FilterProcessor - Handles visual filters and effects\n * Single responsibility: Apply CSS filters and custom shader effects\n */\nexport class FilterProcessor {\n private filterCache = new Map<string, string>();\n\n /**\n * Apply filters to canvas context\n * Combines multiple filters into a single CSS filter string for performance\n */\n applyFilters(\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n filters: VisualFilter[]\n ): void {\n if (!filters || filters.length === 0) {\n ctx.filter = 'none';\n return;\n }\n\n // Generate cache key\n const cacheKey = this.generateCacheKey(filters);\n\n // Check cache\n let filterString = this.filterCache.get(cacheKey);\n\n if (!filterString) {\n filterString = this.buildFilterString(filters);\n this.filterCache.set(cacheKey, filterString);\n }\n\n ctx.filter = filterString;\n }\n\n /**\n * Build CSS filter string from filter array\n */\n private buildFilterString(filters: VisualFilter[]): string {\n const filterStrings: string[] = [];\n\n for (const filter of filters) {\n const filterStr = this.buildSingleFilter(filter);\n if (filterStr) {\n filterStrings.push(filterStr);\n }\n }\n\n return filterStrings.length > 0 ? filterStrings.join(' ') : 'none';\n }\n\n private buildSingleFilter(filter: VisualFilter): string | null {\n switch (filter.type) {\n case 'blur':\n return `blur(${filter.value ?? 0}px)`;\n\n case 'brightness':\n return `brightness(${filter.value ?? 1})`;\n\n case 'contrast':\n return `contrast(${filter.value ?? 1})`;\n\n case 'grayscale':\n return `grayscale(${filter.value ?? 0})`;\n\n case 'hue-rotate':\n return `hue-rotate(${filter.value ?? 0}deg)`;\n\n case 'saturate':\n return `saturate(${filter.value ?? 1})`;\n\n case 'sepia':\n return `sepia(${filter.value ?? 0})`;\n\n case 'custom':\n return this.buildCustomFilter(filter);\n\n default:\n console.warn(`Unknown filter type: ${filter.type}`);\n return null;\n }\n }\n\n /**\n * Build custom filter from params\n */\n private buildCustomFilter(filter: VisualFilter): string | null {\n if (!filter.params) return null;\n\n const { type, ...params } = filter.params;\n\n switch (type) {\n case 'drop-shadow':\n return `drop-shadow(${params.offsetX}px ${params.offsetY}px ${params.blur}px ${params.color})`;\n\n case 'opacity':\n return `opacity(${params.value})`;\n\n case 'invert':\n return `invert(${params.value})`;\n\n default:\n return null;\n }\n }\n\n /**\n * Apply color matrix transformation for advanced effects\n * This allows for more complex color manipulations than CSS filters\n */\n applyColorMatrix(imageData: ImageData, matrix: number[]): ImageData {\n if (matrix.length !== 20) {\n throw new Error('Color matrix must have 20 values (4x5 matrix)');\n }\n\n const data = imageData.data;\n const length = data.length;\n\n for (let i = 0; i < length; i += 4) {\n const r = data[i]!;\n const g = data[i + 1]!;\n const b = data[i + 2]!;\n const a = data[i + 3]!;\n const m = matrix;\n\n // Apply matrix transformation\n data[i] = this.clamp(r * m[0]! + g * m[1]! + b * m[2]! + a * m[3]! + m[4]! * 255);\n data[i + 1] = this.clamp(r * m[5]! + g * m[6]! + b * m[7]! + a * m[8]! + m[9]! * 255);\n data[i + 2] = this.clamp(r * m[10]! + g * m[11]! + b * m[12]! + a * m[13]! + m[14]! * 255);\n data[i + 3] = this.clamp(r * m[15]! + g * m[16]! + b * m[17]! + a * m[18]! + m[19]! * 255);\n }\n\n return imageData;\n }\n\n /**\n * Predefined color matrices for common effects\n */\n getPresetMatrix(preset: string): number[] | null {\n switch (preset) {\n case 'vintage':\n return [\n 0.393, 0.769, 0.189, 0, 0, 0.349, 0.686, 0.168, 0, 0, 0.272, 0.534, 0.131, 0, 0, 0, 0, 0,\n 1, 0,\n ];\n\n case 'noir':\n return [\n 0.25, 0.25, 0.25, 0, 0, 0.25, 0.25, 0.25, 0, 0, 0.25, 0.25, 0.25, 0, 0, 0, 0, 0, 1, 0,\n ];\n\n case 'cool':\n return [0.8, 0, 0, 0, 0, 0, 0.9, 0, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1, 0];\n\n case 'warm':\n return [1.2, 0, 0, 0, 0, 0, 1.1, 0, 0, 0, 0, 0, 0.8, 0, 0, 0, 0, 0, 1, 0];\n\n default:\n return null;\n }\n }\n\n /**\n * Apply Gaussian blur manually (for cases where CSS filter is not enough)\n */\n applyGaussianBlur(imageData: ImageData, radius: number): ImageData {\n // Simplified box blur approximation of Gaussian blur\n const output = new ImageData(\n new Uint8ClampedArray(imageData.data),\n imageData.width,\n imageData.height\n );\n\n const width = imageData.width;\n const height = imageData.height;\n const data = imageData.data;\n const outData = output.data;\n\n // Horizontal pass\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n let r = 0,\n g = 0,\n b = 0,\n a = 0;\n let count = 0;\n\n for (let dx = -radius; dx <= radius; dx++) {\n const nx = Math.min(Math.max(x + dx, 0), width - 1);\n const idx = (y * width + nx) * 4;\n r += data[idx]!;\n g += data[idx + 1]!;\n b += data[idx + 2]!;\n a += data[idx + 3]!;\n count++;\n }\n\n const idx = (y * width + x) * 4;\n outData[idx] = r / count;\n outData[idx + 1] = g / count;\n outData[idx + 2] = b / count;\n outData[idx + 3] = a / count;\n }\n }\n\n // Vertical pass\n for (let x = 0; x < width; x++) {\n for (let y = 0; y < height; y++) {\n let r = 0,\n g = 0,\n b = 0,\n a = 0;\n let count = 0;\n\n for (let dy = -radius; dy <= radius; dy++) {\n const ny = Math.min(Math.max(y + dy, 0), height - 1);\n const idx = (ny * width + x) * 4;\n r += outData[idx]!;\n g += outData[idx + 1]!;\n b += outData[idx + 2]!;\n a += outData[idx + 3]!;\n count++;\n }\n\n const idx = (y * width + x) * 4;\n data[idx] = r / count;\n data[idx + 1] = g / count;\n data[idx + 2] = b / count;\n data[idx + 3] = a / count;\n }\n }\n\n return imageData;\n }\n\n private clamp(value: number): number {\n return Math.min(255, Math.max(0, Math.round(value)));\n }\n\n private generateCacheKey(filters: VisualFilter[]): string {\n return filters.map((f) => `${f.type}:${f.value ?? 'default'}`).join('|');\n }\n\n clearCache(): void {\n this.filterCache.clear();\n }\n\n getCacheSize(): number {\n return this.filterCache.size;\n }\n}\n","import type {\n VideoComposeConfig,\n ComposeRequest,\n ComposeResult,\n TransitionEffect,\n VideoLayer,\n Layer,\n} from './types';\nimport { LayerRenderer } from './LayerRenderer';\nimport { TransitionProcessor } from './TransitionProcessor';\nimport { FilterProcessor } from './FilterProcessor';\nimport { ClipInstructionSet } from './instructions';\n\nconst closeLayerFrame = (layer: Layer) => {\n if ((layer as any).type === 'video') {\n // If layer has videoFrame, close it\n const vf = (layer as VideoLayer).videoFrame;\n if (vf?.close) {\n vf.close();\n }\n // RcFrame should not be closed here as it's managed by CacheManager\n }\n};\n\n/**\n * VideoComposer - Main visual composition orchestrator\n */\nexport class VideoComposer {\n readonly config: Omit<Required<VideoComposeConfig>, 'externalCanvas'> & {\n externalCanvas?: HTMLCanvasElement | OffscreenCanvas;\n };\n readonly canvas: OffscreenCanvas | HTMLCanvasElement;\n\n private ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D;\n private layerRenderer: LayerRenderer;\n private transitionProcessor: TransitionProcessor;\n private filterProcessor: FilterProcessor;\n private frameDurationUs: number; // Cached frame duration\n private fontsLoadingPromise: Promise<void> | null = null;\n private loadedFonts = new Set<string>();\n\n constructor(config: VideoComposeConfig) {\n this.config = this.applyDefaults(config);\n this.frameDurationUs = Math.round(1_000_000 / this.config.fps); // Pre-calculate\n\n if (config.externalCanvas) {\n this.canvas = config.externalCanvas;\n\n // FIX: Ensure external canvas dimensions match the config\n if (this.canvas.width !== this.config.width || this.canvas.height !== this.config.height) {\n this.canvas.width = this.config.width;\n this.canvas.height = this.config.height;\n }\n\n this.ctx = this.canvas.getContext('2d', {\n alpha: true,\n desynchronized: true,\n willReadFrequently: false,\n colorSpace: 'srgb',\n }) as CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n } else {\n this.canvas = new OffscreenCanvas(this.config.width, this.config.height);\n this.ctx = this.canvas.getContext('2d', {\n alpha: true,\n desynchronized: true,\n willReadFrequently: false,\n colorSpace: 'srgb',\n }) as OffscreenCanvasRenderingContext2D;\n }\n\n if (!this.ctx) {\n throw new Error('Failed to create 2D rendering context');\n }\n\n this.ctx.imageSmoothingEnabled = this.config.enableSmoothing;\n\n // Start loading fonts but don't block constructor\n this.fontsLoadingPromise = this.loadFonts();\n this.ctx.imageSmoothingQuality = 'high';\n\n this.layerRenderer = new LayerRenderer(\n this.ctx,\n this.config.width,\n this.config.height,\n this.config.fps\n );\n this.transitionProcessor = new TransitionProcessor(this.config.width, this.config.height);\n this.filterProcessor = new FilterProcessor();\n }\n\n private applyDefaults(config: VideoComposeConfig): Omit<\n Required<VideoComposeConfig>,\n 'externalCanvas'\n > & {\n externalCanvas?: HTMLCanvasElement | OffscreenCanvas;\n } {\n return {\n width: config.width || 720,\n height: config.height || 1280,\n fps: config.fps || 30,\n backgroundColor: config.backgroundColor ?? '#000',\n renderer: config.renderer ?? 'canvas2d',\n enableSmoothing: config.enableSmoothing ?? true,\n enableHardwareAcceleration: config.enableHardwareAcceleration ?? true,\n revision: config.revision ?? 0,\n inputHighWaterMark: config.inputHighWaterMark ?? 3,\n outputHighWaterMark: config.outputHighWaterMark ?? 1,\n maxLayers: config.maxLayers ?? 100,\n timeline: config.timeline ?? {\n clipId: 'default',\n trackId: 'main',\n clipStartUs: 0,\n clipDurationUs: Infinity,\n compositionFps: 30,\n },\n fonts: config.fonts ?? [],\n externalCanvas: config.externalCanvas,\n };\n }\n\n createStreams(_instruction?: ClipInstructionSet): TransformStream<ComposeRequest, VideoFrame> {\n // Always create new streams for each clip\n // ReadableStreams can only be consumed once\n const stream = new TransformStream<ComposeRequest, VideoFrame>(\n {\n transform: async (request, controller) => {\n // console.log('[VideoComposer] transform', request, controller.desiredSize);\n const result = await this.composeFrame(request);\n if (result.frame) {\n controller.enqueue(result.frame);\n }\n // setTimeout(() => {\n // result.frame.close();\n // }, 1000);\n },\n\n flush: async () => {\n this.filterProcessor.clearCache();\n },\n },\n {\n highWaterMark: this.config.inputHighWaterMark,\n },\n {\n highWaterMark: this.config.outputHighWaterMark,\n }\n );\n return stream;\n }\n async composeFrame(request: ComposeRequest): Promise<ComposeResult> {\n // Ensure fonts are loaded before rendering\n if (this.fontsLoadingPromise) {\n await this.fontsLoadingPromise;\n this.fontsLoadingPromise = null; // Only wait once\n }\n\n if (request.layers.length > this.config.maxLayers) {\n throw new Error(`Too many layers: ${request.layers.length} > ${this.config.maxLayers}`);\n }\n\n this.clearCanvas();\n\n // Calculate current frame number for animations (relative to clip start)\n const frameDurationUs = 1_000_000 / this.config.fps;\n const relativeFrame = Math.floor(request.timeUs / frameDurationUs);\n this.layerRenderer.setCurrentFrame(relativeFrame);\n\n if (request.transition) {\n this.ctx.save();\n this.transitionProcessor.applyTransition(this.ctx, request.transition);\n }\n\n for (const layer of request.layers) {\n if (!layer.visible || layer.opacity <= 0) {\n // Close video frame for invisible layers\n closeLayerFrame(layer);\n continue;\n }\n\n try {\n // If layer has RcFrame, use it within the rendering scope\n if ((layer as any).rcFrame) {\n await (layer as any).rcFrame.use(async (frame: VideoFrame) => {\n // Set the cloned frame for this render cycle\n (layer as VideoLayer).videoFrame = frame;\n\n if (layer.filters && layer.filters.length > 0) {\n this.ctx.save();\n this.filterProcessor.applyFilters(this.ctx, layer.filters);\n }\n await this.layerRenderer.renderLayer(layer);\n\n if (layer.filters && layer.filters.length > 0) {\n this.ctx.restore();\n }\n });\n } else {\n // Regular layer without RcFrame\n if (layer.filters && layer.filters.length > 0) {\n this.ctx.save();\n this.filterProcessor.applyFilters(this.ctx, layer.filters);\n }\n await this.layerRenderer.renderLayer(layer);\n\n if (layer.filters && layer.filters.length > 0) {\n this.ctx.restore();\n }\n }\n } catch (error) {\n console.error('[VideoComposer] composeFrame error: ', error);\n // Always close video frame after rendering (or on error)\n closeLayerFrame(layer);\n }\n }\n\n if (request.transition) {\n this.ctx.restore();\n }\n\n let frame: VideoFrame | null = null;\n if (!this.config.externalCanvas) {\n frame = await this.createOutputFrame(request.timeUs);\n }\n\n return {\n frame,\n timeUs: request.timeUs,\n };\n }\n\n async composeTransition(\n fromRequest: ComposeRequest,\n toRequest: ComposeRequest,\n transition: TransitionEffect\n ): Promise<ComposeResult> {\n await this.composeFrame(fromRequest);\n\n const toFrameRequest = {\n ...toRequest,\n transition,\n };\n\n return this.composeFrame(toFrameRequest);\n }\n\n private clearCanvas(): void {\n if (this.config.backgroundColor) {\n this.ctx.fillStyle = this.config.backgroundColor;\n this.ctx.fillRect(0, 0, this.config.width, this.config.height);\n } else {\n this.ctx.clearRect(0, 0, this.config.width, this.config.height);\n }\n }\n\n // private sortLayers(layers: Layer[]): Layer[] {\n // return [...layers].sort((a, b) => a.zIndex - b.zIndex);\n // }\n\n private async createOutputFrame(timeUs: number): Promise<VideoFrame> {\n const frame = new VideoFrame(this.canvas, {\n timestamp: timeUs,\n duration: this.frameDurationUs, // Use cached duration\n alpha: 'discard',\n visibleRect: { x: 0, y: 0, width: this.canvas.width, height: this.canvas.height },\n });\n return frame;\n }\n\n private async loadFonts(): Promise<void> {\n if (!this.config.fonts || this.config.fonts.length === 0) {\n return;\n }\n\n for (const font of this.config.fonts) {\n if (this.loadedFonts.has(font.family)) {\n continue;\n }\n\n try {\n const fontFace = new FontFace(font.family, `url(${font.url})`);\n const loadedFont = await fontFace.load();\n\n if ('fonts' in self) {\n self.fonts.add(loadedFont);\n }\n\n this.loadedFonts.add(font.family);\n } catch {\n // Font loading failed, will fallback to system fonts\n }\n }\n }\n\n updateConfig(config: Partial<VideoComposeConfig>): void {\n Object.assign(this.config, this.applyDefaults({ ...this.config, ...config }));\n\n if (config.fps !== undefined) {\n this.frameDurationUs = Math.round(1_000_000 / this.config.fps); // Update cached duration\n }\n\n if (config.width || config.height) {\n this.canvas.width = this.config.width;\n this.canvas.height = this.config.height;\n this.layerRenderer.updateDimensions(this.config.width, this.config.height);\n this.transitionProcessor.updateDimensions(this.config.width, this.config.height);\n }\n\n if (config.enableSmoothing !== undefined) {\n this.ctx.imageSmoothingEnabled = this.config.enableSmoothing;\n }\n\n if (config.fonts) {\n this.fontsLoadingPromise = this.loadFonts();\n }\n }\n\n dispose(): void {\n this.filterProcessor.clearCache();\n }\n}\n","export type QuantizeStrategy = 'nearest' | 'floor' | 'ceil';\ntype TimeUs = number;\nexport const MICROSECONDS_PER_SECOND = 1_000_000;\n\nconst DEFAULT_FPS = 30;\n\nexport const DEFAULT_FRAME_TOLERANCE_US: TimeUs = 33_333;\n\nexport function normalizeFps(value?: number): number {\n if (!Number.isFinite(value) || (value as number) <= 0) {\n return DEFAULT_FPS;\n }\n return value as number;\n}\n\nexport function frameDurationFromFps(fps?: number): TimeUs {\n const normalized = normalizeFps(fps);\n const duration = MICROSECONDS_PER_SECOND / normalized;\n return Math.max(Math.round(duration), 1);\n}\n\nexport function frameIndexFromTimestamp(\n baseTimestampUs: TimeUs,\n timestampUs: TimeUs,\n fps?: number,\n strategy: QuantizeStrategy = 'nearest'\n): number {\n const frameDurationUs = frameDurationFromFps(fps);\n if (frameDurationUs <= 0) {\n return 0;\n }\n\n const delta = timestampUs - baseTimestampUs;\n const rawIndex = delta / frameDurationUs;\n\n if (!Number.isFinite(rawIndex)) {\n return 0;\n }\n\n switch (strategy) {\n case 'floor':\n return Math.floor(rawIndex);\n case 'ceil':\n return Math.ceil(rawIndex);\n default:\n return Math.round(rawIndex);\n }\n}\n\nexport function quantizeTimestampToFrame(\n timestampUs: TimeUs,\n baseTimestampUs: TimeUs,\n fps?: number,\n strategy: QuantizeStrategy = 'nearest'\n): TimeUs {\n const frameDurationUs = frameDurationFromFps(fps);\n const index = frameIndexFromTimestamp(baseTimestampUs, timestampUs, fps, strategy);\n return baseTimestampUs + index * frameDurationUs;\n}\n\nexport function isTimestampWithinFrame(\n targetTimeUs: TimeUs,\n frameTimestampUs: TimeUs,\n frameDurationUs: TimeUs,\n toleranceUs: TimeUs = DEFAULT_FRAME_TOLERANCE_US\n): boolean {\n if (!Number.isFinite(frameTimestampUs)) {\n return false;\n }\n\n const delta = Math.abs(targetTimeUs - frameTimestampUs);\n if (delta <= toleranceUs) {\n return true;\n }\n\n if (frameDurationUs > 0 && frameTimestampUs <= targetTimeUs) {\n return targetTimeUs < frameTimestampUs + frameDurationUs;\n }\n\n return false;\n}\n","import type { Transform2D } from '../model/types';\n\nexport interface AnimationKeyframeInput {\n time: number;\n transform?: Transform2D;\n opacity?: number;\n easing?: string;\n}\n\nexport function interpolateKeyframes(\n keyframes: AnimationKeyframeInput[],\n timeUs: number\n): { transform: Transform2D; opacity?: number } {\n const defaultTransform: Transform2D = {\n x: 0,\n y: 0,\n scaleX: 1,\n scaleY: 1,\n rotation: 0,\n anchorX: 0.5,\n anchorY: 0.5,\n };\n\n if (keyframes.length === 0) {\n return { transform: defaultTransform };\n }\n\n const firstFrame = keyframes[0]!;\n const lastFrame = keyframes[keyframes.length - 1]!;\n\n if (timeUs <= firstFrame.time) {\n return {\n transform: { ...defaultTransform, ...firstFrame.transform },\n opacity: firstFrame.opacity,\n };\n }\n\n if (timeUs >= lastFrame.time) {\n return {\n transform: { ...defaultTransform, ...lastFrame.transform },\n opacity: lastFrame.opacity,\n };\n }\n\n // Find current keyframe interval\n let prevFrame = firstFrame;\n let nextFrame = lastFrame;\n\n for (let i = 0; i < keyframes.length - 1; i++) {\n const currentFrame = keyframes[i]!;\n const followingFrame = keyframes[i + 1]!;\n if (timeUs >= currentFrame.time && timeUs < followingFrame.time) {\n prevFrame = currentFrame;\n nextFrame = followingFrame;\n break;\n }\n }\n\n const duration = nextFrame.time - prevFrame.time;\n const elapsed = timeUs - prevFrame.time;\n const progress = elapsed / duration;\n const easedProgress = applyEasing(progress, prevFrame.easing ?? 'linear');\n\n const prevTransform = prevFrame.transform ?? { x: 0, y: 0 };\n const nextTransform = nextFrame.transform ?? { x: 0, y: 0 };\n\n const transform = interpolateTransform(prevTransform, nextTransform, easedProgress);\n\n const opacity =\n prevFrame.opacity !== undefined && nextFrame.opacity !== undefined\n ? lerp(prevFrame.opacity, nextFrame.opacity, easedProgress)\n : undefined;\n\n return { transform, opacity };\n}\n\nexport function interpolateTransform(from: Transform2D, to: Transform2D, t: number): Transform2D {\n return {\n x: lerp(from.x ?? 0, to.x ?? 0, t),\n y: lerp(from.y ?? 0, to.y ?? 0, t),\n scaleX: lerp(from.scaleX ?? 1, to.scaleX ?? 1, t),\n scaleY: lerp(from.scaleY ?? 1, to.scaleY ?? 1, t),\n rotation: lerp(from.rotation ?? 0, to.rotation ?? 0, t),\n anchorX: lerp(from.anchorX ?? 0.5, to.anchorX ?? 0.5, t),\n anchorY: lerp(from.anchorY ?? 0.5, to.anchorY ?? 0.5, t),\n };\n}\n\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nexport function applyEasing(t: number, easing: string): number {\n switch (easing) {\n case 'linear':\n return t;\n case 'ease-in':\n // Cubic ease-in: t^3\n return t * t * t;\n case 'ease-out': {\n // Cubic ease-out: 1 - (1-t)^3\n const oneMinusT = 1 - t;\n return 1 - oneMinusT * oneMinusT * oneMinusT;\n }\n case 'ease-in-out':\n // Cubic ease-in-out: smoother transition\n return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;\n default:\n return t;\n }\n}\n","import type { TimeUs } from '../../model/types';\n\n/**\n * FrameRateConverter - Converts VFR (Variable Frame Rate) to CFR (Constant Frame Rate)\n *\n * Receives VideoFrames with irregular timestamps from decoder (VFR)\n * and outputs VideoFrames with regular timestamps based on target fps (CFR).\n *\n * Algorithm:\n * - Generate target frame sequence: t = 0, 33333, 66666, ... µs (for 30fps)\n * - For each target time t, find the closest source frame\n * - Output new frame with standardized timestamp t\n * - Close source frames after use to prevent memory leaks\n *\n * Trim Support:\n * - Frames with timestamp < trimStartUs are filtered out (closed and skipped)\n * - Remaining frame timestamps are adjusted: adjustedTimestamp = timestamp - trimStartUs\n *\n * Duration Handling:\n * - Output stops when source frames are exhausted (no frame padding)\n * - If source is shorter than clipDurationUs, output ends early\n *\n * Scenarios:\n * - Downsampling (60fps→30fps): Skip every other frame\n * - Upsampling (24fps→30fps): Duplicate some frames\n * - Same rate (30fps→30fps): Normalize timestamps\n */\nexport class FrameRateConverter {\n private readonly clipDurationUs: TimeUs;\n private readonly frameDurationUs: number;\n private readonly trimStartUs: TimeUs;\n\n // State for frame processing\n private targetFrameIndex = 0;\n private targetFrameTimeUs: TimeUs = 0;\n private sourceFrameBuffer: VideoFrame[] = [];\n\n constructor(targetFps: number, clipDurationUs: TimeUs, trimStartUs: TimeUs = 0) {\n if (targetFps <= 0) {\n throw new Error(`Invalid target fps: ${targetFps}`);\n }\n if (clipDurationUs <= 0) {\n throw new Error(`Invalid clip duration: ${clipDurationUs}`);\n }\n\n this.clipDurationUs = clipDurationUs;\n this.frameDurationUs = Math.round(1_000_000 / targetFps);\n this.trimStartUs = trimStartUs;\n }\n\n /**\n * Create a TransformStream that converts VFR frames to CFR frames\n */\n createStream(): TransformStream<VideoFrame, VideoFrame> {\n return new TransformStream<VideoFrame, VideoFrame>({\n start: () => {\n // Reset state for new stream\n this.targetFrameIndex = 0;\n this.targetFrameTimeUs = 0;\n this.sourceFrameBuffer = [];\n this.sourceFrameCount = 0;\n this.outputFrameCount = 0;\n },\n\n transform: (sourceFrame, controller) => {\n this.processSourceFrame(sourceFrame, controller);\n },\n\n flush: (controller) => {\n this.flushRemainingFrames(controller);\n },\n });\n }\n\n private sourceFrameCount = 0;\n private outputFrameCount = 0;\n\n /**\n * Process incoming source frame and output target frames\n */\n private processSourceFrame(\n sourceFrame: VideoFrame,\n controller: TransformStreamDefaultController<VideoFrame>\n ): void {\n const sourceTimestamp = sourceFrame.timestamp ?? 0;\n\n // Filter frames before trim start point\n if (sourceTimestamp < this.trimStartUs) {\n sourceFrame.close();\n return;\n }\n\n // Only create adjusted frame if trimStartUs > 0 (needs timestamp shift)\n let frameToBuffer: VideoFrame;\n if (this.trimStartUs > 0) {\n // Convert resource time to clip-relative time\n const adjustedTimestamp = sourceTimestamp - this.trimStartUs;\n frameToBuffer = new VideoFrame(sourceFrame, {\n timestamp: adjustedTimestamp,\n duration: sourceFrame.duration ?? undefined,\n });\n sourceFrame.close();\n } else {\n // No trim, use source frame directly\n frameToBuffer = sourceFrame;\n }\n\n // Add frame to buffer\n this.sourceFrameBuffer.push(frameToBuffer);\n this.sourceFrameCount++;\n\n // Try to output target frames that can be satisfied with current buffer\n while (this.targetFrameTimeUs < this.clipDurationUs) {\n const closestFrame = this.findClosestFrame(this.targetFrameTimeUs);\n\n if (!closestFrame) {\n // Need more source frames\n break;\n }\n\n // Check if we need to wait for next source frame\n // (if closest frame is before target and we might get a better match)\n if (this.shouldWaitForNextFrame(closestFrame)) {\n break;\n }\n\n // Output target frame with standardized timestamp\n try {\n const targetFrame = new VideoFrame(closestFrame, {\n timestamp: this.targetFrameTimeUs,\n duration: this.frameDurationUs,\n });\n\n controller.enqueue(targetFrame);\n this.outputFrameCount++;\n\n // Clean up old frames that are no longer needed\n this.cleanupOldFrames(this.targetFrameTimeUs);\n\n // Move to next target frame\n this.targetFrameIndex++;\n this.targetFrameTimeUs = this.targetFrameIndex * this.frameDurationUs;\n } catch (_error) {\n console.error('[FrameRateConverter] Failed to create target frame:', _error);\n // Continue processing even if one frame fails\n this.targetFrameIndex++;\n this.targetFrameTimeUs = this.targetFrameIndex * this.frameDurationUs;\n }\n }\n }\n\n /**\n * Flush remaining target frames at end of stream\n */\n private flushRemainingFrames(controller: TransformStreamDefaultController<VideoFrame>): void {\n // Process remaining buffered source frames\n while (this.sourceFrameBuffer.length > 0 && this.targetFrameTimeUs < this.clipDurationUs) {\n const closestFrame = this.findClosestFrame(this.targetFrameTimeUs);\n if (!closestFrame) break;\n\n if (!this.outputTargetFrame(closestFrame, controller)) break;\n }\n\n // Clean up all remaining frames\n this.cleanupAllFrames(null);\n }\n\n /**\n * Output a single target frame\n */\n private outputTargetFrame(\n sourceFrame: VideoFrame,\n controller: TransformStreamDefaultController<VideoFrame>\n ): boolean {\n try {\n const targetFrame = new VideoFrame(sourceFrame, {\n timestamp: this.targetFrameTimeUs,\n duration: this.frameDurationUs,\n });\n\n controller.enqueue(targetFrame);\n this.targetFrameIndex++;\n this.targetFrameTimeUs = this.targetFrameIndex * this.frameDurationUs;\n return true;\n } catch (error) {\n console.error('[FrameRateConverter] Failed to create target frame:', error);\n return false;\n }\n }\n\n /**\n * Clean up all buffered frames (except the specified frame to keep)\n */\n private cleanupAllFrames(keepFrame: VideoFrame | null): void {\n for (const frame of this.sourceFrameBuffer) {\n if (frame === keepFrame) continue;\n\n try {\n frame.close();\n } catch {\n // Ignore close errors\n }\n }\n this.sourceFrameBuffer = [];\n }\n\n /**\n * Find the source frame closest to target time\n */\n private findClosestFrame(targetTimeUs: TimeUs): VideoFrame | null {\n if (this.sourceFrameBuffer.length === 0) {\n return null;\n }\n\n let closestFrame = this.sourceFrameBuffer[0];\n let minError = Math.abs((closestFrame?.timestamp ?? 0) - targetTimeUs);\n\n for (const frame of this.sourceFrameBuffer) {\n const error = Math.abs((frame.timestamp ?? 0) - targetTimeUs);\n if (error < minError) {\n minError = error;\n closestFrame = frame;\n }\n }\n\n return closestFrame ?? null;\n }\n\n /**\n * Check if we should wait for next source frame before outputting\n * Returns true if:\n * - We only have 1 frame in buffer\n * - The closest frame is before target time\n * - We might get a better match from next frame\n */\n private shouldWaitForNextFrame(closestFrame: VideoFrame): boolean {\n if (this.sourceFrameBuffer.length <= 1) {\n const frameTimestamp = closestFrame.timestamp ?? 0;\n // If we only have one frame and it's before target, wait for more frames\n // unless it's far ahead (meaning we're falling behind)\n if (frameTimestamp < this.targetFrameTimeUs) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Clean up source frames that are no longer needed\n * Keep frames that might be needed for future target frames\n */\n private cleanupOldFrames(currentTargetTimeUs: TimeUs): void {\n const nextTargetTimeUs = currentTargetTimeUs + this.frameDurationUs;\n\n // Remove frames that are definitely too old (before previous target time)\n const previousTargetTimeUs = currentTargetTimeUs - this.frameDurationUs;\n\n let removeCount = 0;\n for (let i = 0; i < this.sourceFrameBuffer.length; i++) {\n const frame = this.sourceFrameBuffer[i];\n if (!frame) continue;\n\n const frameTimestamp = frame.timestamp ?? 0;\n\n // Keep frame if:\n // 1. It's close to current or next target time\n // 2. We haven't used it yet\n // 3. It might be needed for next target\n const isNeededForNext =\n Math.abs(frameTimestamp - nextTargetTimeUs) <\n Math.abs(frameTimestamp - previousTargetTimeUs);\n\n if (frameTimestamp < previousTargetTimeUs && !isNeededForNext) {\n // This frame is too old and won't be needed\n try {\n frame.close();\n } catch {\n // Ignore close errors\n }\n removeCount++;\n } else {\n // Keep this frame and all subsequent frames\n break;\n }\n }\n\n // Remove closed frames from buffer\n if (removeCount > 0) {\n this.sourceFrameBuffer.splice(0, removeCount);\n }\n }\n\n /**\n * Get current conversion state (for debugging)\n */\n getState(): {\n targetFrameIndex: number;\n targetFrameTimeUs: TimeUs;\n bufferSize: number;\n frameDurationUs: number;\n } {\n return {\n targetFrameIndex: this.targetFrameIndex,\n targetFrameTimeUs: this.targetFrameTimeUs,\n bufferSize: this.sourceFrameBuffer.length,\n frameDurationUs: this.frameDurationUs,\n };\n }\n}\n","import { WorkerChannel } from '../../worker/WorkerChannel';\nimport { WorkerMessageType, WorkerState } from '../../worker/types';\nimport { VideoComposer } from './VideoComposer';\nimport type { VideoComposeConfig, ComposeRequest, Layer, ImageLayer, Transform2D } from './types';\nimport type {\n ClipInstructionSet,\n SerializedLayerPlan,\n SerializedTransitionPlan,\n SerializedImageLayerPayload,\n SerializedTextLayerPayload,\n} from './instructions';\nimport { frameDurationFromFps } from '../../utils/time-utils';\nimport { interpolateKeyframes } from '../../utils/animation-utils';\nimport { FrameRateConverter } from './FrameRateConverter';\n\ntype TimeUs = number;\n\nfunction resolveActiveLayers(\n layers: SerializedLayerPlan[],\n timestamp: number\n): SerializedLayerPlan[] {\n return layers.filter((layer) => {\n if (!layer.payload.attachmentId) {\n // Main track layer (no attachmentId) is always active\n return true;\n }\n if (layer.status !== 'ready') {\n return false;\n }\n // Check if layer is active at current timestamp\n return layer.activeRanges.some(\n (range) => timestamp >= range.startUs && timestamp < range.endUs\n );\n });\n}\n\nfunction materializeLayer(\n layer: SerializedLayerPlan,\n frame: VideoFrame,\n imageMap: Map<string, ImageBitmap>,\n globalTimeUs?: number\n): Layer | null {\n const baseLayer: Layer = {\n id: layer.layerId,\n type: layer.type as any,\n zIndex: layer.zIndex ?? 0,\n visible: true,\n opacity: layer.opacity ?? 1,\n };\n\n if (layer.type === 'video') {\n return {\n ...baseLayer,\n type: 'video',\n videoFrame: frame,\n } as Layer;\n }\n\n if (layer.type === 'text') {\n const payload = layer.payload as SerializedTextLayerPayload;\n return {\n ...baseLayer,\n type: 'text',\n text: payload.text,\n localeCode: payload.localeCode,\n fontConfig: payload.fontConfig,\n animation: payload.animation,\n wordTimings: payload.wordTimings,\n letterCase: payload.letterCase,\n } as Layer;\n }\n\n if (layer.type === 'image') {\n const payload = layer.payload as SerializedImageLayerPayload;\n const resourceId = payload.resourceId;\n const source = imageMap.get(resourceId) ?? null;\n\n const imageLayer: ImageLayer = {\n ...baseLayer,\n type: 'image',\n source,\n attachmentId: payload.attachmentId,\n };\n\n // Add target dimensions if specified\n if (payload.targetWidth !== undefined) {\n (imageLayer as any).targetWidth = payload.targetWidth;\n }\n if (payload.targetHeight !== undefined) {\n (imageLayer as any).targetHeight = payload.targetHeight;\n }\n\n // If has animation config, compute current animation state\n if (payload.animation && globalTimeUs !== undefined) {\n const animState = computeAnimationState(payload.animation, globalTimeUs);\n\n // If not visible, return null to filter out\n if (!animState.visible) {\n return null;\n }\n\n // Ensure all transform fields have values for stages/compose Transform2D type\n imageLayer.transform = {\n x: animState.transform.x ?? 0,\n y: animState.transform.y ?? 0,\n scaleX: animState.transform.scaleX ?? 1,\n scaleY: animState.transform.scaleY ?? 1,\n rotation: animState.transform.rotation ?? 0,\n anchorX: animState.transform.anchorX ?? 0.5,\n anchorY: animState.transform.anchorY ?? 0.5,\n };\n if (animState.opacity !== undefined) {\n imageLayer.opacity = animState.opacity;\n }\n }\n\n return imageLayer;\n }\n\n return baseLayer;\n}\n\nfunction computeAnimationState(\n animation: NonNullable<SerializedImageLayerPayload['animation']>,\n globalTimeUs: number\n): { transform: Transform2D; opacity?: number; visible: boolean } {\n const { position, keyframes, overlayClipStartUs } = animation;\n\n // Calculate time relative to overlay clip start\n const relativeTimeUs = globalTimeUs - overlayClipStartUs;\n\n // If outside keyframe range, hide\n if (relativeTimeUs < 0 || relativeTimeUs > keyframes[keyframes.length - 1].time) {\n return {\n transform: { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0, anchorX: 0.5, anchorY: 0.5 },\n opacity: 0,\n visible: false,\n };\n }\n\n // Interpolate keyframes\n const animState = interpolateKeyframes(keyframes, relativeTimeUs);\n\n // Merge base position and relative transform\n // Convert rotation from degrees (model) to radians (render layer)\n const rotationDeg = animState.transform?.rotation ?? 0;\n const rotationRad = (rotationDeg * Math.PI) / 180;\n\n const finalTransform: Transform2D = {\n x: position.x + (animState.transform?.x ?? 0),\n y: position.y + (animState.transform?.y ?? 0),\n scaleX: animState.transform?.scaleX ?? 1,\n scaleY: animState.transform?.scaleY ?? 1,\n rotation: rotationRad,\n anchorX: animState.transform?.anchorX ?? 0.5,\n anchorY: animState.transform?.anchorY ?? 0.5,\n };\n\n return {\n transform: finalTransform,\n opacity: animState.opacity,\n visible: true,\n };\n}\n\n/**\n * VideoComposeWorker - Visual composition in the pipeline\n * Receives decoded video frames and outputs composed frames\n *\n * Pipeline: DecodeWorker → VideoComposeWorker → EncodeWorker\n *\n * Features:\n * - Multi-layer composition with Canvas2D/WebGL\n * - Transition effects and filters\n * - Text and image overlay support\n * - Stream-based processing with configurable backpressure\n */\nexport class VideoComposeWorker {\n private channel: WorkerChannel;\n private composer: VideoComposer | null = null;\n private composeStream: TransformStream<ComposeRequest, VideoFrame> | null = null;\n\n private sessionId: string | null = null;\n private downstreamPort: MessagePort | null = null;\n private upstreamPort: MessagePort | null = null;\n private instructions: ClipInstructionSet | null = null;\n private imageMap = new Map<string, ImageBitmap>();\n\n constructor() {\n // Initialize WorkerChannel\n this.channel = new WorkerChannel(self, {\n name: 'VideoComposeWorker',\n timeout: 30000,\n });\n\n this.setupHandlers();\n }\n\n private setupHandlers(): void {\n // Register message handlers\n this.channel.registerHandler('configure', this.handleConfigure.bind(this));\n this.channel.registerHandler('connect', this.handleConnect.bind(this));\n this.channel.registerHandler('flush', this.handleFlush.bind(this));\n // this.channel.registerHandler('get_stream', this.handleGetStream.bind(this));\n this.channel.registerHandler('get_stats', this.handleGetStats.bind(this));\n this.channel.registerHandler('install_instructions', this.handleInstallInstructions.bind(this));\n this.channel.registerHandler('receive_image', this.handleReceiveImage.bind(this));\n this.channel.registerHandler('dispose_clip', this.handleDisposeClip.bind(this));\n this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));\n\n // Support receiving VideoFrame stream directly from main thread (export mode)\n this.channel.receiveStream(this.handleReceiveStream.bind(this));\n }\n\n /**\n * Unified connect handler used by stream pipeline\n */\n private async handleConnect(payload: {\n direction: 'upstream' | 'downstream';\n port: MessagePort;\n streamType: 'video' | 'audio' | 'frame' | 'chunk';\n sessionId?: string;\n }): Promise<{ success: boolean }> {\n const { port, direction, sessionId } = payload;\n\n if (sessionId && !this.sessionId) {\n this.sessionId = sessionId;\n }\n\n if (direction === 'upstream') {\n this.upstreamPort = port;\n const channel = new WorkerChannel(port, {\n name: 'VideoCompose-Decode',\n timeout: 30000,\n });\n channel.receiveStream(this.handleReceiveStream.bind(this));\n }\n if (direction === 'downstream') {\n this.downstreamPort = port;\n }\n return { success: true };\n }\n\n /**\n * Configure composer\n * According to docs/impl/14-config, only reinitialize when initial=true\n */\n private async handleConfigure(payload: {\n config: VideoComposeConfig;\n initial?: boolean;\n }): Promise<{\n success: boolean;\n config: VideoComposeConfig;\n }> {\n const { config, initial } = payload;\n const hasValidDimensions = config.width > 0 && config.height > 0;\n const hasValidFps = config.fps > 0;\n\n if (!hasValidDimensions || !hasValidFps) {\n throw new Error(\n `VideoComposeWorker: invalid canvas config width=${config.width}, height=${config.height}, fps=${config.fps}`\n );\n }\n\n // Set worker state to ready on initial configuration\n if (initial) {\n this.channel.state = WorkerState.Ready;\n }\n\n if (initial || !this.composer) {\n // Initial configuration or composer doesn't exist\n if (this.composer) {\n this.composer.dispose();\n this.composeStream = null;\n }\n\n // Create new composer\n this.composer = new VideoComposer(config);\n } else {\n // Just update configuration\n this.composer.updateConfig(config);\n }\n\n // Notify configuration complete\n this.channel.notify('configured', {\n config: this.composer.config,\n initialized: initial || false,\n });\n\n return {\n success: true,\n config: this.composer.config,\n };\n }\n\n private async handleReceiveStream(\n stream: ReadableStream,\n metadata?: Record<string, any>\n ): Promise<void> {\n if (!this.composer) {\n console.error('[VideoComposeWorker] Composer not configured');\n return;\n }\n\n // Support inline instructions from metadata (export mode)\n // This ensures instructions arrive with the stream to avoid race conditions\n if (metadata?.instructions) {\n await this.handleInstallInstructions(metadata.instructions);\n }\n\n if (!this.instructions) {\n console.error('[VideoComposeWorker] No instructions available after metadata check');\n return;\n }\n\n // Get trimStartUs from main video layer (layer without attachmentId)\n const mainLayer = this.instructions.layers.find(\n (l) => l.type === 'video' && !l.payload.attachmentId\n );\n const trimStartUs = mainLayer?.type === 'video' ? (mainLayer.payload.trimStartUs ?? 0) : 0;\n\n // Insert FrameRateConverter to convert VFR to CFR with trim support\n const timeline = this.instructions.baseConfig.timeline;\n const fpsConverter = new FrameRateConverter(\n timeline?.compositionFps ?? 30,\n timeline?.clipDurationUs ?? Infinity,\n trimStartUs\n );\n\n // Pipeline: decode stream → fps converter (VFR→CFR + trim) → filter → compose\n const cfrStream = stream.pipeThrough(fpsConverter.createStream());\n\n const filteredStream = cfrStream.pipeThrough(\n new TransformStream<VideoFrame, ComposeRequest>({\n transform: (frame, controller) => {\n try {\n const request = this.buildComposeRequest(this.instructions!, frame);\n if (!request) {\n frame.close();\n return;\n }\n controller.enqueue(request);\n } catch (error) {\n console.error('[VideoComposeWorker] buildComposeRequest error:', error);\n frame?.close?.();\n throw error;\n }\n },\n })\n );\n\n const composeStream = this.composer.createStreams();\n\n filteredStream.pipeTo(composeStream.writable).catch((error) => {\n console.error('[VideoComposeWorker] compose stream error', this.sessionId, error);\n });\n\n const meta = {\n ...metadata,\n streamType: 'video',\n sessionId: this.sessionId,\n };\n\n if (this.downstreamPort) {\n const encodeChannel = new WorkerChannel(this.downstreamPort, {\n name: 'VideoCompose-Encode',\n timeout: 30000,\n });\n encodeChannel.sendStream(composeStream.readable, meta);\n } else {\n this.channel.sendStream(composeStream.readable, meta);\n }\n }\n\n // private handleGetStream(): ReadableStream<VideoFrame> | undefined {\n // return this.composer?.createStreams()?.cacheStream;\n // }\n\n /**\n * Flush the composition pipeline\n */\n private async handleFlush(): Promise<{ success: boolean }> {\n try {\n // Flush any pending frames in the stream\n // The stream will handle this automatically\n\n this.channel.notify('flush_complete', {});\n return { success: true };\n } catch (error: any) {\n throw {\n code: 'FLUSH_ERROR',\n message: error.message,\n };\n }\n }\n\n /**\n * Get composer statistics\n */\n private async handleGetStats(): Promise<{\n configured: boolean;\n config?: VideoComposeConfig;\n streaming: boolean;\n }> {\n return {\n configured: this.composer !== null,\n config: this.composer?.config,\n streaming: this.composeStream !== null,\n };\n }\n\n /**\n * Dispose worker and cleanup resources\n */\n private async handleDispose(): Promise<{ success: boolean }> {\n if (this.composer) {\n this.composer.dispose();\n this.composer = null;\n }\n\n this.composeStream = null;\n\n this.downstreamPort?.close();\n this.upstreamPort?.close();\n this.downstreamPort = null;\n this.upstreamPort = null;\n\n this.imageMap.forEach((bitmap) => bitmap.close());\n this.imageMap.clear();\n this.instructions = null;\n\n this.channel.state = WorkerState.Disposed;\n\n return { success: true };\n }\n\n private async handleInstallInstructions(\n payload: ClipInstructionSet\n ): Promise<{ success: boolean }> {\n const { clipId, revision } = payload;\n\n if (!this.sessionId) {\n this.sessionId = clipId;\n }\n\n if (this.instructions && this.instructions.revision > revision) {\n return { success: false };\n }\n\n this.instructions = payload;\n\n return { success: true };\n }\n\n /**\n * Receive image data with instructions (aligned with video pipeline)\n * Note: ImageBitmap is required because VideoFrame constructor in Worker context\n * only accepts ImageBitmap/OffscreenCanvas, not HTMLImageElement or Blob\n */\n private async handleReceiveImage(payload: {\n resourceId: string;\n sessionId: string;\n imageBitmap: ImageBitmap;\n instructions?: ClipInstructionSet;\n }): Promise<{ success: boolean }> {\n const { resourceId, sessionId, imageBitmap, instructions } = payload;\n\n if (!this.sessionId) {\n this.sessionId = sessionId;\n }\n\n // Install instructions if provided (aligned with video pipeline metadata)\n if (instructions) {\n await this.handleInstallInstructions(instructions);\n }\n\n // Store in Map (release old value if exists)\n const existing = this.imageMap.get(resourceId);\n if (existing) {\n existing.close();\n }\n\n this.imageMap.set(resourceId, imageBitmap);\n\n // Start frame stream if this is main track image\n if (this.instructions) {\n const mainLayer = this.instructions.layers.find((l) => !l.payload.attachmentId);\n const mainResourceId = mainLayer?.payload.resourceId;\n if (resourceId === mainResourceId) {\n await this.startImageFrameStream();\n }\n }\n\n return { success: true };\n }\n\n private async handleDisposeClip(): Promise<{ success: boolean }> {\n this.instructions = null;\n\n this.downstreamPort?.close();\n this.upstreamPort?.close();\n this.downstreamPort = null;\n this.upstreamPort = null;\n\n this.imageMap.forEach((bitmap) => bitmap.close());\n this.imageMap.clear();\n\n return { success: true };\n }\n\n private async startImageFrameStream(): Promise<void> {\n if (!this.instructions || !this.composer) {\n return;\n }\n\n const timeline = this.instructions.baseConfig.timeline;\n if (!timeline) {\n return;\n }\n\n // Find main track resource ImageBitmap from Map\n const mainLayer = this.instructions.layers.find((l) => !l.payload.attachmentId);\n if (!mainLayer) return;\n\n const mainResourceId = (mainLayer.payload as any).resourceId as string;\n const imageBitmap = this.imageMap.get(mainResourceId);\n if (!imageBitmap) {\n console.warn('[VideoComposeWorker] Main track ImageBitmap not found:', mainResourceId);\n return;\n }\n\n const composeStream = this.composer.createStreams();\n\n const { clipDurationUs, compositionFps } = timeline;\n\n let currentTimeUs = 0;\n const readableStream = new ReadableStream<ComposeRequest>({\n pull: (controller) => {\n if (currentTimeUs >= clipDurationUs) {\n controller.close();\n return;\n }\n\n const videoFrame = new VideoFrame(imageBitmap, {\n timestamp: currentTimeUs,\n duration: frameDurationFromFps(compositionFps),\n });\n try {\n const request = this.buildComposeRequest(this.instructions!, videoFrame);\n if (request) {\n controller.enqueue(request);\n } else {\n videoFrame.close();\n }\n currentTimeUs += frameDurationFromFps(compositionFps);\n } catch (error) {\n videoFrame.close();\n throw error;\n }\n },\n });\n\n readableStream.pipeTo(composeStream.writable).catch((error) => {\n console.error('[VideoComposeWorker] image frame stream error', this.sessionId, error);\n });\n\n const meta = {\n streamType: 'video',\n sessionId: this.sessionId,\n };\n\n if (this.downstreamPort) {\n const encodeChannel = new WorkerChannel(this.downstreamPort, {\n name: 'VideoCompose-Encode',\n timeout: 30000,\n });\n encodeChannel.sendStream(composeStream.readable, meta);\n } else {\n this.channel.sendStream(composeStream.readable, meta);\n }\n }\n\n private buildComposeRequest(\n instruction: ClipInstructionSet,\n frame: VideoFrame\n ): ComposeRequest | null {\n const clipRelativeTime = frame.timestamp ?? 0;\n const clipDurationUs = instruction.baseConfig.timeline?.clipDurationUs ?? Infinity;\n\n // Check if frame is within clip boundary (relative time)\n if (clipRelativeTime < 0 || clipRelativeTime >= clipDurationUs) {\n return null;\n }\n\n const activeLayers = resolveActiveLayers(instruction.layers, clipRelativeTime);\n\n if (!activeLayers.length) {\n return null;\n }\n\n // Calculate global time\n const clipStartUs = instruction.baseConfig.timeline?.clipStartUs ?? 0;\n const globalTimeUs = clipStartUs + clipRelativeTime;\n\n // Materialize layers with global time\n const layers = activeLayers\n .map((layer) => materializeLayer(layer, frame, this.imageMap, globalTimeUs))\n .filter((layer): layer is Layer => layer !== null);\n\n if (!layers.length) {\n return null;\n }\n\n return {\n timeUs: clipRelativeTime,\n globalTimeUs,\n layers,\n transition: VideoComposeWorker.buildTransition(\n instruction.transitions,\n clipRelativeTime,\n instruction.baseConfig.timeline\n ),\n };\n }\n\n private static buildTransition(\n transitions: SerializedTransitionPlan[],\n timeUs: TimeUs,\n _timeline?: VideoComposeConfig['timeline']\n ) {\n const entry = transitions.find((transition) => {\n const { startUs, endUs } = transition.range;\n return timeUs >= startUs && timeUs < endUs;\n });\n if (!entry) {\n return undefined;\n }\n const durationUs = entry.range.endUs - entry.range.startUs;\n const progress = durationUs > 0 ? (timeUs - entry.range.startUs) / durationUs : 0;\n return {\n type: entry.params.type,\n progress: Math.min(Math.max(progress, 0), 1),\n easing: entry.params.easing,\n params: entry.params.payload,\n direction: entry.params.payload?.direction,\n } as any;\n }\n}\n\n// Initialize worker\nconst worker = new VideoComposeWorker();\n\n// Handle worker termination\nself.addEventListener('beforeunload', () => {\n worker['handleDispose']();\n});\n\nexport default null; // Required for TypeScript worker compilation\n"],"names":["calculateYPosition","usToFrame","idx","frame"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { W as WorkerChannel, a as WorkerMessageType, b as WorkerState } from "../../WorkerChannel.CE5euh3R.js";
1
+ import { W as WorkerChannel, a as WorkerMessageType, b as WorkerState } from "../../WorkerChannel.DjBEVvEA.js";
2
2
  import { B as BaseDecoder } from "../../BaseDecoder.CB5XmTpS.js";
3
3
  class AudioChunkDecoder extends BaseDecoder {
4
4
  // Default values
@@ -317,4 +317,4 @@ export {
317
317
  AudioDecodeWorker,
318
318
  audioDecode_worker as default
319
319
  };
320
- //# sourceMappingURL=audio-decode.worker.B__6tqsy.js.map
320
+ //# sourceMappingURL=audio-decode.worker.CpjkrZtT.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"audio-decode.worker.B__6tqsy.js","sources":["../../../../src/stages/decode/AudioChunkDecoder.ts","../../../../src/stages/decode/audio-decode.worker.ts"],"sourcesContent":["import { AudioDecoderConfig } from './types';\nimport { BaseDecoder } from './BaseDecoder';\n\n/**\n * Audio decoder with streaming support\n * Extends BaseDecoder for common WebCodecs operations\n */\nexport class AudioChunkDecoder extends BaseDecoder<\n AudioDecoder,\n AudioDecoderConfig,\n EncodedAudioChunk,\n AudioData\n> {\n // Default values\n private static readonly DEFAULT_HIGH_WATER_MARK = 20;\n private static readonly DEFAULT_DECODE_QUEUE_THRESHOLD = 16;\n\n // Exposed properties\n readonly trackId: string;\n\n // Backpressure configuration\n protected readonly highWaterMark: number;\n protected readonly decodeQueueThreshold: number;\n\n // Buffering support for delayed configuration\n private bufferedChunks: EncodedAudioChunk[] = [];\n private isProcessingBuffer: boolean = false;\n\n constructor(trackId: string, config?: Partial<AudioDecoderConfig>) {\n // Initialize with empty config, will be configured later\n super(config as AudioDecoderConfig);\n\n this.trackId = trackId;\n\n // Set backpressure configuration\n this.highWaterMark =\n config?.backpressure?.highWaterMark ?? AudioChunkDecoder.DEFAULT_HIGH_WATER_MARK;\n this.decodeQueueThreshold = AudioChunkDecoder.DEFAULT_DECODE_QUEUE_THRESHOLD;\n }\n\n // Computed properties\n get isConfigured(): boolean {\n return this.isReady;\n }\n\n get state(): string {\n return this.decoder?.state || 'unconfigured';\n }\n\n /**\n * Update configuration - can be called before or after initialization\n */\n async updateConfig(config: Partial<AudioDecoderConfig>): Promise<void> {\n // If decoder is not ready and we have codec info, configure it\n if (!this.isReady && config.codec) {\n await this.configure(config as AudioDecoderConfig);\n await this.processBufferedChunks();\n return;\n }\n\n // Note: AudioDecoder doesn't have many runtime-configurable options\n // Backpressure settings are readonly in this implementation\n // if (config.backpressure) {\n // console.warn('Backpressure settings cannot be changed at runtime');\n // }\n }\n\n // Override createStream to handle buffering\n override createStream(): TransformStream<EncodedAudioChunk, AudioData> {\n return new TransformStream<EncodedAudioChunk, AudioData>(\n {\n start: async (controller) => {\n this.controller = controller;\n // Don't initialize if no codec config yet\n if (this.config?.codec && !this.isReady) {\n await this.initialize();\n }\n },\n\n transform: async (chunk) => {\n // If not configured yet, buffer the chunk\n if (!this.isReady) {\n this.bufferedChunks.push(chunk);\n return; // Don't process yet\n }\n\n // If we're processing buffered chunks, add to buffer to maintain order\n if (this.isProcessingBuffer) {\n this.bufferedChunks.push(chunk);\n return;\n }\n\n // Normal processing\n await this.processChunk(chunk);\n },\n\n flush: async () => {\n if (this.isReady) {\n await this.flush();\n }\n },\n },\n {\n highWaterMark: this.highWaterMark,\n size: () => 1,\n }\n );\n }\n\n /**\n * Process a single chunk (extracted from transform for reuse)\n */\n private async processChunk(chunk: EncodedAudioChunk): Promise<void> {\n if (!this.decoder) {\n throw new Error('Decoder not initialized');\n }\n\n if (this.decoder.state !== 'configured') {\n console.error('[AudioChunkDecoder] Decoder in unexpected state:', this.decoder.state);\n throw new Error(`Decoder not configured, state: ${this.decoder.state}`);\n }\n\n this.decode(chunk);\n }\n\n // Implement abstract methods\n protected async isConfigSupported(config: AudioDecoderConfig): Promise<{ supported: boolean }> {\n const result = await AudioDecoder.isConfigSupported({\n codec: config.codec,\n sampleRate: config.sampleRate,\n numberOfChannels: config.numberOfChannels,\n });\n return { supported: result.supported ?? false };\n }\n\n protected createDecoder(init: {\n output: (data: AudioData) => void;\n error: (error: DOMException) => void;\n }): AudioDecoder {\n return new AudioDecoder(init);\n }\n\n protected getDecoderType(): string {\n return 'Audio';\n }\n\n protected async configureDecoder(config: AudioDecoderConfig): Promise<void> {\n if (!this.decoder) return;\n\n await this.decoder.configure({\n codec: config.codec,\n sampleRate: config.sampleRate,\n numberOfChannels: config.numberOfChannels,\n ...(config.description && { description: config.description }),\n });\n }\n\n protected decode(chunk: EncodedAudioChunk): void {\n this.decoder?.decode(chunk);\n }\n\n /**\n * Configure the decoder with codec info (can be called after creation)\n */\n async configure(config: AudioDecoderConfig): Promise<void> {\n if (this.isReady) {\n // If already configured, reconfigure\n await this.reconfigure(config);\n return;\n }\n\n this.config = config as any;\n\n // Initialize decoder with new config\n await this.initialize();\n }\n\n /**\n * Process any buffered chunks after configuration\n */\n async processBufferedChunks(): Promise<void> {\n if (!this.isReady || this.bufferedChunks.length === 0) {\n return;\n }\n\n this.isProcessingBuffer = true;\n\n // Process buffered chunks in order\n const chunks = [...this.bufferedChunks];\n this.bufferedChunks = [];\n\n for (const chunk of chunks) {\n try {\n await this.processChunk(chunk);\n } catch (error) {\n console.error('[AudioChunkDecoder] Error processing buffered chunk:', error);\n }\n }\n\n this.isProcessingBuffer = false;\n\n // Process any new chunks that arrived while processing buffer\n if (this.bufferedChunks.length > 0) {\n await this.processBufferedChunks();\n }\n }\n\n // Override close to clean up buffered chunks\n override async close(): Promise<void> {\n // Clear buffered chunks\n this.bufferedChunks = [];\n\n // Call parent close\n await super.close();\n }\n}\n","import { WorkerChannel } from '../../worker/WorkerChannel';\nimport { WorkerMessageType, WorkerState } from '../../worker/types';\nimport { AudioChunkDecoder } from './AudioChunkDecoder';\nimport { AudioDecoderConfig } from './types';\nimport type { AudioTrackConfig } from '../compose/types';\n\ninterface TrackMetadata {\n clipId: string;\n config: AudioTrackConfig;\n sampleRate?: number;\n numberOfChannels?: number;\n type: 'bgm' | 'voice' | 'sfx' | 'other';\n}\n\nconst normalizeDescription = (desc?: ArrayBuffer | ArrayBufferView): ArrayBuffer | undefined => {\n if (!desc) return undefined;\n\n if (desc instanceof ArrayBuffer) return desc;\n\n const view = desc as ArrayBufferView;\n return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength) as ArrayBuffer;\n};\n\n/**\n * AudioDecodeWorker (Clip Local) - Decodes audio for a single clip\n * Receives encoded audio chunks from AudioDemuxWorker and outputs decoded audio data\n *\n * Pipeline: AudioDemuxWorker → AudioDecodeWorker → Main Thread (OfflineAudioContext)\n *\n * Features:\n * - Single clip, single AudioDecoder instance\n * - Outputs AudioData stream to main thread for mixing\n * - Stream-based processing with backpressure\n * - Lifecycle tied to clip pipeline\n */\nexport class AudioDecodeWorker {\n private channel: WorkerChannel;\n private decoder: AudioChunkDecoder | null = null;\n private clipId: string = '';\n private trackId: string = '';\n\n private defaultConfig: Partial<AudioDecoderConfig> = {};\n private trackMetadata: TrackMetadata | null = null;\n\n private upstreamPort: MessagePort | null = null;\n\n constructor() {\n this.channel = new WorkerChannel(self as any, {\n name: 'AudioDecodeWorker',\n timeout: 30000,\n });\n\n this.setupHandlers();\n }\n\n private setupHandlers(): void {\n this.channel.registerHandler('configure', this.handleConfigure.bind(this));\n this.channel.registerHandler('connect', this.handleConnect.bind(this));\n this.channel.registerHandler('flush', this.handleFlush.bind(this));\n this.channel.registerHandler('reset', this.handleReset.bind(this));\n this.channel.registerHandler('get_stats', this.handleGetStats.bind(this));\n this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));\n }\n\n private async handleConnect(payload: {\n direction: 'upstream' | 'downstream';\n port: MessagePort;\n streamType?: 'audio';\n sessionId?: string;\n trackId?: string;\n clipStartUs?: number;\n clipDurationUs?: number;\n }): Promise<{ success: boolean }> {\n const { port, direction, sessionId, trackId } = payload;\n\n if (direction === 'upstream') {\n this.upstreamPort = port;\n this.clipId = sessionId || 'default';\n this.trackId = trackId || sessionId || 'default';\n\n const channel = new WorkerChannel(port, {\n name: 'Demux-AudioDecode',\n timeout: 30000,\n });\n\n channel.receiveStream((stream, metadata) => {\n this.handleReceiveStream(stream, {\n ...metadata,\n clipStartUs: payload.clipStartUs,\n clipDurationUs: payload.clipDurationUs,\n });\n });\n\n channel.registerHandler('configure', this.handleConfigure.bind(this));\n }\n\n return { success: true };\n }\n\n private async handleConfigure(payload: {\n config?: { audio?: Partial<AudioDecoderConfig> };\n sessionId?: string;\n streamType?: 'audio';\n codec?: string;\n sampleRate?: number;\n numberOfChannels?: number;\n description?: ArrayBuffer | Uint8Array;\n }): Promise<{ success: boolean }> {\n const { sessionId, streamType, codec, sampleRate, numberOfChannels, description, config } =\n payload;\n\n if (sessionId && streamType === 'audio') {\n // Save codec info to defaultConfig for decoder creation\n Object.assign(this.defaultConfig, {\n codec,\n sampleRate,\n numberOfChannels,\n description: normalizeDescription(description),\n });\n\n // Update existing decoder if present (will process buffered chunks)\n if (this.decoder) {\n await this.decoder.updateConfig({\n codec,\n sampleRate,\n numberOfChannels,\n description: normalizeDescription(description),\n });\n }\n\n return { success: true };\n }\n\n if (config?.audio) {\n Object.assign(this.defaultConfig, config.audio);\n\n if (this.decoder) {\n await this.decoder.updateConfig(config.audio);\n }\n }\n\n this.channel.state = WorkerState.Ready;\n\n return { success: true };\n }\n\n private async handleReceiveStream(\n stream: ReadableStream,\n metadata?: Record<string, any>\n ): Promise<void> {\n const sessionId = metadata?.sessionId || this.clipId;\n const trackId = metadata?.trackId || this.trackId;\n if (!this.decoder) {\n // Prefer metadata, fallback to defaultConfig\n // Note: If codec is not available, decoder will buffer chunks internally\n const decoderConfig = {\n ...this.defaultConfig,\n codec: metadata?.codec ?? this.defaultConfig.codec,\n sampleRate: metadata?.sampleRate ?? this.defaultConfig.sampleRate,\n numberOfChannels: metadata?.numberOfChannels ?? this.defaultConfig.numberOfChannels,\n description: normalizeDescription(metadata?.description) ?? this.defaultConfig.description,\n };\n\n this.decoder = new AudioChunkDecoder(trackId, decoderConfig);\n }\n\n this.trackMetadata = {\n clipId: this.clipId,\n config: this.extractTrackConfig(metadata?.runtimeConfig),\n sampleRate: metadata?.sampleRate,\n numberOfChannels: metadata?.numberOfChannels,\n type: (metadata?.trackType as TrackMetadata['type']) ?? 'other',\n };\n\n const transform = this.decoder.createStream();\n this.channel.sendStream(transform.readable as ReadableStream<AudioData>, {\n streamType: 'audio',\n sessionId,\n trackId,\n clipStartUs: metadata?.clipStartUs ?? 0,\n clipDurationUs: metadata?.clipDurationUs ?? 0,\n trackMetadata: this.trackMetadata,\n });\n\n stream\n .pipeTo(transform.writable)\n .catch((error) => console.error('[AudioDecodeWorker] Audio stream pipe error:', error));\n }\n\n private extractTrackConfig(config: any): AudioTrackConfig {\n return {\n startTimeUs: config?.startTimeUs ?? 0,\n durationUs: config?.durationUs,\n volume: config?.volume ?? 1,\n fadeIn: config?.fadeIn,\n fadeOut: config?.fadeOut,\n effects: config?.effects ?? [],\n duckingTag: config?.duckingTag,\n };\n }\n\n private async handleFlush(): Promise<{ success: boolean }> {\n if (this.decoder) {\n await this.decoder.flush();\n }\n return { success: true };\n }\n\n private async handleReset(): Promise<{ success: boolean }> {\n if (this.decoder) {\n await this.decoder.reset();\n }\n\n this.channel.notify('reset_complete', {\n type: 'audio',\n });\n\n return { success: true };\n }\n\n private async handleGetStats(): Promise<{ audio?: any }> {\n if (!this.decoder) {\n return {};\n }\n\n return {\n audio: {\n clipId: this.clipId,\n trackId: this.trackId,\n configured: this.decoder.isConfigured,\n queueSize: this.decoder.queueSize,\n state: this.decoder.state,\n },\n };\n }\n\n private async handleDispose(): Promise<{ success: boolean }> {\n if (this.decoder) {\n await this.decoder.close();\n this.decoder = null;\n }\n\n this.upstreamPort?.close();\n this.upstreamPort = null;\n\n this.trackMetadata = null;\n\n this.channel.state = WorkerState.Disposed;\n\n return { success: true };\n }\n}\n\nconst worker = new AudioDecodeWorker();\n\nself.addEventListener('beforeunload', () => {\n worker['handleDispose']();\n});\n\nexport default null;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"audio-decode.worker.CpjkrZtT.js","sources":["../../../../src/stages/decode/AudioChunkDecoder.ts","../../../../src/stages/decode/audio-decode.worker.ts"],"sourcesContent":["import { AudioDecoderConfig } from './types';\nimport { BaseDecoder } from './BaseDecoder';\n\n/**\n * Audio decoder with streaming support\n * Extends BaseDecoder for common WebCodecs operations\n */\nexport class AudioChunkDecoder extends BaseDecoder<\n AudioDecoder,\n AudioDecoderConfig,\n EncodedAudioChunk,\n AudioData\n> {\n // Default values\n private static readonly DEFAULT_HIGH_WATER_MARK = 20;\n private static readonly DEFAULT_DECODE_QUEUE_THRESHOLD = 16;\n\n // Exposed properties\n readonly trackId: string;\n\n // Backpressure configuration\n protected readonly highWaterMark: number;\n protected readonly decodeQueueThreshold: number;\n\n // Buffering support for delayed configuration\n private bufferedChunks: EncodedAudioChunk[] = [];\n private isProcessingBuffer: boolean = false;\n\n constructor(trackId: string, config?: Partial<AudioDecoderConfig>) {\n // Initialize with empty config, will be configured later\n super(config as AudioDecoderConfig);\n\n this.trackId = trackId;\n\n // Set backpressure configuration\n this.highWaterMark =\n config?.backpressure?.highWaterMark ?? AudioChunkDecoder.DEFAULT_HIGH_WATER_MARK;\n this.decodeQueueThreshold = AudioChunkDecoder.DEFAULT_DECODE_QUEUE_THRESHOLD;\n }\n\n // Computed properties\n get isConfigured(): boolean {\n return this.isReady;\n }\n\n get state(): string {\n return this.decoder?.state || 'unconfigured';\n }\n\n /**\n * Update configuration - can be called before or after initialization\n */\n async updateConfig(config: Partial<AudioDecoderConfig>): Promise<void> {\n // If decoder is not ready and we have codec info, configure it\n if (!this.isReady && config.codec) {\n await this.configure(config as AudioDecoderConfig);\n await this.processBufferedChunks();\n return;\n }\n\n // Note: AudioDecoder doesn't have many runtime-configurable options\n // Backpressure settings are readonly in this implementation\n // if (config.backpressure) {\n // console.warn('Backpressure settings cannot be changed at runtime');\n // }\n }\n\n // Override createStream to handle buffering\n override createStream(): TransformStream<EncodedAudioChunk, AudioData> {\n return new TransformStream<EncodedAudioChunk, AudioData>(\n {\n start: async (controller) => {\n this.controller = controller;\n // Don't initialize if no codec config yet\n if (this.config?.codec && !this.isReady) {\n await this.initialize();\n }\n },\n\n transform: async (chunk) => {\n // If not configured yet, buffer the chunk\n if (!this.isReady) {\n this.bufferedChunks.push(chunk);\n return; // Don't process yet\n }\n\n // If we're processing buffered chunks, add to buffer to maintain order\n if (this.isProcessingBuffer) {\n this.bufferedChunks.push(chunk);\n return;\n }\n\n // Normal processing\n await this.processChunk(chunk);\n },\n\n flush: async () => {\n if (this.isReady) {\n await this.flush();\n }\n },\n },\n {\n highWaterMark: this.highWaterMark,\n size: () => 1,\n }\n );\n }\n\n /**\n * Process a single chunk (extracted from transform for reuse)\n */\n private async processChunk(chunk: EncodedAudioChunk): Promise<void> {\n if (!this.decoder) {\n throw new Error('Decoder not initialized');\n }\n\n if (this.decoder.state !== 'configured') {\n console.error('[AudioChunkDecoder] Decoder in unexpected state:', this.decoder.state);\n throw new Error(`Decoder not configured, state: ${this.decoder.state}`);\n }\n\n this.decode(chunk);\n }\n\n // Implement abstract methods\n protected async isConfigSupported(config: AudioDecoderConfig): Promise<{ supported: boolean }> {\n const result = await AudioDecoder.isConfigSupported({\n codec: config.codec,\n sampleRate: config.sampleRate,\n numberOfChannels: config.numberOfChannels,\n });\n return { supported: result.supported ?? false };\n }\n\n protected createDecoder(init: {\n output: (data: AudioData) => void;\n error: (error: DOMException) => void;\n }): AudioDecoder {\n return new AudioDecoder(init);\n }\n\n protected getDecoderType(): string {\n return 'Audio';\n }\n\n protected async configureDecoder(config: AudioDecoderConfig): Promise<void> {\n if (!this.decoder) return;\n\n await this.decoder.configure({\n codec: config.codec,\n sampleRate: config.sampleRate,\n numberOfChannels: config.numberOfChannels,\n ...(config.description && { description: config.description }),\n });\n }\n\n protected decode(chunk: EncodedAudioChunk): void {\n this.decoder?.decode(chunk);\n }\n\n /**\n * Configure the decoder with codec info (can be called after creation)\n */\n async configure(config: AudioDecoderConfig): Promise<void> {\n if (this.isReady) {\n // If already configured, reconfigure\n await this.reconfigure(config);\n return;\n }\n\n this.config = config as any;\n\n // Initialize decoder with new config\n await this.initialize();\n }\n\n /**\n * Process any buffered chunks after configuration\n */\n async processBufferedChunks(): Promise<void> {\n if (!this.isReady || this.bufferedChunks.length === 0) {\n return;\n }\n\n this.isProcessingBuffer = true;\n\n // Process buffered chunks in order\n const chunks = [...this.bufferedChunks];\n this.bufferedChunks = [];\n\n for (const chunk of chunks) {\n try {\n await this.processChunk(chunk);\n } catch (error) {\n console.error('[AudioChunkDecoder] Error processing buffered chunk:', error);\n }\n }\n\n this.isProcessingBuffer = false;\n\n // Process any new chunks that arrived while processing buffer\n if (this.bufferedChunks.length > 0) {\n await this.processBufferedChunks();\n }\n }\n\n // Override close to clean up buffered chunks\n override async close(): Promise<void> {\n // Clear buffered chunks\n this.bufferedChunks = [];\n\n // Call parent close\n await super.close();\n }\n}\n","import { WorkerChannel } from '../../worker/WorkerChannel';\nimport { WorkerMessageType, WorkerState } from '../../worker/types';\nimport { AudioChunkDecoder } from './AudioChunkDecoder';\nimport { AudioDecoderConfig } from './types';\nimport type { AudioTrackConfig } from '../compose/types';\n\ninterface TrackMetadata {\n clipId: string;\n config: AudioTrackConfig;\n sampleRate?: number;\n numberOfChannels?: number;\n type: 'bgm' | 'voice' | 'sfx' | 'other';\n}\n\nconst normalizeDescription = (desc?: ArrayBuffer | ArrayBufferView): ArrayBuffer | undefined => {\n if (!desc) return undefined;\n\n if (desc instanceof ArrayBuffer) return desc;\n\n const view = desc as ArrayBufferView;\n return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength) as ArrayBuffer;\n};\n\n/**\n * AudioDecodeWorker (Clip Local) - Decodes audio for a single clip\n * Receives encoded audio chunks from AudioDemuxWorker and outputs decoded audio data\n *\n * Pipeline: AudioDemuxWorker → AudioDecodeWorker → Main Thread (OfflineAudioContext)\n *\n * Features:\n * - Single clip, single AudioDecoder instance\n * - Outputs AudioData stream to main thread for mixing\n * - Stream-based processing with backpressure\n * - Lifecycle tied to clip pipeline\n */\nexport class AudioDecodeWorker {\n private channel: WorkerChannel;\n private decoder: AudioChunkDecoder | null = null;\n private clipId: string = '';\n private trackId: string = '';\n\n private defaultConfig: Partial<AudioDecoderConfig> = {};\n private trackMetadata: TrackMetadata | null = null;\n\n private upstreamPort: MessagePort | null = null;\n\n constructor() {\n this.channel = new WorkerChannel(self as any, {\n name: 'AudioDecodeWorker',\n timeout: 30000,\n });\n\n this.setupHandlers();\n }\n\n private setupHandlers(): void {\n this.channel.registerHandler('configure', this.handleConfigure.bind(this));\n this.channel.registerHandler('connect', this.handleConnect.bind(this));\n this.channel.registerHandler('flush', this.handleFlush.bind(this));\n this.channel.registerHandler('reset', this.handleReset.bind(this));\n this.channel.registerHandler('get_stats', this.handleGetStats.bind(this));\n this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));\n }\n\n private async handleConnect(payload: {\n direction: 'upstream' | 'downstream';\n port: MessagePort;\n streamType?: 'audio';\n sessionId?: string;\n trackId?: string;\n clipStartUs?: number;\n clipDurationUs?: number;\n }): Promise<{ success: boolean }> {\n const { port, direction, sessionId, trackId } = payload;\n\n if (direction === 'upstream') {\n this.upstreamPort = port;\n this.clipId = sessionId || 'default';\n this.trackId = trackId || sessionId || 'default';\n\n const channel = new WorkerChannel(port, {\n name: 'Demux-AudioDecode',\n timeout: 30000,\n });\n\n channel.receiveStream((stream, metadata) => {\n this.handleReceiveStream(stream, {\n ...metadata,\n clipStartUs: payload.clipStartUs,\n clipDurationUs: payload.clipDurationUs,\n });\n });\n\n channel.registerHandler('configure', this.handleConfigure.bind(this));\n }\n\n return { success: true };\n }\n\n private async handleConfigure(payload: {\n config?: { audio?: Partial<AudioDecoderConfig> };\n sessionId?: string;\n streamType?: 'audio';\n codec?: string;\n sampleRate?: number;\n numberOfChannels?: number;\n description?: ArrayBuffer | Uint8Array;\n }): Promise<{ success: boolean }> {\n const { sessionId, streamType, codec, sampleRate, numberOfChannels, description, config } =\n payload;\n\n if (sessionId && streamType === 'audio') {\n // Save codec info to defaultConfig for decoder creation\n Object.assign(this.defaultConfig, {\n codec,\n sampleRate,\n numberOfChannels,\n description: normalizeDescription(description),\n });\n\n // Update existing decoder if present (will process buffered chunks)\n if (this.decoder) {\n await this.decoder.updateConfig({\n codec,\n sampleRate,\n numberOfChannels,\n description: normalizeDescription(description),\n });\n }\n\n return { success: true };\n }\n\n if (config?.audio) {\n Object.assign(this.defaultConfig, config.audio);\n\n if (this.decoder) {\n await this.decoder.updateConfig(config.audio);\n }\n }\n\n this.channel.state = WorkerState.Ready;\n\n return { success: true };\n }\n\n private async handleReceiveStream(\n stream: ReadableStream,\n metadata?: Record<string, any>\n ): Promise<void> {\n const sessionId = metadata?.sessionId || this.clipId;\n const trackId = metadata?.trackId || this.trackId;\n if (!this.decoder) {\n // Prefer metadata, fallback to defaultConfig\n // Note: If codec is not available, decoder will buffer chunks internally\n const decoderConfig = {\n ...this.defaultConfig,\n codec: metadata?.codec ?? this.defaultConfig.codec,\n sampleRate: metadata?.sampleRate ?? this.defaultConfig.sampleRate,\n numberOfChannels: metadata?.numberOfChannels ?? this.defaultConfig.numberOfChannels,\n description: normalizeDescription(metadata?.description) ?? this.defaultConfig.description,\n };\n\n this.decoder = new AudioChunkDecoder(trackId, decoderConfig);\n }\n\n this.trackMetadata = {\n clipId: this.clipId,\n config: this.extractTrackConfig(metadata?.runtimeConfig),\n sampleRate: metadata?.sampleRate,\n numberOfChannels: metadata?.numberOfChannels,\n type: (metadata?.trackType as TrackMetadata['type']) ?? 'other',\n };\n\n const transform = this.decoder.createStream();\n this.channel.sendStream(transform.readable as ReadableStream<AudioData>, {\n streamType: 'audio',\n sessionId,\n trackId,\n clipStartUs: metadata?.clipStartUs ?? 0,\n clipDurationUs: metadata?.clipDurationUs ?? 0,\n trackMetadata: this.trackMetadata,\n });\n\n stream\n .pipeTo(transform.writable)\n .catch((error) => console.error('[AudioDecodeWorker] Audio stream pipe error:', error));\n }\n\n private extractTrackConfig(config: any): AudioTrackConfig {\n return {\n startTimeUs: config?.startTimeUs ?? 0,\n durationUs: config?.durationUs,\n volume: config?.volume ?? 1,\n fadeIn: config?.fadeIn,\n fadeOut: config?.fadeOut,\n effects: config?.effects ?? [],\n duckingTag: config?.duckingTag,\n };\n }\n\n private async handleFlush(): Promise<{ success: boolean }> {\n if (this.decoder) {\n await this.decoder.flush();\n }\n return { success: true };\n }\n\n private async handleReset(): Promise<{ success: boolean }> {\n if (this.decoder) {\n await this.decoder.reset();\n }\n\n this.channel.notify('reset_complete', {\n type: 'audio',\n });\n\n return { success: true };\n }\n\n private async handleGetStats(): Promise<{ audio?: any }> {\n if (!this.decoder) {\n return {};\n }\n\n return {\n audio: {\n clipId: this.clipId,\n trackId: this.trackId,\n configured: this.decoder.isConfigured,\n queueSize: this.decoder.queueSize,\n state: this.decoder.state,\n },\n };\n }\n\n private async handleDispose(): Promise<{ success: boolean }> {\n if (this.decoder) {\n await this.decoder.close();\n this.decoder = null;\n }\n\n this.upstreamPort?.close();\n this.upstreamPort = null;\n\n this.trackMetadata = null;\n\n this.channel.state = WorkerState.Disposed;\n\n return { success: true };\n }\n}\n\nconst worker = new AudioDecodeWorker();\n\nself.addEventListener('beforeunload', () => {\n worker['handleDispose']();\n});\n\nexport default null;\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { W as WorkerChannel, a as WorkerMessageType, b as WorkerState } from "../../WorkerChannel.CE5euh3R.js";
1
+ import { W as WorkerChannel, a as WorkerMessageType, b as WorkerState } from "../../WorkerChannel.DjBEVvEA.js";
2
2
  import { B as BaseDecoder } from "../../BaseDecoder.CB5XmTpS.js";
3
3
  let cachedPlatformInfo = null;
4
4
  function detectPlatform() {
@@ -331,4 +331,4 @@ export {
331
331
  VideoDecodeWorker,
332
332
  videoDecode_worker as default
333
333
  };
334
- //# sourceMappingURL=video-decode.worker.tOv-QR2f.js.map
334
+ //# sourceMappingURL=video-decode.worker.BQtw6eWn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video-decode.worker.BQtw6eWn.js","sources":["../../../../src/utils/platform-utils.ts","../../../../src/stages/decode/VideoChunkDecoder.ts","../../../../src/stages/decode/video-decode.worker.ts"],"sourcesContent":["/**\n * Platform detection utilities with caching for performance\n */\n\nexport interface PlatformInfo {\n isWindows: boolean;\n isMacOS: boolean;\n isLinux: boolean;\n platform: string;\n userAgent: string;\n}\n\n// Cache platform detection result (only detect once)\nlet cachedPlatformInfo: PlatformInfo | null = null;\n\n/**\n * Detect current platform (cached after first call)\n */\nexport function detectPlatform(): PlatformInfo {\n if (cachedPlatformInfo) {\n return cachedPlatformInfo;\n }\n\n const platform = typeof navigator !== 'undefined' ? navigator.platform : '';\n const userAgent = typeof navigator !== 'undefined' ? navigator.userAgent : '';\n\n cachedPlatformInfo = {\n isWindows: /Win/i.test(platform) || /Win/i.test(userAgent),\n isMacOS: /Mac/i.test(platform),\n isLinux: /Linux/i.test(platform),\n platform,\n userAgent,\n };\n\n return cachedPlatformInfo;\n}\n\n/**\n * Check if current platform is Windows (cached)\n */\nexport function isWindows(): boolean {\n return detectPlatform().isWindows;\n}\n\n/**\n * Check if current platform is macOS (cached)\n */\nexport function isMacOS(): boolean {\n return detectPlatform().isMacOS;\n}\n\n/**\n * Check if current platform is Linux (cached)\n */\nexport function isLinux(): boolean {\n return detectPlatform().isLinux;\n}\n\n/**\n * Get platform-recommended hardware acceleration setting for video decoding\n *\n * Background:\n * Windows hardware video decoders (especially with DXVA2/D3D11) may hang indefinitely\n * when calling VideoDecoder.flush() in certain scenarios (frequent seeks, large GOPs).\n * This appears to be a driver/platform-specific issue affecting Chromium's WebCodecs.\n *\n * Related discussions:\n * - https://github.com/w3c/webcodecs/issues\n * - Observed in production on Windows 10/11 with various GPU vendors\n *\n * Workaround:\n * Use software decoding on Windows to avoid flush() hangs, with ~4x slower decode\n * but reliable operation. Other platforms use hardware acceleration by default.\n *\n * @returns Platform-recommended hardware acceleration setting\n */\nexport function getRecommendedHardwareAcceleration(): HardwareAcceleration {\n // Windows: prefer software to avoid flush hang in hardware decoders\n if (isWindows()) {\n return 'prefer-software';\n }\n\n // Other platforms: no preference (let browser choose)\n return 'no-preference';\n}\n","import { VideoDecoderConfig } from './types';\nimport { BaseDecoder } from './BaseDecoder';\nimport { getRecommendedHardwareAcceleration } from '../../utils/platform-utils';\n\n/**\n * Video decoder with GOP tracking\n * Tracks keyframe boundaries and attaches GOP metadata to decoded frames\n */\nexport class VideoChunkDecoder extends BaseDecoder<\n VideoDecoder,\n VideoDecoderConfig,\n EncodedVideoChunk,\n VideoFrame\n> {\n private static readonly DEFAULT_HIGH_WATER_MARK = 4;\n private static readonly DEFAULT_DECODE_QUEUE_THRESHOLD = 16;\n\n readonly trackId: string;\n\n protected readonly highWaterMark: number;\n protected readonly decodeQueueThreshold: number;\n\n // Buffering support for delayed configuration\n private bufferedChunks: EncodedVideoChunk[] = [];\n private isProcessingBuffer: boolean = false;\n\n constructor(trackId: string, config?: Partial<VideoDecoderConfig>) {\n super((config || {}) as VideoDecoderConfig);\n\n this.trackId = trackId;\n this.highWaterMark =\n config?.backpressure?.highWaterMark ?? VideoChunkDecoder.DEFAULT_HIGH_WATER_MARK;\n this.decodeQueueThreshold =\n config?.backpressure?.decodeQueueThreshold ??\n VideoChunkDecoder.DEFAULT_DECODE_QUEUE_THRESHOLD;\n }\n\n // Computed properties\n get isConfigured(): boolean {\n return this.isReady;\n }\n\n get state(): string {\n return this.decoder?.state || 'unconfigured';\n }\n\n /**\n * Update configuration - can be called before or after initialization\n */\n async updateConfig(config: Partial<VideoDecoderConfig>): Promise<void> {\n if (!this.isReady && config.codec) {\n await this.configure(config as VideoDecoderConfig);\n await this.processBufferedChunks();\n }\n }\n\n // Override createStream to handle GOP tracking and buffering\n // Always create new stream for each clip (ReadableStreams can only be consumed once)\n override createStream(): TransformStream<EncodedVideoChunk, VideoFrame> {\n return new TransformStream<EncodedVideoChunk, VideoFrame>(\n {\n start: async (controller) => {\n this.controller = controller;\n // Don't initialize if no codec config yet\n if (this.config?.codec && this.config?.description && !this.isReady) {\n await this.initialize();\n }\n },\n\n transform: async (chunk) => {\n // If not configured yet, buffer the chunk\n if (!this.isReady) {\n this.bufferedChunks.push(chunk);\n return; // Don't process yet\n }\n\n // If we're processing buffered chunks, add to buffer to maintain order\n if (this.isProcessingBuffer) {\n this.bufferedChunks.push(chunk);\n return;\n }\n\n // Normal processing\n await this.processChunk(chunk);\n },\n\n flush: async () => {\n if (this.isReady) {\n await this.flush();\n }\n },\n },\n {\n highWaterMark: this.highWaterMark,\n size: () => 1,\n }\n );\n }\n\n /**\n * Process a single chunk (extracted from transform for reuse)\n */\n private async processChunk(chunk: EncodedVideoChunk): Promise<void> {\n if (!this.decoder) {\n throw new Error('Decoder not initialized');\n }\n\n if (this.decoder.state !== 'configured') {\n console.error('[VideoChunkDecoder] Decoder in unexpected state:', this.decoder.state);\n throw new Error(`Decoder not configured, state: ${this.decoder.state}`);\n }\n\n this.decode(chunk);\n }\n\n // Override handleOutput to enqueue decoded frames\n protected override handleOutput(frame: VideoFrame): void {\n super.handleOutput(frame);\n }\n\n // Implement abstract methods\n protected async isConfigSupported(config: VideoDecoderConfig): Promise<{ supported: boolean }> {\n const result = await VideoDecoder.isConfigSupported({\n codec: config.codec,\n codedWidth: config.width,\n codedHeight: config.height,\n });\n return { supported: result.supported ?? false };\n }\n\n protected createDecoder(init: {\n output: (frame: VideoFrame) => void;\n error: (error: DOMException) => void;\n }): VideoDecoder {\n return new VideoDecoder(init);\n }\n\n protected getDecoderType(): string {\n return 'Video';\n }\n\n protected async configureDecoder(config: VideoDecoderConfig): Promise<void> {\n if (!this.decoder) return;\n\n const hardwareAcceleration =\n config.hardwareAcceleration ?? getRecommendedHardwareAcceleration();\n\n const decoderConfig = {\n codec: config.codec,\n codedWidth: config.width,\n codedHeight: config.height,\n hardwareAcceleration,\n optimizeForLatency: true,\n ...(config.description && { description: config.description }),\n ...(config.displayAspectWidth && { displayAspectWidth: config.displayAspectWidth }),\n ...(config.displayAspectHeight && { displayAspectHeight: config.displayAspectHeight }),\n };\n\n this.decoder.configure(decoderConfig as any);\n\n // Log when using software decoding for debugging\n if (hardwareAcceleration === 'prefer-software') {\n console.info('[VideoChunkDecoder] Using software decoding for platform compatibility');\n }\n }\n\n protected decode(chunk: EncodedVideoChunk): void {\n this.decoder?.decode(chunk);\n }\n\n /**\n * Configure the decoder with codec info (can be called after creation)\n */\n async configure(config: VideoDecoderConfig): Promise<void> {\n // console.log('[VideoChunkDecoder] Configuring with:', config);\n\n if (this.isReady) {\n // If already configured, reconfigure\n await this.reconfigure(config);\n return;\n }\n\n this.config = config as any;\n\n // Initialize decoder with new config\n await this.initialize();\n }\n\n /**\n * Process any buffered chunks after configuration\n */\n async processBufferedChunks(): Promise<void> {\n if (!this.isReady || this.bufferedChunks.length === 0) {\n return;\n }\n\n // console.log('[VideoChunkDecoder] Processing', this.bufferedChunks.length, 'buffered chunks');\n this.isProcessingBuffer = true;\n\n // Process buffered chunks in order\n const chunks = [...this.bufferedChunks];\n this.bufferedChunks = [];\n\n for (const chunk of chunks) {\n try {\n await this.processChunk(chunk);\n } catch (error) {\n console.error('[VideoChunkDecoder] Error processing buffered chunk:', error);\n }\n }\n\n this.isProcessingBuffer = false;\n\n // Process any new chunks that arrived while processing buffer\n if (this.bufferedChunks.length > 0) {\n await this.processBufferedChunks();\n }\n }\n\n // Override close to clean up buffered chunks\n override async close(): Promise<void> {\n // Clear buffered chunks\n this.bufferedChunks = [];\n\n // Call parent close\n await super.close();\n }\n}\n","/**\n * @deprecated VideoDecodeWorker is deprecated and will be removed in a future version.\n *\n * Reason: Export pipeline now uses OnDemandVideoSession (main thread) for decoding.\n * This eliminates the need for EncodedVideoChunk serialization and provides better\n * code reuse with preview's decoding logic.\n *\n * Replacement: OnDemandVideoSession (packages/core/src/orchestrator/OnDemandVideoSession.ts)\n *\n * New pipeline: IndexedVideoSource → OnDemandVideoSession (decode) → ComposeWorker → EncodeWorker\n * All in main thread before ComposeWorker, avoiding worker communication overhead.\n *\n * This file is kept for backward compatibility only and may be removed in the future.\n */\n\nimport { WorkerChannel } from '../../worker/WorkerChannel';\nimport { WorkerMessageType, WorkerState } from '../../worker/types';\nimport { VideoChunkDecoder } from './VideoChunkDecoder';\nimport { VideoDecoderConfig } from './types';\n\nconst normalizeDescription = (desc?: ArrayBuffer | ArrayBufferView): ArrayBuffer | undefined => {\n if (!desc) return undefined;\n\n if (desc instanceof ArrayBuffer) return desc;\n\n const view = desc as ArrayBufferView;\n return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength) as ArrayBuffer;\n};\n\n/**\n * VideoDecodeWorker (Clip Local) - Decodes video for a single clip\n * Receives encoded video chunks from VideoDemuxWorker and outputs decoded frames\n *\n * Pipeline: VideoDemuxWorker → VideoDecodeWorker → VideoComposeWorker\n *\n * Features:\n * - Single clip, single VideoDecoder instance (no routing)\n * - GOP-based decoding with metadata\n * - Stream-based processing with backpressure\n * - Lifecycle tied to clip pipeline\n */\nexport class VideoDecodeWorker {\n private channel: WorkerChannel;\n private decoder: VideoChunkDecoder | null = null;\n private clipId: string = '';\n\n private defaultConfig: Partial<VideoDecoderConfig> = {};\n\n private upstreamPort: MessagePort | null = null;\n private downstreamPort: MessagePort | null = null;\n\n constructor() {\n this.channel = new WorkerChannel(self as any, {\n name: 'VideoDecodeWorker',\n timeout: 30000,\n });\n\n this.setupHandlers();\n }\n\n private setupHandlers(): void {\n this.channel.registerHandler('configure', this.handleConfigure.bind(this));\n this.channel.registerHandler('connect', this.handleConnect.bind(this));\n this.channel.registerHandler('flush', this.handleFlush.bind(this));\n this.channel.registerHandler('reset', this.handleReset.bind(this));\n this.channel.registerHandler('get_stats', this.handleGetStats.bind(this));\n this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));\n }\n\n private async handleConnect(payload: {\n direction: 'upstream' | 'downstream';\n port: MessagePort;\n streamType?: 'video';\n sessionId?: string;\n clipStartUs?: number;\n clipDurationUs?: number;\n }): Promise<{ success: boolean }> {\n const { port, direction, sessionId } = payload;\n\n if (direction === 'upstream') {\n this.upstreamPort = port;\n this.clipId = sessionId || 'default';\n\n const channel = new WorkerChannel(port, {\n name: 'Demux-VideoDecode',\n timeout: 30000,\n });\n\n channel.receiveStream((stream, metadata) => {\n this.handleReceiveStream(stream, {\n ...metadata,\n clipStartUs: payload.clipStartUs,\n clipDurationUs: payload.clipDurationUs,\n });\n });\n\n channel.registerHandler('configure', this.handleConfigure.bind(this));\n }\n\n if (direction === 'downstream') {\n this.downstreamPort = port;\n }\n\n return { success: true };\n }\n\n private async handleConfigure(payload: {\n config?: { video?: Partial<VideoDecoderConfig> };\n sessionId?: string;\n streamType?: 'video';\n codec?: string;\n width?: number;\n height?: number;\n description?: ArrayBuffer | Uint8Array;\n }): Promise<{ success: boolean }> {\n const { sessionId, streamType, codec, width, height, description, config } = payload;\n\n if (sessionId && streamType === 'video') {\n if (this.decoder) {\n await this.decoder.updateConfig({\n codec,\n width,\n height,\n description: normalizeDescription(description),\n });\n }\n return { success: true };\n }\n\n if (config?.video) {\n Object.assign(this.defaultConfig, config.video);\n\n if (this.decoder) {\n await this.decoder.updateConfig(config.video);\n }\n }\n\n this.channel.state = WorkerState.Ready;\n\n return { success: true };\n }\n\n private async handleReceiveStream(\n stream: ReadableStream,\n metadata?: Record<string, any>\n ): Promise<void> {\n const sessionId = metadata?.sessionId || this.clipId;\n\n if (!this.decoder) {\n this.decoder = new VideoChunkDecoder(sessionId, {\n ...this.defaultConfig,\n codec: metadata?.codec,\n width: metadata?.width,\n height: metadata?.height,\n description: normalizeDescription(metadata?.description),\n });\n }\n\n const transform = this.decoder.createStream();\n\n if (this.downstreamPort) {\n const channel = new WorkerChannel(this.downstreamPort, {\n name: 'VideoDecode-Compose',\n timeout: 30000,\n });\n\n channel.sendStream(transform.readable as ReadableStream, {\n streamType: 'video',\n sessionId,\n });\n\n stream\n .pipeTo(transform.writable)\n .catch((error) =>\n console.error('[VideoDecodeWorker] Video stream pipe error:', sessionId, error)\n );\n }\n }\n\n private async handleFlush(): Promise<{ success: boolean }> {\n if (this.decoder) {\n await this.decoder.flush();\n }\n return { success: true };\n }\n\n private async handleReset(): Promise<{ success: boolean }> {\n if (this.decoder) {\n await this.decoder.reset();\n }\n\n this.channel.notify('reset_complete', {\n type: 'video',\n });\n\n return { success: true };\n }\n\n private async handleGetStats(): Promise<{ video?: any }> {\n if (!this.decoder) {\n return {};\n }\n\n return {\n video: {\n clipId: this.clipId,\n configured: this.decoder.isConfigured,\n queueSize: this.decoder.queueSize,\n state: this.decoder.state,\n },\n };\n }\n\n private async handleDispose(): Promise<{ success: boolean }> {\n if (this.decoder) {\n await this.decoder.close();\n this.decoder = null;\n }\n\n this.upstreamPort?.close();\n this.upstreamPort = null;\n\n this.downstreamPort?.close();\n this.downstreamPort = null;\n\n this.channel.state = WorkerState.Disposed;\n\n return { success: true };\n }\n}\n\nconst worker = new VideoDecodeWorker();\n\nself.addEventListener('beforeunload', () => {\n worker['handleDispose']();\n});\n\nexport default null;\n"],"names":[],"mappings":"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"}