@agrhub/engine-pixi 0.0.0-stage → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/LICENSE +47 -0
  2. package/NOTICE.md +20 -0
  3. package/README.md +6 -2
  4. package/dist/animation/block-reveal-animation.d.ts +33 -0
  5. package/dist/animation/easings.d.ts +4 -0
  6. package/dist/animation/gsap-animation.d.ts +32 -0
  7. package/dist/animation/index.d.ts +9 -0
  8. package/dist/animation/keyframe-animation.d.ts +11 -0
  9. package/dist/animation/mask-animation.d.ts +170 -0
  10. package/dist/animation/pixi-animation-utils.d.ts +10 -0
  11. package/dist/animation/registry.d.ts +11 -0
  12. package/dist/animation/types.d.ts +211 -0
  13. package/dist/animation/wipe-animation.d.ts +53 -0
  14. package/dist/clips/audio-clip.d.ts +122 -0
  15. package/dist/clips/backdrop-clip.d.ts +56 -0
  16. package/dist/clips/base-clip.d.ts +150 -0
  17. package/dist/clips/base-text-clip.d.ts +228 -0
  18. package/dist/clips/caption-clip.d.ts +129 -0
  19. package/dist/clips/clip-registry.d.ts +56 -0
  20. package/dist/clips/effect-clip.d.ts +37 -0
  21. package/dist/clips/iclip.d.ts +235 -0
  22. package/dist/clips/image-clip.d.ts +116 -0
  23. package/dist/clips/index.d.ts +20 -0
  24. package/dist/clips/placeholder-clip.d.ts +22 -0
  25. package/dist/clips/shape-clip.d.ts +59 -0
  26. package/dist/clips/text-clip.d.ts +148 -0
  27. package/dist/clips/transition-clip.d.ts +45 -0
  28. package/dist/clips/video-clip.d.ts +216 -0
  29. package/dist/compositor/audio-mixer.d.ts +8 -0
  30. package/dist/compositor/av-encoder.d.ts +17 -0
  31. package/dist/compositor/clip-style-renderer.d.ts +23 -0
  32. package/dist/compositor/compositor-renderer.d.ts +29 -0
  33. package/dist/compositor/effect-manager.d.ts +30 -0
  34. package/dist/compositor/scheduler.d.ts +8 -0
  35. package/dist/compositor/transition-manager.d.ts +45 -0
  36. package/dist/compositor.d.ts +157 -0
  37. package/dist/effect/constant/index.d.ts +566 -0
  38. package/dist/effect/effect.d.ts +9 -0
  39. package/dist/effect/glsl/custom-glsl.d.ts +1043 -0
  40. package/dist/effect/glsl/gl-effect.d.ts +38 -0
  41. package/dist/effect/interface/index.d.ts +25 -0
  42. package/dist/effect/types.d.ts +26 -0
  43. package/dist/effect/vertex.d.ts +1 -0
  44. package/dist/event-emitter.d.ts +55 -0
  45. package/dist/filters/outline-filter.d.ts +28 -0
  46. package/dist/index.d.ts +27 -0
  47. package/dist/index.es.js +16144 -0
  48. package/dist/index.es.js.map +1 -0
  49. package/dist/index.umd.cjs +3335 -0
  50. package/dist/index.umd.cjs.map +1 -0
  51. package/dist/json-serialization.d.ts +312 -0
  52. package/dist/mp4-utils/index.d.ts +31 -0
  53. package/dist/mp4-utils/mp4box-utils.d.ts +44 -0
  54. package/dist/mp4-utils/sample-transform.d.ts +26 -0
  55. package/dist/sprite/base-sprite.d.ts +273 -0
  56. package/dist/sprite/pixi-sprite-renderer.d.ts +69 -0
  57. package/dist/standalone/index.es.js +94191 -0
  58. package/dist/standalone/index.es.js.map +1 -0
  59. package/dist/studio/history-manager.d.ts +46 -0
  60. package/dist/studio/resource-manager.d.ts +53 -0
  61. package/dist/studio/selection-manager.d.ts +66 -0
  62. package/dist/studio/timeline-model.d.ts +117 -0
  63. package/dist/studio/transport.d.ts +44 -0
  64. package/dist/studio-bridge.d.ts +50 -0
  65. package/dist/studio.d.ts +529 -0
  66. package/dist/transformer/handle.d.ts +17 -0
  67. package/dist/transformer/snapping.d.ts +45 -0
  68. package/dist/transformer/transformer.d.ts +38 -0
  69. package/dist/transformer/wireframe.d.ts +5 -0
  70. package/dist/transition/fragment.d.ts +1 -0
  71. package/dist/transition/glsl/custom-glsl.d.ts +231 -0
  72. package/dist/transition/glsl/gl-transition.d.ts +42 -0
  73. package/dist/transition/transition.d.ts +6 -0
  74. package/dist/transition/types.d.ts +31 -0
  75. package/dist/transition/uniforms.d.ts +35 -0
  76. package/dist/transition/vertex.d.ts +1 -0
  77. package/dist/utils/asset-manager.d.ts +15 -0
  78. package/dist/utils/audio-codec-detector.d.ts +39 -0
  79. package/dist/utils/audio.d.ts +81 -0
  80. package/dist/utils/chromakey.d.ts +24 -0
  81. package/dist/utils/color-adjustment.d.ts +53 -0
  82. package/dist/utils/color.d.ts +17 -0
  83. package/dist/utils/common.d.ts +7 -0
  84. package/dist/utils/dom.d.ts +48 -0
  85. package/dist/utils/effect.d.ts +1 -0
  86. package/dist/utils/fonts.d.ts +21 -0
  87. package/dist/utils/index.d.ts +6 -0
  88. package/dist/utils/log.d.ts +27 -0
  89. package/dist/utils/media-cache.d.ts +45 -0
  90. package/dist/utils/stream-utils.d.ts +4 -0
  91. package/dist/utils/video.d.ts +16 -0
  92. package/dist/utils/worker-timer.d.ts +1 -0
  93. package/package.json +63 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.umd.cjs","sources":["../src/utils/log.ts","../src/utils/audio.ts","../src/utils/audio-codec-detector.ts","../src/utils/chromakey.ts","../src/utils/worker-timer.ts","../src/utils/common.ts","../src/utils/dom.ts","../src/utils/video.ts","../src/event-emitter.ts","../src/animation/types.ts","../src/animation/easings.ts","../src/animation/keyframe-animation.ts","../src/animation/pixi-animation-utils.ts","../src/animation/gsap-animation.ts","../src/animation/wipe-animation.ts","../src/utils/color.ts","../src/animation/block-reveal-animation.ts","../src/animation/mask-animation.ts","../src/animation/registry.ts","../src/sprite/base-sprite.ts","../src/clips/base-clip.ts","../src/clips/iclip.ts","../src/utils/asset-manager.ts","../src/utils/media-cache.ts","../src/studio/resource-manager.ts","../src/clips/audio-clip.ts","../src/filters/outline-filter.ts","../src/utils/fonts.ts","../src/clips/base-text-clip.ts","../src/clips/caption-clip.ts","../src/clips/image-clip.ts","../src/mp4-utils/mp4box-utils.ts","../src/clips/video-clip.ts","../src/clips/text-clip.ts","../src/utils/effect.ts","../src/clips/effect-clip.ts","../src/clips/placeholder-clip.ts","../src/clips/transition-clip.ts","../src/clips/shape-clip.ts","../src/clips/backdrop-clip.ts","../src/clips/clip-registry.ts","../src/utils/stream-utils.ts","../src/mp4-utils/sample-transform.ts","../src/mp4-utils/index.ts","../src/json-serialization.ts","../src/compositor/scheduler.ts","../src/effect/glsl/custom-glsl.ts","../src/effect/vertex.ts","../src/utils/color-adjustment.ts","../src/sprite/pixi-sprite-renderer.ts","../src/transition/vertex.ts","../src/transition/uniforms.ts","../src/transition/fragment.ts","../src/transition/glsl/custom-glsl.ts","../src/transition/glsl/gl-transition.ts","../src/transition/transition.ts","../src/compositor/clip-style-renderer.ts","../src/compositor/transition-manager.ts","../src/effect/glsl/gl-effect.ts","../src/effect/constant/index.ts","../src/assets/texture1.png","../src/assets/texture2.png","../src/effect/effect.ts","../src/compositor/effect-manager.ts","../src/compositor/compositor-renderer.ts","../src/compositor/audio-mixer.ts","../src/compositor/av-encoder.ts","../src/compositor.ts","../src/studio-bridge.ts","../src/transformer/wireframe.ts","../src/transformer/handle.ts","../src/transformer/snapping.ts","../src/transformer/transformer.ts","../src/studio/selection-manager.ts","../src/studio/transport.ts","../src/studio/timeline-model.ts","../src/studio/history-manager.ts","../src/studio.ts"],"sourcesContent":["enum LogLevel {\n DEBUG = 0,\n INFO = 1,\n WARN = 2,\n ERROR = 3,\n}\n\nconst LEVEL_NAMES: Record<LogLevel, string> = {\n [LogLevel.DEBUG]: \"debug\",\n [LogLevel.INFO]: \"info\",\n [LogLevel.WARN]: \"warn\",\n [LogLevel.ERROR]: \"error\",\n};\n\ninterface HistoryEntry {\n level: string;\n time: string;\n args: any[];\n}\n\nfunction any2Str(val: any): string {\n if (val instanceof Error) return String(val);\n if (typeof val === \"object\" && val !== null) {\n try {\n return JSON.stringify(val, (_, v) => (v instanceof Error ? String(v) : v));\n } catch {\n return String(val);\n }\n }\n return String(val);\n}\n\nfunction getTimeStr() {\n const d = new Date();\n const pad = (n: number) => n.toString().padStart(2, \"0\");\n const ms = d.getMilliseconds().toString().padStart(3, \"0\");\n return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}.${ms}`;\n}\n\nclass InternalLogger {\n private threshold: LogLevel = LogLevel.INFO;\n private history: HistoryEntry[] = [];\n\n public debug = (...args: any[]) => this.log(LogLevel.DEBUG, console.debug, args);\n public info = (...args: any[]) => this.log(LogLevel.INFO, console.info, args);\n public warn = (...args: any[]) => this.log(LogLevel.WARN, console.warn, args);\n public error = (...args: any[]) => this.log(LogLevel.ERROR, console.error, args);\n\n private log(level: LogLevel, consoleMethod: (...args: any[]) => void, args: any[]) {\n if (level >= this.threshold) {\n consoleMethod(...args);\n this.history.push({\n level: LEVEL_NAMES[level],\n time: getTimeStr(),\n args,\n });\n }\n }\n\n public setThreshold(level: LogLevel) {\n this.threshold = level;\n }\n\n public getThreshold(): LogLevel {\n return this.threshold;\n }\n\n public createTagged(tag: string) {\n return {\n debug: (...args: any[]) => this.debug(tag, ...args),\n info: (...args: any[]) => this.info(tag, ...args),\n warn: (...args: any[]) => this.warn(tag, ...args),\n error: (...args: any[]) => this.error(tag, ...args),\n };\n }\n\n public dump(): string {\n return this.history\n .map(\n ({ level, time, args }) =>\n `[${level.toUpperCase()}][${time}] ${args.map(any2Str).join(\" \")}`,\n )\n .join(\"\\n\");\n }\n}\n\nconst logger = new InternalLogger();\n\n/**\n * Global logging utility.\n */\nexport const Log = {\n debug: logger.debug,\n info: logger.info,\n warn: logger.warn,\n error: logger.error,\n\n /**\n * Sets the logging threshold. Only logs at this level or higher will be recorded.\n * @example Log.setLogLevel(Log.warn) // Only warn and error will be logged\n */\n setLogLevel: <T extends Function>(logfn: T) => {\n const fn: any = logfn;\n if (fn === Log.debug) logger.setThreshold(LogLevel.DEBUG);\n else if (fn === Log.info) logger.setThreshold(LogLevel.INFO);\n else if (fn === Log.warn) logger.setThreshold(LogLevel.WARN);\n else if (fn === Log.error) logger.setThreshold(LogLevel.ERROR);\n },\n\n /**\n * Creates a logger instance that prefixes all messages with a tag.\n */\n create: (tag: string) => logger.createTagged(tag),\n\n /**\n * Dumps the log history as a string.\n */\n dump: async () => logger.dump(),\n};\n\n// Set initial log levels based on environment\nif (import.meta.env?.DEV) {\n Log.setLogLevel(Log.debug);\n} else if (import.meta.env?.MODE === \"test\") {\n Log.setLogLevel(Log.warn);\n}\n","// Audio utility functions that can run in both worker and main threads\n\nimport * as waveResampler from \"wave-resampler\";\n\n/**\n * Concatenate multiple Float32Arrays, commonly used for merging PCM data\n */\nexport function concatFloat32Array(buffers: Float32Array[]): Float32Array {\n const result = new Float32Array(buffers.map((buf) => buf.length).reduce((a, b) => a + b));\n\n let offset = 0;\n for (const buf of buffers) {\n result.set(buf, offset);\n offset += buf.length;\n }\n\n return result;\n}\n\n/**\n * Merge small PCM fragments into a large fragment\n * @param fragments Small PCM fragments, where each element is raw PCM data from different channels\n */\nexport function concatPCMFragments(fragments: Float32Array[][]): Float32Array[] {\n // fragments: [[chan0, chan1], [chan0, chan1]...]\n // chanListPCM: [[chan0, chan0...], [chan1, chan1...]]\n const chanListPCM: Float32Array[][] = [];\n for (let i = 0; i < fragments.length; i += 1) {\n for (let j = 0; j < fragments[i].length; j += 1) {\n if (chanListPCM[j] == null) chanListPCM[j] = [];\n chanListPCM[j].push(fragments[i][j]);\n }\n }\n // [bigChan0, bigChan1]\n return chanListPCM.map(concatFloat32Array);\n}\n\n/**\n * Utility function to extract PCM data from AudioData\n */\nexport function extractPCM4AudioData(audioData: AudioData): Float32Array[] {\n if (audioData.format === \"f32-planar\") {\n const result = [];\n for (let idx = 0; idx < audioData.numberOfChannels; idx += 1) {\n const chanBufSize = audioData.allocationSize({ planeIndex: idx });\n const chanBuf = new ArrayBuffer(chanBufSize);\n audioData.copyTo(chanBuf, { planeIndex: idx });\n result.push(new Float32Array(chanBuf));\n }\n return result;\n } else if (audioData.format === \"f32\") {\n const buf = new ArrayBuffer(audioData.allocationSize({ planeIndex: 0 }));\n audioData.copyTo(buf, { planeIndex: 0 });\n return convertF32ToPlanar(new Float32Array(buf), audioData.numberOfChannels);\n } else if (audioData.format === \"s16\") {\n const buf = new ArrayBuffer(audioData.allocationSize({ planeIndex: 0 }));\n audioData.copyTo(buf, { planeIndex: 0 });\n return convertS16ToF32Planar(new Int16Array(buf), audioData.numberOfChannels);\n }\n throw Error(\"Unsupported audio data format\");\n}\n\n/**\n * Convert s16 PCM to f32-planar\n * @param pcmS16Data - The s16 PCM data.\n * @param numChannels - Number of audio channels.\n * @returns An array of Float32Array, each containing the audio data for one channel.\n */\nfunction convertS16ToF32Planar(pcmS16Data: Int16Array, numChannels: number) {\n const numSamples = pcmS16Data.length / numChannels;\n const planarData = Array.from({ length: numChannels }, () => new Float32Array(numSamples));\n\n for (let i = 0; i < numSamples; i++) {\n for (let channel = 0; channel < numChannels; channel++) {\n const sample = pcmS16Data[i * numChannels + channel];\n planarData[channel][i] = sample / 32768; // Normalize to range [-1.0, 1.0]\n }\n }\n\n return planarData;\n}\n\nfunction convertF32ToPlanar(pcmF32Data: Float32Array, numChannels: number) {\n const numSamples = pcmF32Data.length / numChannels;\n const planarData = Array.from({ length: numChannels }, () => new Float32Array(numSamples));\n\n for (let i = 0; i < numSamples; i++) {\n for (let channel = 0; channel < numChannels; channel++) {\n planarData[channel][i] = pcmF32Data[i * numChannels + channel];\n }\n }\n\n return planarData;\n}\n\n/**\n * Extract PCM from AudioBuffer\n */\nexport function extractPCM4AudioBuffer(audioBuffer: AudioBuffer): Float32Array[] {\n return Array(audioBuffer.numberOfChannels)\n .fill(0)\n .map((_, idx) => {\n return audioBuffer.getChannelData(idx);\n });\n}\n\n/**\n * Mix PCM data from dual-channel audio tracks and interleave multiple channels into a single Float32Array output\n * @param audios - A 2D array where each element is a Float32Array array representing PCM data from an audio stream.\n * The first element of each Float32Array array is left channel data, and the second element (if present) is right channel data.\n * If only left channel data exists, the right channel will reuse the left channel data.\n *\n * @returns Returns a Float32Array with left and right channels interleaved.\n *\n * @example\n *\n * const audios = [\n * [new Float32Array([0.1, 0.2, 0.3]), new Float32Array([0.4, 0.5, 0.6])],\n * [new Float32Array([0.7, 0.8, 0.9])],\n * ];\n * const mixed = mixinPCM(audios);\n */\nexport function mixinPCM(audios: Float32Array[][]): Float32Array {\n const maxLen = Math.max(...audios.map((a) => a[0]?.length ?? 0));\n const data = new Float32Array(maxLen * 2);\n\n for (let bufIdx = 0; bufIdx < maxLen; bufIdx++) {\n let ch0 = 0;\n let ch1 = 0;\n for (let trackIdx = 0; trackIdx < audios.length; trackIdx++) {\n const c0 = audios[trackIdx][0]?.[bufIdx] ?? 0;\n // If mono PCM, duplicate first channel to second channel\n const c1 = audios[trackIdx][1]?.[bufIdx] ?? c0;\n ch0 += c0;\n ch1 += c1;\n }\n data[bufIdx] = ch0;\n data[bufIdx + maxLen] = ch1;\n }\n\n return data;\n}\n\n/**\n * Resample PCM audio data.\n *\n * @param pcmData - A Float32Array array where each element represents PCM data from one channel.\n * @param curRate - Current sample rate.\n * @param target - Target parameters object.\n * @param target.rate - Target sample rate.\n * @param target.chanCount - Target channel count.\n *\n * @returns Returns a Promise that resolves to a Float32Array array where each element represents PCM data from one channel after resampling.\n *\n * @example\n *\n * const pcmData = [new Float32Array([0.1, 0.2, 0.3]), new Float32Array([0.4, 0.5, 0.6])];\n * const curRate = 44100;\n * const target = { rate: 48000, chanCount: 2 };\n * const resampled = await audioResample(pcmData, curRate, target);\n */\nexport async function audioResample(\n pcmData: Float32Array[],\n curRate: number,\n target: {\n rate: number;\n chanCount: number;\n },\n): Promise<Float32Array[]> {\n const chanCount = pcmData.length;\n const emptyPCM = Array(target.chanCount)\n .fill(0)\n .map(() => new Float32Array(0));\n if (chanCount === 0) return emptyPCM;\n\n const len = Math.max(...pcmData.map((c) => c.length));\n if (len === 0) return emptyPCM;\n\n // The Worker scope does not have access to OfflineAudioContext\n if (globalThis.OfflineAudioContext == null) {\n return pcmData.map(\n (p) =>\n new Float32Array(\n waveResampler.resample(p, curRate, target.rate, {\n method: \"sinc\",\n LPF: false,\n }),\n ),\n );\n }\n\n const ctx = new globalThis.OfflineAudioContext(\n target.chanCount,\n (len * target.rate) / curRate,\n target.rate,\n );\n const abSource = ctx.createBufferSource();\n const ab = ctx.createBuffer(chanCount, len, curRate);\n // Create new Float32Array to ensure ArrayBuffer (not SharedArrayBuffer) backing\n pcmData.forEach((d, idx) => ab.copyToChannel(new Float32Array(d), idx));\n\n abSource.buffer = ab;\n abSource.connect(ctx.destination);\n abSource.start();\n\n return extractPCM4AudioBuffer(await ctx.startRendering());\n}\n\n/**\n * Extract a circular slice from the given Float32Array, looping from 0 when exceeding boundaries\n *\n * Mainly used for slicing PCM data to implement looped playback\n *\n * @param data - Input Float32Array.\n * @param start - Start index of the slice.\n * @param end - End index of the slice.\n * @returns Returns a new Float32Array containing data from start to end.\n *\n * @example\n * const data = new Float32Array([0, 1, 2, 3, 4, 5]);\n * ringSliceFloat32Array(data, 4, 6); // => Float32Array [4, 5, 0]\n */\nexport function ringSliceFloat32Array(\n data: Float32Array,\n start: number,\n end: number,\n): Float32Array {\n const count = end - start;\n const result = new Float32Array(count);\n let i = 0;\n while (i < count) {\n result[i] = data[(start + i) % data.length];\n i += 1;\n }\n return result;\n}\n\n/**\n * Change PCM data playback rate, where 1 means normal playback, 0.5 means half speed, and 2 means double speed\n */\nexport function changePCMPlaybackRate(pcmData: Float32Array, playbackRate: number) {\n // Calculate new length\n const newLength = Math.floor(pcmData.length / playbackRate);\n const newPcmData = new Float32Array(newLength);\n\n // Linear interpolation\n for (let i = 0; i < newLength; i++) {\n // Position in original data\n const originalIndex = i * playbackRate;\n const intIndex = Math.floor(originalIndex);\n const frac = originalIndex - intIndex;\n\n // Boundary check\n if (intIndex + 1 < pcmData.length) {\n newPcmData[i] = pcmData[intIndex] * (1 - frac) + pcmData[intIndex + 1] * frac;\n } else {\n newPcmData[i] = pcmData[intIndex]; // Last sample\n }\n }\n\n return newPcmData;\n}\n\nexport interface IFade {\n duration: number; // ms\n curve?: \"linear\" | \"ease-in\" | \"ease-out\" | \"ease-in-out\";\n}\n\nexport function getEaseFactor(\n t: number,\n curve?: \"linear\" | \"ease-in\" | \"ease-out\" | \"ease-in-out\",\n): number {\n const clampedT = Math.max(0, Math.min(1, t));\n if (!curve || curve === \"linear\") return clampedT;\n if (curve === \"ease-in\") return clampedT * clampedT;\n if (curve === \"ease-out\") return clampedT * (2 - clampedT);\n if (curve === \"ease-in-out\") {\n return clampedT < 0.5 ? 2 * clampedT * clampedT : -1 + (4 - 2 * clampedT) * clampedT;\n }\n return clampedT;\n}\n\nexport function applyAudioFade(\n audio: Float32Array[],\n endTimeMicro: number,\n clipDurationMicro: number,\n sampleRate: number,\n fadeIn?: IFade,\n fadeOut?: IFade,\n): void {\n if (!audio || audio.length === 0 || audio[0].length === 0) return;\n const length = audio[0].length;\n const durationMicro = (length / sampleRate) * 1e6;\n const startTimeMicro = endTimeMicro - durationMicro;\n\n const hasFadeIn = fadeIn !== undefined && fadeIn.duration > 0;\n const hasFadeOut = fadeOut !== undefined && fadeOut.duration > 0;\n if (!hasFadeIn && !hasFadeOut) return;\n\n const fadeInDurationMicro = hasFadeIn ? fadeIn!.duration * 1000 : 0;\n const fadeOutDurationMicro = hasFadeOut ? fadeOut!.duration * 1000 : 0;\n\n for (const chan of audio) {\n for (let i = 0; i < chan.length; i++) {\n const sampleClipTime = startTimeMicro + (i / sampleRate) * 1e6;\n let fadeMultiplier = 1.0;\n\n if (hasFadeIn && sampleClipTime < fadeInDurationMicro) {\n const t = sampleClipTime / fadeInDurationMicro;\n fadeMultiplier *= getEaseFactor(t, fadeIn!.curve);\n }\n\n if (hasFadeOut) {\n const fadeOutStartTime = clipDurationMicro - fadeOutDurationMicro;\n if (sampleClipTime >= fadeOutStartTime) {\n const timeInFadeOut = sampleClipTime - fadeOutStartTime;\n const t = 1.0 - timeInFadeOut / fadeOutDurationMicro;\n fadeMultiplier *= getEaseFactor(t, fadeOut!.curve);\n }\n }\n\n chan[i] *= Math.max(0, Math.min(1, fadeMultiplier));\n }\n }\n}\n","/**\n * Audio codec detection utility\n * Detects the best supported audio codec based on browser capabilities\n */\n\nexport interface AudioCodecConfig {\n codec: string;\n codecType: \"aac\" | \"opus\"; // Simplified type for recodemux\n sampleRate: number;\n channelCount: number;\n}\n\n/**\n * Preferred codec configurations in order of preference\n */\nconst CODEC_PREFERENCES = [\n {\n codec: \"mp4a.40.2\", // AAC-LC\n codecType: \"aac\" as const,\n sampleRate: 48000,\n channelCount: 2,\n },\n {\n codec: \"opus\",\n codecType: \"opus\" as const,\n sampleRate: 48000,\n channelCount: 2,\n },\n] as const;\n\nlet cachedCodec: AudioCodecConfig | null = null;\n\n/**\n * Test if a specific audio codec configuration is supported\n */\nasync function isCodecSupported(config: AudioCodecConfig): Promise<boolean> {\n if (typeof AudioEncoder === \"undefined\") {\n return false;\n }\n\n try {\n const result = await AudioEncoder.isConfigSupported({\n codec: config.codec,\n sampleRate: config.sampleRate,\n numberOfChannels: config.channelCount,\n });\n return result.supported ?? false;\n } catch (error) {\n return false;\n }\n}\n\n/**\n * Get the default audio codec configuration based on browser support\n * Prefers AAC (mp4a.40.2) but falls back to Opus if not supported\n *\n * @returns Promise resolving to the best supported audio codec configuration\n */\nexport async function getDefaultAudioCodec(): Promise<AudioCodecConfig> {\n // Return cached result if available\n if (cachedCodec !== null) {\n return cachedCodec;\n }\n\n // Test codecs in order of preference\n for (const config of CODEC_PREFERENCES) {\n const supported = await isCodecSupported(config);\n\n if (supported) {\n cachedCodec = { ...config };\n return cachedCodec;\n }\n }\n\n // Fallback to Opus if nothing else works (should never happen)\n const fallback = {\n codec: \"opus\",\n codecType: \"opus\" as const,\n sampleRate: 48000,\n channelCount: 2,\n };\n\n console.warn(\"[AudioCodec] No supported codec found, falling back to Opus\");\n cachedCodec = fallback;\n return fallback;\n}\n\n/**\n * Synchronously get the cached codec configuration\n * Returns null if detection hasn't been performed yet\n *\n * @returns The cached audio codec configuration or null\n */\nexport function getCachedAudioCodec(): AudioCodecConfig | null {\n return cachedCodec;\n}\n\nexport interface EncodableAudio {\n codecType: \"aac\" | \"opus\";\n sampleRate: number;\n}\n\nconst WEBCODECS_CODEC: Record<\"aac\" | \"opus\", string> = { aac: \"mp4a.40.2\", opus: \"opus\" };\n\n/**\n * Picks an audio encoding the environment can actually encode, starting from the requested one:\n * requested codec at the requested rate → same codec at 44.1 kHz → Opus at 48 kHz.\n * Returns null when nothing is encodable (the export should then drop audio instead of failing).\n * Headless Chromium on Linux (render workers) commonly lacks an AAC encoder.\n */\nexport async function resolveEncodableAudio(\n codecType: string | undefined,\n sampleRate: number,\n channelCount: number,\n): Promise<EncodableAudio | null> {\n if (typeof AudioEncoder === \"undefined\") return null;\n const requested: \"aac\" | \"opus\" = codecType === \"opus\" ? \"opus\" : \"aac\";\n const candidates: EncodableAudio[] = [\n { codecType: requested, sampleRate },\n ...(sampleRate !== 44100 ? [{ codecType: requested, sampleRate: 44100 }] : []),\n ...(requested !== \"opus\" ? [{ codecType: \"opus\" as const, sampleRate: 48000 }] : []),\n ];\n for (const c of candidates) {\n try {\n const { supported } = await AudioEncoder.isConfigSupported({\n codec: WEBCODECS_CODEC[c.codecType],\n sampleRate: c.sampleRate,\n numberOfChannels: channelCount,\n });\n if (supported) {\n if (c.codecType !== requested || c.sampleRate !== sampleRate) {\n console.warn(`[AudioCodec] ${requested} @ ${sampleRate}Hz is not encodable here; using ${c.codecType} @ ${c.sampleRate}Hz`);\n }\n return c;\n }\n } catch {\n // try the next candidate\n }\n }\n console.warn(`[AudioCodec] No encodable audio configuration found; audio will be skipped`);\n return null;\n}\n\n/**\n * Reset the cached codec (useful for testing)\n */\nexport function resetCodecCache(): void {\n cachedCodec = null;\n}\n","// Adapted from https://jameshfisher.com/2020/08/11/production-ready-green-screen-in-the-browser/\nconst vertexShader = `#version 300 es\n layout (location = 0) in vec4 a_position;\n layout (location = 1) in vec2 a_texCoord;\n out vec2 v_texCoord;\n void main () {\n gl_Position = a_position;\n v_texCoord = a_texCoord;\n }\n`;\n\nconst fragmentShader = `#version 300 es\nprecision mediump float;\nout vec4 FragColor;\nin vec2 v_texCoord;\n\nuniform sampler2D frameTexture;\nuniform vec3 keyColor;\n\n// Chroma similarity calculation\nuniform float similarity;\n// Smoothness calculation for transparency\nuniform float smoothness;\n// Reduce green screen saturation to improve keying accuracy\nuniform float spill;\n\nvec2 RGBtoUV(vec3 rgb) {\n return vec2(\n rgb.r * -0.169 + rgb.g * -0.331 + rgb.b * 0.5 + 0.5,\n rgb.r * 0.5 + rgb.g * -0.419 + rgb.b * -0.081 + 0.5\n );\n}\n\nvoid main() {\n // Get current pixel RGBA value\n vec4 rgba = texture(frameTexture, v_texCoord);\n // Calculate chroma difference between current pixel and key color\n vec2 chromaVec = RGBtoUV(rgba.rgb) - RGBtoUV(keyColor);\n // Calculate chroma distance (vector length) between current pixel and key color, smaller distance means more similar\n float chromaDist = sqrt(dot(chromaVec, chromaVec));\n // Set similarity threshold, negative baseMask indicates green screen, positive indicates not green screen\n float baseMask = chromaDist - similarity;\n // If baseMask is negative, fullMask equals 0; if baseMask is positive, larger value means lower transparency\n float fullMask = pow(clamp(baseMask / smoothness, 0., 1.), 1.5);\n rgba.a = fullMask; // Set transparency\n // If baseMask is negative, spillVal equals 0; if baseMask is positive, smaller value means lower saturation\n float spillVal = pow(clamp(baseMask / spill, 0., 1.), 1.5);\n float desat = clamp(rgba.r * 0.2126 + rgba.g * 0.7152 + rgba.b * 0.0722, 0., 1.); // Calculate current pixel grayscale\n rgba.rgb = mix(vec3(desat, desat, desat), rgba.rgb, spillVal);\n FragColor = rgba;\n}\n`;\n\nconst POINT_POS = [-1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1];\nconst TEX_COORD_POS = [0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1];\n\n// Initialize shader program to tell WebGL how to render our data\nfunction initShaderProgram(gl: WebGLRenderingContext, vsSource: string, fsSource: string) {\n const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource)!;\n const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource)!;\n\n // Create shader program\n const shaderProgram = gl.createProgram()!;\n gl.attachShader(shaderProgram, vertexShader);\n gl.attachShader(shaderProgram, fragmentShader);\n gl.linkProgram(shaderProgram);\n\n if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {\n throw Error(gl.getProgramInfoLog(shaderProgram) ?? \"Unable to initialize the shader program\");\n }\n\n return shaderProgram;\n}\n\n// Create shader of specified type, upload source code and compile\nfunction loadShader(gl: WebGLRenderingContext, type: number, source: string) {\n const shader = gl.createShader(type)!;\n\n // Send the source to the shader object\n gl.shaderSource(shader, source);\n\n // Compile the shader program\n gl.compileShader(shader);\n\n // See if it compiled successfully\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n const errMsg = gl.getShaderInfoLog(shader);\n gl.deleteShader(shader);\n throw Error(errMsg ?? \"An error occurred compiling the shaders\");\n }\n\n return shader;\n}\n\nfunction updateTexture(gl: WebGLRenderingContext, img: ImgSource, texture: WebGLTexture) {\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);\n gl.drawArrays(gl.TRIANGLES, 0, 6);\n}\n\nfunction initTexture(gl: WebGLRenderingContext) {\n const texture = gl.createTexture();\n if (texture == null) throw Error(\"Create WebGL texture error\");\n gl.bindTexture(gl.TEXTURE_2D, texture);\n\n // put a single pixel in the texture so we can use it immediately.\n const level = 0;\n const internalFormat = gl.RGBA;\n const width = 1;\n const height = 1;\n const border = 0;\n const srcFormat = gl.RGBA;\n const srcType = gl.UNSIGNED_BYTE;\n const pixel = new Uint8Array([0, 0, 255, 255]); // opaque blue\n gl.texImage2D(\n gl.TEXTURE_2D,\n level,\n internalFormat,\n width,\n height,\n border,\n srcFormat,\n srcType,\n pixel,\n );\n\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\n return texture;\n}\n\ninterface IChromakeyOpts {\n keyColor: [number, number, number];\n similarity: number;\n smoothness: number;\n spill: number;\n}\n\nfunction initCanvas(\n opts: {\n width: number;\n height: number;\n } & IChromakeyOpts,\n) {\n const canvas =\n \"document\" in globalThis\n ? globalThis.document.createElement(\"canvas\")\n : new OffscreenCanvas(opts.width, opts.height);\n canvas.width = opts.width;\n canvas.height = opts.height;\n\n const gl = canvas.getContext(\"webgl2\", {\n premultipliedAlpha: false,\n alpha: true,\n }) as WebGL2RenderingContext | null;\n\n if (gl == null) throw Error(\"Cant create gl context\");\n\n const shaderProgram = initShaderProgram(gl, vertexShader, fragmentShader);\n gl.useProgram(shaderProgram);\n\n gl.uniform3fv(\n gl.getUniformLocation(shaderProgram, \"keyColor\"),\n opts.keyColor.map((v) => v / 255),\n );\n gl.uniform1f(gl.getUniformLocation(shaderProgram, \"similarity\"), opts.similarity);\n gl.uniform1f(gl.getUniformLocation(shaderProgram, \"smoothness\"), opts.smoothness);\n gl.uniform1f(gl.getUniformLocation(shaderProgram, \"spill\"), opts.spill);\n\n const posBuffer = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(POINT_POS), gl.STATIC_DRAW);\n const a_position = gl.getAttribLocation(shaderProgram, \"a_position\");\n gl.vertexAttribPointer(a_position, 2, gl.FLOAT, false, Float32Array.BYTES_PER_ELEMENT * 2, 0);\n gl.enableVertexAttribArray(a_position);\n\n const texCoordBuffer = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(TEX_COORD_POS), gl.STATIC_DRAW);\n const a_texCoord = gl.getAttribLocation(shaderProgram, \"a_texCoord\");\n gl.vertexAttribPointer(a_texCoord, 2, gl.FLOAT, false, Float32Array.BYTES_PER_ELEMENT * 2, 0);\n gl.enableVertexAttribArray(a_texCoord);\n\n gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);\n\n return { canvas, gl };\n}\n\ntype ImgSource =\n | HTMLVideoElement\n | HTMLCanvasElement\n | HTMLImageElement\n | ImageBitmap\n | OffscreenCanvas\n | VideoFrame;\n\nfunction getSourceWH(imgSource: ImgSource) {\n return imgSource instanceof VideoFrame\n ? { width: imgSource.codedWidth, height: imgSource.codedHeight }\n : { width: imgSource.width, height: imgSource.height };\n}\n\nfunction getKeyColor(imgSource: ImgSource) {\n const canvas = new OffscreenCanvas(1, 1);\n const ctx = canvas.getContext(\"2d\")!;\n ctx.drawImage(imgSource, 0, 0);\n const {\n data: [r, g, b],\n } = ctx.getImageData(0, 0, 1, 1);\n return [r, g, b] as [number, number, number];\n}\n\n/**\n * Green screen keying\n * keyColor Background color to remove, if not provided will use first pixel\n * similarity Background color similarity threshold, too small may retain background, too large may remove more non-background pixels\n * smoothness Smoothness; too small may cause jagged edges, too large causes overall transparency\n * spill Saturation; too small may retain green spill, too large causes image to become grayscale\n * @param opts: {\n * keyColor?: [r, g, b]\n * similarity: number\n * smoothness: number\n * spill: number\n * }\n */\nexport const createChromakey = (\n opts: Omit<IChromakeyOpts, \"keyColor\"> & {\n keyColor?: [number, number, number];\n },\n) => {\n let canvas: HTMLCanvasElement | OffscreenCanvas | null = null;\n let gl: WebGLRenderingContext | null = null;\n let keyColor = opts.keyColor;\n let texture: WebGLTexture | null = null;\n\n return async (imgSource: ImgSource) => {\n if (canvas == null || gl == null || texture == null) {\n if (keyColor == null) keyColor = getKeyColor(imgSource);\n ({ canvas, gl } = initCanvas({\n ...getSourceWH(imgSource),\n keyColor: keyColor,\n ...opts,\n }));\n texture = initTexture(gl);\n }\n\n updateTexture(gl, imgSource, texture);\n\n if (globalThis.VideoFrame != null && imgSource instanceof globalThis.VideoFrame) {\n const frame = new VideoFrame(canvas, {\n alpha: \"keep\",\n timestamp: imgSource.timestamp,\n duration: imgSource.duration ?? undefined,\n });\n imgSource.close();\n return frame;\n }\n\n return createImageBitmap(canvas, {\n imageOrientation: imgSource instanceof ImageBitmap ? \"flipY\" : \"none\",\n });\n };\n};\n","const setup = (): void => {\n let timerId: number;\n\n let interval: number = 16.6;\n\n self.onmessage = (e) => {\n if (e.data.event === \"start\") {\n self.clearInterval(timerId);\n timerId = self.setInterval(() => {\n self.postMessage({});\n }, interval);\n }\n\n if (e.data.event === \"stop\") {\n self.clearInterval(timerId);\n }\n };\n};\n\nconst createWorker = (): Worker => {\n const blob = new Blob([`(${setup.toString()})()`]);\n const url = URL.createObjectURL(blob);\n return new Worker(url);\n};\n\nconst handlerMap = new Map<number, Set<() => void>>();\nlet runCount = 1;\n\nlet worker: Worker | null = null;\nif (globalThis.Worker != null) {\n worker = createWorker();\n worker.onmessage = () => {\n runCount += 1;\n for (const [k, v] of handlerMap) {\n if (runCount % k === 0) for (const fn of v) fn();\n }\n };\n}\n\nexport const workerTimer = (handler: () => void, time: number): (() => void) => {\n const groupId = Math.max(1, Math.round(time / 16.6));\n const fns = handlerMap.get(groupId) ?? new Set();\n fns.add(handler);\n handlerMap.set(groupId, fns);\n\n if (handlerMap.size === 1 && fns.size === 1) {\n worker?.postMessage({ event: \"start\" });\n }\n\n return () => {\n fns.delete(handler);\n if (fns.size === 0) handlerMap.delete(groupId);\n if (handlerMap.size === 0) {\n runCount = 0;\n worker?.postMessage({ event: \"stop\" });\n }\n };\n};\n","// Common utility functions that can run in both worker and main threads\n\nimport { Log } from \"./log\";\nimport { workerTimer } from \"./worker-timer\";\n\nif (import.meta.env?.DEV) {\n Log.setLogLevel(Log.debug);\n}\n\nif (import.meta.env?.MODE === \"test\") {\n Log.setLogLevel(Log.warn);\n}\n\n/**\n * Pause the current execution environment for a period of time.\n * @param time - Pause duration in milliseconds.\n * @example\n * await sleep(1000); // Pause for 1 second\n */\nexport function sleep(time: number): Promise<void> {\n return new Promise((resolve) => {\n const stop = workerTimer(() => {\n stop();\n resolve();\n }, time);\n });\n}\n","// Utility functions executed in the main thread\n\n/**\n * Create a new HTML element\n * @param tagName - Tag name of the element to create\n * @returns Newly created HTML element\n */\nexport function createEl(tagName: string): HTMLElement {\n return document.createElement(tagName);\n}\n\nfunction arrayBufferToBase64(buffer: ArrayBuffer) {\n var binary = \"\";\n var bytes = new Uint8Array(buffer);\n var len = bytes.byteLength;\n for (let i = 0; i < len; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return window.btoa(binary);\n}\n\n/**\n * Render text as an image\n * @param text - Text to render\n * @param cssText - CSS styles to apply to the text\n * @returns Rendered image element\n */\nexport async function renderTxt2Img(\n text: string,\n cssText: string,\n opts: {\n font?: { name: string; url: string };\n onCreated?: (el: HTMLElement) => void;\n } = {},\n): Promise<HTMLImageElement> {\n const div = createEl(\"pre\");\n div.style.cssText = `margin: 0; ${cssText}; position: fixed;`;\n div.textContent = text;\n document.body.appendChild(div);\n opts.onCreated?.(div);\n\n const { width, height } = div.getBoundingClientRect();\n // Calculate rect, immediately remove from DOM\n div.remove();\n\n const img = new Image();\n img.width = width;\n img.height = height;\n const fontFaceStr =\n opts.font == null\n ? \"\"\n : `\n @font-face {\n font-family: '${opts.font.name}';\n src: url('data:font/woff2;base64,${arrayBufferToBase64(await (await fetch(opts.font.url)).arrayBuffer())}') format('woff2');\n }\n `;\n const svgStr = `\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\">\n <style>\n ${fontFaceStr}\n </style>\n <foreignObject width=\"100%\" height=\"100%\">\n <div xmlns=\"http://www.w3.org/1999/xhtml\">${div.outerHTML}</div>\n </foreignObject>\n </svg>\n `\n .replace(/\\t/g, \"\")\n .replace(/#/g, \"%23\");\n\n img.src = `data:image/svg+xml;charset=utf-8,${svgStr}`;\n\n await new Promise((resolve) => {\n img.onload = resolve;\n });\n return img;\n}\n\n/**\n * Render text as {@link ImageBitmap} for creating {@link Image}\n * @param text - Text to render\n * @param cssText - CSS styles to apply to the text\n * @param opts - Options\n * @param opts.font - Custom font\n * @param opts.onCreated - Callback after creation\n *\n * // Example:\n * new Image(\n * await renderTxt2ImgBitmap(\n * 'Watermark',\n * `font-size:40px; color: white; text-shadow: 2px 2px 6px red; font-family: CustomFont;`,\n * {\n * font: {\n * name: 'CustomFont',\n * url: '/CustomFont.ttf',\n * },\n * },\n * )\n * )\n */\nexport async function renderTxt2ImgBitmap(\n text: string,\n cssText: string,\n opts: {\n font?: { name: string; url: string };\n onCreated?: (el: HTMLElement) => void;\n } = {},\n): Promise<ImageBitmap> {\n const imgEl = await renderTxt2Img(text, cssText, opts);\n const canvas = new OffscreenCanvas(imgEl.width, imgEl.height);\n const ctx = canvas.getContext(\"2d\");\n ctx?.drawImage(imgEl, 0, 0, imgEl.width, imgEl.height);\n return await createImageBitmap(canvas);\n}\n","// Video utility functions that can run in both worker and main threads\n\n/**\n * Decode image stream, return an array of video frames.\n *\n * @param stream - Readable stream containing image data.\n * @param type - MIME type of the image, e.g. 'image/jpeg'.\n *\n * @returns Returns a Promise that resolves to an array of {@link VideoFrame} after decoding completes.\n *\n * @example\n *\n * const frames = await decodeImg(\n * (await fetch('<gif url>')).body!,\n * `image/gif`,\n * );\n */\nexport async function decodeImg(\n stream: ReadableStream<Uint8Array>,\n type: string,\n): Promise<VideoFrame[]> {\n const init = {\n type,\n data: stream,\n };\n const imageDecoder = new ImageDecoder(init);\n\n await Promise.all([imageDecoder.completed, imageDecoder.tracks.ready]);\n\n const frameCount = imageDecoder.tracks.selectedTrack?.frameCount ?? 1;\n\n const result: VideoFrame[] = [];\n for (let i = 0; i < frameCount; i += 1) {\n result.push((await imageDecoder.decode({ frameIndex: i })).image);\n }\n return result;\n}\n","export type EventType = string | symbol;\n\n// An event handler can take an optional event argument\n// and should not return a value\nexport type Handler<T = unknown> = (event: T) => void;\nexport type WildcardHandler<T = Record<string, unknown>> = (\n type: keyof T,\n event: T[keyof T],\n) => void;\n\n// An array of all currently registered event handlers for a type\nexport type EventHandlerList<T = unknown> = Array<Handler<T>>;\nexport type WildCardEventHandlerList<T = Record<string, unknown>> = Array<WildcardHandler<T>>;\n\n// A map of event types and their corresponding event handlers.\nexport type EventHandlerMap<Events extends Record<EventType, unknown>> = Map<\n keyof Events | \"*\",\n EventHandlerList<Events[keyof Events]> | WildCardEventHandlerList<Events>\n>;\n\nexport interface Emitter<Events extends Record<EventType, unknown>> {\n all: EventHandlerMap<Events>;\n\n on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): void;\n on(type: \"*\", handler: WildcardHandler<Events>): void;\n\n off<Key extends keyof Events>(type: Key, handler?: Handler<Events[Key]>): void;\n off(type: \"*\", handler: WildcardHandler<Events>): void;\n\n emit<Key extends keyof Events>(type: Key, event: Events[Key]): void;\n emit<Key extends keyof Events>(type: undefined extends Events[Key] ? Key : never): void;\n}\n\n/**\n * EventEmitter: A class-based event emitter for inheritance\n */\nexport default class EventEmitter<\n Events extends Record<EventType, unknown>,\n> implements Emitter<Events> {\n public all: EventHandlerMap<Events> = new Map();\n\n /**\n * Register an event handler for the given type.\n * @param {string|symbol} type Type of event to listen for, or `'*'` for all events\n * @param {Function} handler Function to call in response to given event\n * @returns {Function} A function to unregister the handler\n */\n on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): () => void;\n on(type: \"*\", handler: WildcardHandler<Events>): () => void;\n on<Key extends keyof Events>(\n type: Key,\n handler: Handler<Events[Key]> | WildcardHandler<Events>,\n ): () => void {\n const handlers = this.all.get(type);\n if (handlers) {\n handlers.push(handler as any);\n } else {\n this.all.set(type, [handler as any]);\n }\n return () => this.off(type as any, handler as any);\n }\n\n /**\n * Register a one-time event handler for the given type.\n * @param {string|symbol} type Type of event to listen for\n * @param {Function} handler Function to call in response to given event\n * @returns {Function} A function to unregister the handler\n */\n once<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): () => void {\n const off = this.on(type, (evt) => {\n off();\n handler(evt);\n });\n return off;\n }\n\n /**\n * Remove an event handler for the given type.\n * If `handler` is omitted, all handlers of the given type are removed.\n * @param {string|symbol} type Type of event to unregister `handler` from (`'*'` to remove a wildcard handler)\n * @param {Function} [handler] Handler function to remove\n */\n off<Key extends keyof Events>(type: Key, handler?: Handler<Events[Key]>): void;\n off(type: \"*\", handler: WildcardHandler<Events>): void;\n off<Key extends keyof Events>(\n type: Key,\n handler?: Handler<Events[Key]> | WildcardHandler<Events>,\n ) {\n const handlers = this.all.get(type);\n if (handlers) {\n if (handler) {\n handlers.splice(handlers.indexOf(handler as any) >>> 0, 1);\n } else {\n this.all.set(type, []);\n }\n }\n }\n\n /**\n * Invoke all handlers for the given type.\n * If present, `'*'` handlers are invoked after type-matched handlers.\n *\n * Note: Manually firing '*' handlers is not supported.\n *\n * @param {string|symbol} type The event type to invoke\n * @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler\n */\n emit<Key extends keyof Events>(type: Key, event: Events[Key]): void;\n emit<Key extends keyof Events>(type: undefined extends Events[Key] ? Key : never): void;\n emit<Key extends keyof Events>(type: Key, evt?: Events[Key]) {\n let handlers = this.all.get(type);\n if (handlers) {\n (handlers as EventHandlerList<Events[keyof Events]>).slice().forEach((handler) => {\n handler(evt!);\n });\n }\n\n handlers = this.all.get(\"*\");\n if (handlers) {\n (handlers as WildCardEventHandlerList<Events>).slice().forEach((handler) => {\n handler(type, evt!);\n });\n }\n }\n}\n","export type EasingFunction = (t: number) => number;\n\nexport interface AnimationProps {\n x?: number;\n y?: number;\n width?: number;\n height?: number;\n scale?: number;\n scaleX?: number;\n scaleY?: number;\n opacity?: number;\n angle?: number;\n blur?: number;\n brightness?: number;\n mirror?: number;\n motionBlur?: number;\n}\n\nexport interface AnimationOptions {\n duration: number; // in microseconds\n delay?: number; // in microseconds\n easing?: string | EasingFunction;\n iterCount?: number;\n id?: string;\n disableGlobalEasing?: boolean;\n}\n\nexport interface IAnimation {\n readonly id: string;\n readonly type: string;\n readonly options: Required<AnimationOptions>;\n readonly params?: any;\n\n /**\n * Calculate offsets and multipliers for the given time\n * @param time Relative time from the start of the clip in microseconds\n * @returns Partial state containing offsets/multipliers\n */\n getTransform(time: number): AnimationTransform;\n\n /**\n * Apply complex animations (like GSAP character animations) directly to a target\n * @param target The target object (e.g., PixiJS Container)\n * @param time Relative time in microseconds\n */\n apply?(target: any, time: number): void;\n}\n\nexport interface AnimationTransform {\n x?: number; // additive offset\n y?: number; // additive offset\n width?: number; // additive offset\n height?: number; // additive offset\n scale?: number; // multiplier (relative to 1.0)\n scaleX?: number; // multiplier (relative to 1.0)\n scaleY?: number; // multiplier (relative to 1.0)\n opacity?: number; // multiplier (relative to 1.0)\n angle?: number; // additive offset\n blur?: number; // additive offset\n brightness?: number; // multiplier (relative to 1.0)\n mirror?: number; // 0 or 1 (boolean via number)\n motionBlur?: number; // additive offset\n // ─── Mask fields ─────────────────────────────────────────────────────────\n mask?: MaskTransform;\n}\n\n/**\n * Custom mask painter function.\n * Called by PixiSpriteRenderer when shape === \"custom\".\n * Receives a cleared Graphics object; draw your shape into it using Pixi's\n * Graphics API. Fill with white (0xffffff) — alpha determines mask opacity.\n *\n * @param g The cleared Graphics object to draw into\n * @param width Clip's logical width in pixels\n * @param height Clip's logical height in pixels\n * @param progress Normalized reveal progress 0→1\n */\nexport type MaskPainter = (\n g: { rect: any; circle: any; ellipse: any; fill: any; poly: any; [key: string]: any },\n width: number,\n height: number,\n progress: number,\n) => void;\n\nexport interface MaskTransform {\n /** Mask shape. Use \"custom\" and provide a `painter` for arbitrary paths. */\n shape: \"rect\" | \"circle\" | \"ellipse\" | \"custom\" | \"edgeCrop\";\n /**\n * Normalized progress 0–1 controlling how much of the clip is revealed.\n * 0 = fully hidden, 1 = fully visible.\n */\n progress: number;\n /** For rect: which edge the wipe sweeps from. For circle/ellipse: ignored. */\n direction?: \"left\" | \"right\" | \"top\" | \"bottom\";\n /** For angled wipe: rotation of the mask edge in degrees (0 = vertical sweep) */\n angle?: number;\n /** Origin point for expand masks (circle/ellipse/rectExpand). Default: \"center\" */\n origin?: \"center\" | \"topLeft\" | \"topRight\" | \"bottomLeft\" | \"bottomRight\";\n /** Soft edge width in pixels. 0 = hard edge. */\n feather?: number;\n /**\n * Normalized starting size of the mask (0–1). Default: 0.\n * e.g. 0.2 means the mask starts at 20% size and grows to 100%.\n * The painter receives a `progress` value already remapped from\n * initialProgress→1 so individual painters don't need to handle this.\n */\n initialProgress?: number;\n /** edgeCrop: horizontal crop distance in canvas pixels at progress 0. Default: 100 */\n xDistance?: number;\n /** edgeCrop: vertical crop distance in canvas pixels at progress 0. Default: 100 */\n yDistance?: number;\n /** edgeCrop: corner radius of the visible area. Default: 0 */\n maskBorderRadius?: number;\n /**\n * Custom painter for shape === \"custom\".\n * Draw any path into the provided Graphics object.\n * The renderer calls this instead of its built-in shape dispatch.\n */\n painter?: MaskPainter;\n}\n\nexport interface KeyframeData {\n [key: string]: Partial<AnimationProps & { easing?: string | EasingFunction }>;\n}\n\nexport const ANIMATABLE_PROPERTIES = {\n x: { label: \"X Position\", min: -2000, max: 2000, step: 1, default: 0 },\n y: { label: \"Y Position\", min: -2000, max: 2000, step: 1, default: 0 },\n width: { label: \"Width\", min: -1000, max: 1000, step: 1, default: 0 },\n height: { label: \"Height\", min: -1000, max: 1000, step: 1, default: 0 },\n scale: { label: \"Scale\", min: 0, max: 3, step: 0.1, default: 1 },\n scaleX: { label: \"Scale X\", min: 0, max: 3, step: 0.1, default: 1 },\n scaleY: { label: \"Scale Y\", min: 0, max: 3, step: 0.1, default: 1 },\n opacity: { label: \"Opacity\", min: 0, max: 1, step: 0.01, default: 1 },\n angle: { label: \"Rotation\", min: -360, max: 360, step: 1, default: 0 },\n blur: { label: \"Blur\", min: 0, max: 100, step: 1, default: 0 },\n brightness: { label: \"Brightness\", min: 0, max: 5, step: 0.1, default: 1 },\n mirror: { label: \"Mirror\", min: 0, max: 1, step: 1, default: 0 },\n motionBlur: { label: \"Motion Blur\", min: 0, max: 500, step: 1, default: 0 },\n} as const;\n","import { EasingFunction } from \"./types\";\n\nexport const easings: Record<string, EasingFunction> = {\n linear: (t) => t,\n\n easeInQuad: (t) => t * t,\n easeOutQuad: (t) => t * (2 - t),\n easeInOutQuad: (t) => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t),\n\n easeInCubic: (t) => t * t * t,\n easeOutCubic: (t) => --t * t * t + 1,\n easeInOutCubic: (t) => (t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1),\n\n easeInSine: (t) => 1 - Math.cos((t * Math.PI) / 2),\n easeOutSine: (t) => Math.sin((t * Math.PI) / 2),\n easeInOutSine: (t) => 0.5 * (1 - Math.cos(Math.PI * t)),\n\n easeInExpo: (t) => (t === 0 ? 0 : Math.pow(2, 10 * (t - 1))),\n easeOutExpo: (t) => (t === 1 ? 1 : 1 - Math.pow(2, -10 * t)),\n easeInOutExpo: (t) => {\n if (t === 0) return 0;\n if (t === 1) return 1;\n if ((t /= 0.5) < 1) return 0.5 * Math.pow(2, 10 * (t - 1));\n return 0.5 * (2 - Math.pow(2, -10 * --t));\n },\n\n easeInCirc: (t) => 1 - Math.sqrt(1 - t * t),\n easeOutCirc: (t) => Math.sqrt(1 - (t - 1) * (t - 1)),\n easeInOutCirc: (t) => {\n if ((t /= 0.5) < 1) return -0.5 * (Math.sqrt(1 - t * t) - 1);\n return 0.5 * (Math.sqrt(1 - (t - 2) * t) + 1);\n },\n\n slow: createSlowMo(0.5, 0.5, false),\n};\n\nexport function createSlowMo(\n linearRatio: number = 0.7,\n power: number = 0.7,\n yoyoMode: boolean = false,\n): EasingFunction {\n const lr = Math.min(1, linearRatio);\n const pow = lr < 1 ? power : 0;\n const t1 = (1 - lr) / 2;\n const t3 = t1 + lr;\n\n return (t: number) => {\n const r = t + (0.5 - t) * pow;\n if (t < t1) {\n const tMod = 1 - t / t1;\n return yoyoMode ? 1 - tMod * tMod : r - tMod * tMod * tMod * r;\n }\n if (t > t3) {\n const tMod = (t - t3) / t1;\n return yoyoMode ? (t === 1 ? 0 : 1 - tMod * tMod) : r + (t - r) * tMod * tMod * tMod;\n }\n return yoyoMode ? 1 : r;\n };\n}\n\nexport function getEasing(easing: string | EasingFunction | undefined): EasingFunction {\n if (typeof easing === \"function\") return easing;\n if (typeof easing === \"string\" && easings[easing]) return easings[easing];\n return easings.linear;\n}\n","import { getEasing } from \"./easings\";\nimport {\n AnimationOptions,\n AnimationProps,\n AnimationTransform,\n IAnimation,\n KeyframeData,\n} from \"./types\";\n\nexport class KeyframeAnimation implements IAnimation {\n readonly id: string;\n readonly type: string;\n readonly options: Required<AnimationOptions>;\n readonly params: any;\n private frames: Array<{\n progress: number;\n props: Partial<AnimationProps>;\n easing?: string | ((t: number) => number);\n }>;\n\n constructor(data: KeyframeData | any[], options: AnimationOptions, type: string = \"keyframes\") {\n this.id = options.id || `keyframe_${Math.random().toString(36).substr(2, 9)}`;\n this.type = type;\n this.params = data;\n this.options = {\n duration: options.duration,\n delay: options.delay ?? 0,\n easing: options.easing ?? \"linear\",\n iterCount: options.iterCount ?? 1,\n id: this.id,\n disableGlobalEasing: options.disableGlobalEasing ?? false,\n };\n\n // Handle array format (internal representation)\n if (Array.isArray(data)) {\n this.frames = data.map((f: any) => ({\n progress: f.progress,\n props: f.props || f, // handle cases where props is missing or is the object itself\n easing: f.easing,\n }));\n } else {\n // Handle object format (percentage keys)\n this.frames = Object.entries(data)\n .filter(([k]) => {\n if (k === \"from\" || k === \"to\") return true;\n const num = Number(k.replace(\"%\", \"\"));\n return !isNaN(num) && num >= 0 && num <= 100;\n })\n .map(([k, val]) => {\n const progress = { from: 0, to: 100 }[k] ?? Number(k.replace(\"%\", \"\"));\n\n const { easing, ...props } = val;\n return {\n progress: progress / 100,\n props,\n easing: easing,\n };\n })\n .sort((a, b) => a.progress - b.progress);\n }\n\n // Ensure 0 and 1 exist\n if (this.frames.length > 0 && this.frames[0].progress !== 0) {\n this.frames.unshift({ progress: 0, props: {} });\n }\n if (this.frames.length > 0 && this.frames[this.frames.length - 1].progress !== 1) {\n this.frames.push({ progress: 1, props: {} });\n }\n }\n\n getTransform(time: number): AnimationTransform {\n const { duration, delay, iterCount, easing, disableGlobalEasing } = this.options;\n const offsetTime = time - delay;\n\n if (offsetTime < 0) return {};\n\n // If iterCount is finite, the whole animation must finish at precisely 'duration'\n if (iterCount !== Infinity && offsetTime >= duration) {\n const transform = this.interpolateProps(1);\n // if ('mirror' in transform) {\n // (transform as any).mirror = 0;\n // }\n return transform;\n }\n\n const cycleDuration = iterCount === Infinity ? duration : duration / iterCount;\n let progress = (offsetTime % cycleDuration) / cycleDuration;\n\n if (!disableGlobalEasing && easing !== \"linear\") {\n const easingFn = getEasing(easing);\n progress = easingFn(progress);\n }\n\n return this.interpolateProps(progress);\n }\n\n private interpolateProps(progress: number): AnimationTransform {\n const idx = this.frames.findIndex((f) => f.progress >= progress);\n if (idx === -1) return this.frames[this.frames.length - 1].props as AnimationTransform;\n if (idx === 0) return this.frames[0].props as AnimationTransform;\n\n const startFrame = this.frames[idx - 1];\n const endFrame = this.frames[idx];\n\n const segmentProgress =\n (progress - startFrame.progress) / (endFrame.progress - startFrame.progress);\n\n // If global easing is used, the input progress is already eased.\n // In that case, we default to linear interpolation between keyframes\n // unless a specific per-segment easing is provided.\n const easingSource =\n endFrame.easing ?? (this.options.disableGlobalEasing ? this.options.easing : \"linear\");\n\n const easingFn = getEasing(easingSource);\n\n const easedProgress = easingFn(segmentProgress);\n\n const transform: AnimationTransform = {};\n const props = new Set([...Object.keys(startFrame.props), ...Object.keys(endFrame.props)]);\n\n for (const prop of props) {\n const p = prop as keyof AnimationProps;\n const def = p === \"scale\" || p === \"scaleX\" || p === \"scaleY\" || p === \"opacity\" ? 1 : 0;\n const s = startFrame.props[p] ?? def;\n const e = endFrame.props[p] ?? def;\n (transform as any)[p] = s + (e - s) * easedProgress;\n }\n\n return transform;\n }\n}\n","import gsap from \"gsap\";\n\n// List of properties that should be handled by PixiPlugin\nexport const pixiProps = [\n \"scale\",\n \"scaleX\",\n \"scaleY\",\n \"rotation\",\n \"skewX\",\n \"skewY\",\n \"skew\",\n \"pivotX\",\n \"pivotY\",\n \"pivot\",\n \"anchorX\",\n \"anchorY\",\n \"anchor\",\n \"blur\",\n \"brightness\",\n \"contrast\",\n \"grayscale\",\n \"hueRotate\",\n \"invert\",\n \"saturate\",\n \"threshold\",\n \"matrix\",\n];\n\nexport const hasPixiProp = (obj: any) =>\n obj && Object.keys(obj).some((key) => pixiProps.includes(key));\n\nexport const prepareVars = (vars: any): any => {\n if (!vars) return vars;\n const newVars: any = { ...vars };\n\n if (newVars.keyframes) {\n if (Array.isArray(newVars.keyframes)) {\n newVars.keyframes = newVars.keyframes.map((frame: any) => prepareVars(frame));\n } else if (typeof newVars.keyframes === \"object\") {\n const resolvedKf: Record<string, any> = {};\n for (const [kfKey, frame] of Object.entries(newVars.keyframes)) {\n if (frame && typeof frame === \"object\") {\n resolvedKf[kfKey] = prepareVars(frame);\n } else {\n resolvedKf[kfKey] = frame;\n }\n }\n newVars.keyframes = resolvedKf;\n }\n }\n\n if (!hasPixiProp(newVars)) return newVars;\n const pixiVars: any = {};\n pixiProps.forEach((prop) => {\n if (prop in newVars) {\n pixiVars[prop] = newVars[prop];\n delete newVars[prop];\n }\n });\n newVars.pixi = pixiVars;\n return newVars;\n};\n\nexport function resolveValue(val: any, baseVal: number): number {\n if (typeof val === \"number\") return val;\n if (typeof val === \"string\") {\n if (val.startsWith(\"+=\")) {\n return baseVal + parseFloat(val.substring(2));\n }\n if (val.startsWith(\"-=\")) {\n return baseVal - parseFloat(val.substring(2));\n }\n }\n const parsed = parseFloat(val);\n return isNaN(parsed) ? baseVal : parsed;\n}\n\nfunction getKeyframeKeys(to: any): Set<string> {\n const kfKeys = new Set<string>();\n if (to && to.keyframes) {\n if (Array.isArray(to.keyframes)) {\n to.keyframes.forEach((frame: any) => {\n if (frame && typeof frame === \"object\") {\n Object.keys(frame).forEach((k) => kfKeys.add(k));\n }\n });\n } else if (typeof to.keyframes === \"object\") {\n Object.values(to.keyframes).forEach((frame: any) => {\n if (frame && typeof frame === \"object\") {\n Object.keys(frame).forEach((k) => kfKeys.add(k));\n }\n });\n }\n }\n return kfKeys;\n}\n\nexport function resolveVars(\n from: any,\n to: any,\n baseSource: Record<string, any>,\n isOut: boolean,\n): { resolvedFrom: Record<string, any>; resolvedTo: Record<string, any> } {\n const resolvedFrom: Record<string, any> = {};\n const resolvedTo: Record<string, any> = {};\n\n const keys = new Set([...Object.keys(from || {}), ...Object.keys(to || {})]);\n const kfKeys = getKeyframeKeys(to);\n\n for (const key of keys) {\n if (\n [\"immediateRender\", \"ease\", \"duration\", \"stagger\", \"repeat\", \"yoyo\", \"keyframes\"].includes(\n key,\n )\n ) {\n if (from && key in from) resolvedFrom[key] = from[key];\n if (to && key in to) resolvedTo[key] = to[key];\n continue;\n }\n\n const baseVal = baseSource[key] ?? 0;\n\n if (kfKeys.has(key)) {\n const fromVal = from ? from[key] : undefined;\n resolvedFrom[key] = fromVal !== undefined ? resolveValue(fromVal, baseVal) : baseVal;\n continue;\n }\n\n if (isOut) {\n // For exit (out) animations:\n // If the property has a relative value in 'from', it represents the offset.\n // We want to start at the rest value (baseVal) and end at the offset value (baseVal + offset).\n const fromVal = from ? from[key] : undefined;\n const toVal = to ? to[key] : undefined;\n\n const isFromRelative =\n typeof fromVal === \"string\" && (fromVal.startsWith(\"+=\") || fromVal.startsWith(\"-=\"));\n const isToRelative =\n typeof toVal === \"string\" && (toVal.startsWith(\"+=\") || toVal.startsWith(\"-=\"));\n\n if (isFromRelative) {\n resolvedFrom[key] = baseVal;\n const offset = resolveValue(fromVal, 0);\n resolvedTo[key] = baseVal + offset;\n } else if (isToRelative) {\n resolvedFrom[key] = fromVal !== undefined ? resolveValue(fromVal, baseVal) : baseVal;\n const offset = resolveValue(toVal, 0);\n resolvedTo[key] = resolvedFrom[key] + offset;\n } else {\n resolvedFrom[key] = fromVal !== undefined ? resolveValue(fromVal, baseVal) : baseVal;\n resolvedTo[key] = toVal !== undefined ? resolveValue(toVal, baseVal) : baseVal;\n }\n } else {\n // For entrance (in) animations:\n // Resolve from relative to baseSource, and to relative to resolvedFrom.\n const fromVal = from ? from[key] : undefined;\n const toVal = to ? to[key] : undefined;\n\n resolvedFrom[key] = fromVal !== undefined ? resolveValue(fromVal, baseVal) : baseVal;\n const baseForTo = resolvedFrom[key];\n resolvedTo[key] = toVal !== undefined ? resolveValue(toVal, baseForTo) : baseVal;\n }\n }\n\n // Handle keyframes\n if (to && to.keyframes) {\n if (Array.isArray(to.keyframes)) {\n resolvedTo.keyframes = to.keyframes.map((frame: any) => {\n const { resolvedTo: frameResolved } = resolveVars(\n null,\n frame,\n { ...baseSource, ...resolvedFrom },\n isOut,\n );\n return frameResolved;\n });\n if (resolvedTo.keyframes.length > 0) {\n const lastFrame = resolvedTo.keyframes[resolvedTo.keyframes.length - 1];\n if (lastFrame && typeof lastFrame === \"object\") {\n Object.keys(lastFrame).forEach((key) => {\n if (resolvedTo[key] === undefined) {\n resolvedTo[key] = lastFrame[key];\n }\n });\n }\n }\n } else if (typeof to.keyframes === \"object\") {\n const resolvedKf: Record<string, any> = {};\n for (const [kfKey, frame] of Object.entries(to.keyframes)) {\n if (frame && typeof frame === \"object\") {\n const { resolvedTo: frameResolved } = resolveVars(\n null,\n frame,\n { ...baseSource, ...resolvedFrom },\n isOut,\n );\n resolvedKf[kfKey] = frameResolved;\n } else {\n resolvedKf[kfKey] = frame;\n }\n }\n resolvedTo.keyframes = resolvedKf;\n\n const kf100 = resolvedKf[\"100%\"];\n if (kf100 && typeof kf100 === \"object\") {\n Object.keys(kf100).forEach((key) => {\n if (resolvedTo[key] === undefined) {\n resolvedTo[key] = kf100[key];\n }\n });\n }\n }\n }\n\n return { resolvedFrom, resolvedTo };\n}\n\nexport function getAnimatedKeys(from: any, to: any): string[] {\n const keys = new Set<string>();\n const excludeKeys = [\n \"immediateRender\",\n \"ease\",\n \"duration\",\n \"stagger\",\n \"repeat\",\n \"yoyo\",\n \"keyframes\",\n ];\n if (from) {\n for (const key of Object.keys(from)) {\n if (!excludeKeys.includes(key)) keys.add(key);\n }\n }\n if (to) {\n for (const key of Object.keys(to)) {\n if (!excludeKeys.includes(key)) keys.add(key);\n }\n if (to.keyframes) {\n if (Array.isArray(to.keyframes)) {\n for (const frame of to.keyframes) {\n for (const key of Object.keys(frame)) {\n if (!excludeKeys.includes(key)) keys.add(key);\n }\n }\n } else if (typeof to.keyframes === \"object\") {\n for (const frame of Object.values(to.keyframes)) {\n if (frame && typeof frame === \"object\") {\n for (const key of Object.keys(frame)) {\n if (!excludeKeys.includes(key)) keys.add(key);\n }\n }\n }\n }\n }\n }\n return Array.from(keys);\n}\n\nexport function getPixiProperty(t: any, key: string): number {\n if (key === \"scale\" || key === \"scaleX\") {\n return t.scale?.x ?? 1;\n }\n if (key === \"scaleY\") {\n return t.scale?.y ?? 1;\n }\n if (key === \"anchor\" || key === \"anchorX\") {\n return t.anchor?.x ?? 0;\n }\n if (key === \"anchorY\") {\n return t.anchor?.y ?? 0;\n }\n if (key === \"pivot\" || key === \"pivotX\") {\n return t.pivot?.x ?? 0;\n }\n if (key === \"pivotY\") {\n return t.pivot?.y ?? 0;\n }\n if (key === \"skew\" || key === \"skewX\") {\n return ((t.skew?.x ?? 0) * 180) / Math.PI;\n }\n if (key === \"skewY\") {\n return ((t.skew?.y ?? 0) * 180) / Math.PI;\n }\n if (key === \"rotation\") {\n return t.angle ?? 0;\n }\n\n const val = gsap.getProperty(t, key);\n if (typeof val === \"number\") {\n return val;\n }\n if (val && typeof val === \"object\") {\n if (\"x\" in val && typeof (val as any).x === \"number\") {\n return (val as any).x;\n }\n }\n const parsed = parseFloat(val as any);\n return isNaN(parsed) ? 0 : parsed;\n}\n","import gsap from \"gsap\";\nimport { PixiPlugin } from \"gsap/PixiPlugin\";\nimport * as PIXI from \"pixi.js\";\nimport { AnimationOptions, AnimationTransform, IAnimation } from \"./types\";\nimport { prepareVars, resolveVars, getAnimatedKeys, getPixiProperty } from \"./pixi-animation-utils\";\n\n// Register PixiPlugin to support skewX, skewY, and other PixiJS properties\ngsap.registerPlugin(PixiPlugin);\nPixiPlugin.registerPIXI(PIXI);\n\nexport interface GsapAnimationParams {\n /**\n * Animation presets or custom GSAP vars\n */\n type: \"character\" | \"word\" | \"line\";\n from: gsap.TweenVars;\n to: gsap.TweenVars;\n stagger?: number | gsap.StaggerVars;\n}\n\nexport class GsapAnimation implements IAnimation {\n readonly id: string;\n readonly type: string;\n readonly options: Required<AnimationOptions>;\n readonly params: GsapAnimationParams;\n\n private timeline: gsap.core.Timeline | null = null;\n private lastTarget: any = null;\n private originalProperties = new Map<any, Record<string, any>>();\n\n constructor(params: GsapAnimationParams, options: AnimationOptions, type: string = \"gsap\") {\n this.id = options.id || `gsap_${Math.random().toString(36).substr(2, 9)}`;\n this.type = type;\n this.params = params;\n this.options = {\n duration: options.duration,\n delay: options.delay ?? 0,\n easing: options.easing ?? \"none\",\n iterCount: options.iterCount ?? 1,\n id: this.id,\n disableGlobalEasing: options.disableGlobalEasing ?? false,\n };\n }\n\n getTransform(_time: number): AnimationTransform {\n // GSAP animations usually handle properties directly on children,\n // so the base transform is empty.\n return {};\n }\n\n get isOutAnimation(): boolean {\n return (\n (this.options as any).mode === \"out\" ||\n (this.params as any).metaMode === \"out\" ||\n (this.params as any).mode === \"out\" ||\n this.id.toLowerCase().includes(\"out\")\n );\n }\n\n restoreOriginals(): void {\n this.originalProperties.forEach((orig, t) => {\n if (t && !t.destroyed) {\n try {\n const pixiOrig = prepareVars(orig);\n gsap.set(t, pixiOrig);\n delete t.__ovAnchorAdjusted;\n } catch (e) {\n // ignore\n }\n }\n });\n }\n\n public getTargetCount(target: any): number {\n return this.getCurrentTargets(target).length;\n }\n\n apply(target: any, time: number): void {\n const { duration, delay } = this.options;\n const offsetTime = time - delay;\n\n // Check if we need to re-initialize the timeline\n let needsReinit =\n this.lastTarget !== target || !this.timeline || this.originalProperties.size === 0;\n\n // Get current actual targets from the container for comparison\n const currentActualTargets = this.getCurrentTargets(target);\n\n if (!needsReinit) {\n if (this.originalProperties.size !== currentActualTargets.length) {\n needsReinit = true;\n } else {\n // Check if target references have changed or any target is destroyed\n for (const t of currentActualTargets) {\n if (!this.originalProperties.has(t) || t.destroyed || !t.parent) {\n needsReinit = true;\n break;\n }\n // If a target now has a valid size but we haven't adjusted its anchor yet, we must re-initialize\n const hasAnchor = !!t.anchor;\n const hasPivot = !t.anchor && t.pivot && t.getLocalBounds;\n if (hasAnchor && !t.__ovAnchorAdjusted && t.width > 0 && t.height > 0) {\n needsReinit = true;\n break;\n }\n if (hasPivot && !t.__ovAnchorAdjusted) {\n const bounds = t.getLocalBounds();\n if (bounds.width > 0 && bounds.height > 0) {\n needsReinit = true;\n break;\n }\n }\n }\n }\n }\n\n if (needsReinit) {\n this.initTimeline(target);\n this.lastTarget = target;\n }\n\n if (!this.timeline) return;\n\n // Handle iteration and clamping\n const cycleDuration =\n this.options.iterCount === Infinity ? duration : duration / this.options.iterCount;\n\n let progress: number;\n if (this.options.iterCount !== Infinity && offsetTime >= duration) {\n progress = 1;\n } else if (offsetTime < 0) {\n if (this.isOutAnimation) {\n return; // exit animations do not apply anything before their start time\n }\n progress = 0;\n } else {\n progress = (offsetTime % cycleDuration) / cycleDuration;\n }\n\n this.timeline.progress(progress);\n\n // Apply manual boundary values for staggered elements to prevent GSAP revert issues\n const timelineTime = progress * this.timeline.duration();\n const animTargets = this.getCurrentTargets(target);\n const durationInSeconds = duration / 1e6;\n const { from, to, stagger } = this.params;\n const staggerVal = typeof stagger === \"number\" ? stagger : 0;\n\n animTargets.forEach((t, i) => {\n const tStart = i * staggerVal;\n const tEnd = tStart + durationInSeconds;\n\n const isOut = this.isOutAnimation;\n if (timelineTime < tStart) {\n // Force the starting values\n const orig = this.originalProperties.get(t) || {};\n const { resolvedFrom } = resolveVars(from, to, orig, isOut);\n const pixiFrom = prepareVars(resolvedFrom);\n gsap.set(t, pixiFrom);\n } else if (timelineTime > tEnd) {\n // Force the ending values\n const orig = this.originalProperties.get(t) || {};\n const { resolvedTo } = resolveVars(from, to, orig, isOut);\n const pixiTo = prepareVars(resolvedTo);\n gsap.set(t, pixiTo);\n }\n });\n }\n\n /**\n * Get current animation targets from the container based on animation type.\n * Used to compare against GSAP's cached targets to detect when children are recreated.\n */\n private getCurrentTargets(target: any): any[] {\n if (!target) {\n return [];\n }\n\n const { type } = this.params;\n\n // For Text and Caption clips, the words and characters live inside the TextOnlyContainer child if it exists.\n let textContainer = target;\n if (target.children) {\n const found = target.children.find((child: any) => child.label === \"TextOnlyContainer\");\n if (found) {\n textContainer = found;\n }\n }\n\n if (type === \"character\" || type === \"word\") {\n if (!textContainer || !textContainer.children || textContainer.children.length === 0) {\n return [];\n }\n if (type === \"character\") {\n // Find all characters (recursive)\n const findCharacters = (node: any, isRoot: boolean = false): any[] => {\n if (node && node.label === \"LineMask\") {\n return [];\n }\n if (!node.children || node.children.length === 0) {\n return isRoot ? [] : [node];\n }\n let results: any[] = [];\n for (const child of node.children) {\n results = results.concat(findCharacters(child));\n }\n return results;\n };\n return findCharacters(textContainer, true);\n } else {\n // type === \"word\"\n const hasLineContainers = textContainer.children.some(\n (child: any) => child && child.label === \"LineContainer\",\n );\n if (hasLineContainers) {\n const results: any[] = [];\n for (const child of textContainer.children) {\n if (child && child.label === \"LineContainer\" && child.children) {\n results.push(...child.children);\n }\n }\n return results;\n }\n return textContainer.children;\n }\n }\n\n return [target];\n }\n\n private initTimeline(target: any): void {\n const { from, to, stagger, type } = this.params;\n const durationInSeconds = this.options.duration / 1e6;\n\n // Identify animation targets based on type\n const animTargets: any[] = this.getCurrentTargets(target);\n\n // CRITICAL: Don't create the timeline if we have no targets but expected them.\n // By keeping this.timeline as null, the apply method will keep retrying every frame.\n if ((type === \"character\" || type === \"word\") && animTargets.length === 0) {\n if (this.timeline) {\n this.timeline.kill();\n this.timeline = null;\n }\n return;\n }\n\n // Re-initialize the timeline\n if (this.timeline) {\n this.timeline.kill();\n }\n // Restore original properties of old targets before clearing\n this.restoreOriginals();\n this.originalProperties.clear();\n\n this.timeline = gsap.timeline({ paused: true });\n animTargets.forEach((t) => {\n if (t.anchor) {\n if (!t.__ovAnchorAdjusted) {\n if (t.width > 0 && t.height > 0) {\n if (t.anchor.x !== 0.5 || t.anchor.y !== 0.5) {\n const oldX = t.anchor.x;\n const oldY = t.anchor.y;\n t.anchor.set(0.5, 0.5);\n const w = t.width / (t.scale?.x || 1);\n const h = t.height / (t.scale?.y || 1);\n t.x += (0.5 - oldX) * w * (t.scale?.x || 1);\n t.y += (0.5 - oldY) * h * (t.scale?.y || 1);\n }\n t.__ovAnchorAdjusted = true;\n }\n }\n } else if (t.pivot && t.getLocalBounds) {\n if (!t.__ovAnchorAdjusted) {\n const bounds = t.getLocalBounds();\n const cx = bounds.x + bounds.width / 2;\n const cy = bounds.y + bounds.height / 2;\n if (bounds.width > 0 && bounds.height > 0) {\n if (t.pivot.x !== cx || t.pivot.y !== cy) {\n const oldX = t.pivot.x;\n const oldY = t.pivot.y;\n t.pivot.set(cx, cy);\n t.x += (cx - oldX) * (t.scale?.x || 1);\n t.y += (cy - oldY) * (t.scale?.y || 1);\n }\n t.__ovAnchorAdjusted = true;\n }\n }\n }\n });\n\n // Populate original properties for new targets\n const animKeys = getAnimatedKeys(from, to);\n animTargets.forEach((t) => {\n const orig: Record<string, any> = {};\n t.__ovOriginalProperties = t.__ovOriginalProperties || {};\n animKeys.forEach((key) => {\n if (t.__ovOriginalProperties[key] === undefined) {\n t.__ovOriginalProperties[key] = getPixiProperty(t, key);\n }\n orig[key] = t.__ovOriginalProperties[key];\n });\n this.originalProperties.set(t, orig);\n });\n\n const staggerVal = typeof stagger === \"number\" ? stagger : 0;\n\n const isOut = this.isOutAnimation;\n\n // Add individual tweens to timeline\n animTargets.forEach((t, i) => {\n const orig = this.originalProperties.get(t) || {};\n const { resolvedFrom, resolvedTo } = resolveVars(from, to, orig, isOut);\n\n const finalFrom = prepareVars(resolvedFrom);\n const finalTo = prepareVars(resolvedTo);\n\n this.timeline!.add(\n gsap.fromTo(t, finalFrom, {\n duration: durationInSeconds,\n ease: this.options.easing as any,\n immediateRender: !isOut,\n ...finalTo,\n }),\n i * staggerVal,\n );\n });\n }\n\n destroy() {\n if (this.timeline) {\n this.timeline.kill();\n this.timeline = null;\n }\n // Restore original properties of targets before clearing\n this.restoreOriginals();\n this.originalProperties.clear();\n }\n}\n","import { getEasing } from \"./easings\";\nimport { AnimationOptions, AnimationTransform, IAnimation, MaskTransform } from \"./types\";\n\n/**\n * Direction the wipe edge travels FROM:\n * \"left\" → wipe sweeps left-to-right (mask grows from left)\n * \"right\" → wipe sweeps right-to-left (mask grows from right)\n * \"top\" → wipe sweeps top-to-bottom (mask grows from top)\n * \"bottom\" → wipe sweeps bottom-to-top (mask grows from bottom)\n */\nexport type WipeDirection = \"left\" | \"right\" | \"top\" | \"bottom\";\n\n/**\n * \"reveal\" = wipe IN (mask expands, more of the clip becomes visible)\n * \"conceal\"= wipe OUT (mask shrinks, clip disappears progressively)\n */\nexport type WipeMode = \"reveal\" | \"conceal\";\n\nexport interface WipeAnimationParams {\n direction: WipeDirection;\n mode: WipeMode;\n /** Optional angle offset for diagonal wipes (degrees) */\n angle?: number;\n /** Soft edge feather width in pixels. 0 = hard edge. */\n feather?: number;\n /** Starting mask size 0–1. Default: 0 (starts from nothing). */\n initialProgress?: number;\n}\n\n/**\n * WipeAnimation\n *\n * Rectangular edge-sweep mask animation. Emits a MaskTransform via\n * getTransform() so it composes cleanly with other animations.\n * The actual mask drawing is handled by PixiSpriteRenderer's unified\n * mask compositor, which reads renderTransform.mask each frame.\n *\n * Example (AI usage):\n *\n * ```ts\n * clip.addAnimation(\"wipe\", {\n * duration: 1_000_000, // 1 second in microseconds\n * easing: \"easeInOutCubic\",\n * }, {\n * direction: \"left\",\n * mode: \"reveal\",\n * feather: 0, // hard edge (default)\n * });\n * ```\n */\nexport class WipeAnimation implements IAnimation {\n readonly id: string;\n readonly type = \"wipe\";\n readonly options: Required<AnimationOptions>;\n readonly params: WipeAnimationParams;\n\n constructor(params: WipeAnimationParams, options: AnimationOptions) {\n this.id = options.id || `wipe_${Math.random().toString(36).substr(2, 9)}`;\n this.params = params;\n this.options = {\n duration: options.duration,\n delay: options.delay ?? 0,\n easing: options.easing ?? \"linear\",\n iterCount: options.iterCount ?? 1,\n id: this.id,\n disableGlobalEasing: options.disableGlobalEasing ?? false,\n };\n }\n\n getTransform(time: number): AnimationTransform {\n const { duration, delay, easing, iterCount } = this.options;\n const { direction, mode, angle, feather } = this.params;\n\n const offsetTime = time - delay;\n\n const isReveal = mode !== \"conceal\";\n const isFinished = iterCount !== Infinity && offsetTime >= duration;\n\n if (isReveal && isFinished) {\n return {};\n }\n if (!isReveal && offsetTime < 0) {\n return {};\n }\n\n let rawProgress: number;\n if (offsetTime < 0) {\n rawProgress = 0;\n } else if (iterCount !== Infinity && offsetTime >= duration) {\n rawProgress = 1;\n } else {\n const cycleDuration = iterCount === Infinity ? duration : duration / iterCount;\n rawProgress = (offsetTime % cycleDuration) / cycleDuration;\n }\n\n const easingFn = getEasing(easing);\n const progress = easingFn(rawProgress);\n\n const mask: MaskTransform = {\n shape: \"rect\",\n progress: mode === \"reveal\" ? progress : 1 - progress,\n direction,\n angle: angle ?? 0,\n feather: feather ?? 0,\n ...(this.params.initialProgress != null && { initialProgress: this.params.initialProgress }),\n };\n\n return { mask };\n }\n}\n","import { Color } from \"pixi.js\";\n\n/**\n * Convert color string or number to PixiJS color number\n */\nexport function parseColor(color: string | number | undefined): number | undefined {\n if (color === undefined || color === null) return undefined;\n if (typeof color === \"number\") return color;\n if (typeof color === \"string\") {\n if (color === \"transparent\") return undefined;\n\n // Handle hex strings like '#ff0000' or '0xff0000'\n if (color.startsWith(\"#\")) {\n const parsed = parseInt(color.slice(1), 16);\n if (!isNaN(parsed)) return parsed;\n }\n if (color.startsWith(\"0x\")) {\n const parsed = parseInt(color, 16);\n if (!isNaN(parsed)) return parsed;\n }\n // Try to parse as hex number\n const parsed = parseInt(color, 16);\n if (!isNaN(parsed)) return parsed;\n // Use PixiJS Color to parse named colors (like 'red', 'blue', etc.)\n try {\n const colorObj = new Color(color);\n return colorObj.toNumber();\n } catch (e) {\n // If color parsing fails, return undefined\n return undefined;\n }\n }\n return undefined;\n}\n\nexport const isTransparent = (color?: any) =>\n color === \"transparent\" || color === \"\" || color === undefined || color === null;\n\nexport const resolveColor = (color?: string | number | null, fallback = 0xffffff) => {\n if (isTransparent(color)) {\n return { color: fallback, alpha: 0 };\n }\n return {\n color: parseColor(color as any) ?? fallback,\n alpha: 1,\n };\n};\n\n/**\n * Convert hex color string to RGB object\n */\nexport function hexToRgb(hex: string): { r: number; g: number; b: number } | null {\n try {\n const colorObj = new Color(hex);\n const rgb = colorObj.toRgbArray(); // Pixi v8 Color returns [r, g, b] in 0-1 range\n return {\n r: Math.round(rgb[0] * 255),\n g: Math.round(rgb[1] * 255),\n b: Math.round(rgb[2] * 255),\n };\n } catch (e) {\n return null;\n }\n}\n","import { Container, Graphics, SplitBitmapText, TextStyle } from \"pixi.js\";\nimport { getEasing } from \"./easings\";\nimport { parseColor } from \"../utils/color\";\nimport type { AnimationOptions, AnimationTransform, IAnimation } from \"./types\";\n\nexport type BlockRevealDirection = \"left\" | \"right\" | \"top\" | \"bottom\";\n\n/**\n * \"reveal\": a solid block grows across the text, then retracts the other way, uncovering it.\n * Any other mode: a block of `blockSize` sweeps across the text.\n */\nexport type BlockRevealMode = \"reveal\" | \"sweep\";\n\nexport interface BlockRevealParams {\n /** Block colour (default white) */\n blockColor?: string | number;\n /** Colour of the text where the block covers it (default black) */\n textColorInside?: string | number;\n direction?: BlockRevealDirection;\n mode?: BlockRevealMode;\n /** Sweep mode: block size as a fraction of the line (default 0.3) */\n blockSize?: number;\n}\n\ninterface Rect { x: number; y: number; w: number; h: number }\n\n/** Copy of the text lines in another colour, shown only where the block covers the text (via mask) */\nfunction createInvertTextContainer(textOnlyContainer: Container, fill: number): Container {\n const container = new Container();\n container.label = \"InvertTextContainer\";\n for (const line of textOnlyContainer.children) {\n if (!(line instanceof Container) || line.label !== \"LineContainer\") continue;\n const lineCopy = new Container();\n lineCopy.label = \"LineContainer\";\n for (const word of line.children) {\n if (!(word instanceof SplitBitmapText)) continue;\n const s = word.style;\n const style = new TextStyle({\n fontFamily: s.fontFamily,\n fontSize: s.fontSize,\n fontWeight: s.fontWeight,\n fontStyle: s.fontStyle,\n align: s.align,\n wordWrap: s.wordWrap,\n wordWrapWidth: s.wordWrapWidth,\n lineHeight: s.lineHeight,\n letterSpacing: s.letterSpacing,\n fill,\n });\n const copy = new SplitBitmapText({ text: word.text, style });\n copy.x = word.x;\n copy.y = word.y;\n if (word.filters) copy.filters = [...(word.filters as any[])];\n lineCopy.addChild(copy);\n }\n container.addChild(lineCopy);\n }\n return container;\n}\n\n/** Block rectangle for one line box at eased progress `p` (0..1) */\nfunction blockRect(box: Rect, p: number, direction: BlockRevealDirection, mode: string, blockSize: number): Rect {\n const { x, y, w, h } = box;\n let rx = x, ry = y, rw = 0, rh = h;\n if (mode === \"reveal\") {\n const grow = p <= 0.5;\n const k = grow ? p * 2 : (p - 0.5) * 2;\n if (direction === \"left\") {\n rx = grow ? x : x + k * w;\n rw = grow ? k * w : w - k * w;\n ry = y; rh = h;\n } else if (direction === \"right\") {\n rx = grow ? x + w - k * w : x;\n rw = grow ? k * w : w - k * w;\n ry = y; rh = h;\n } else if (direction === \"top\") {\n ry = grow ? y : y + k * h;\n rh = grow ? k * h : h - k * h;\n rx = x; rw = w;\n } else {\n ry = grow ? y + h - k * h : y;\n rh = grow ? k * h : h - k * h;\n rx = x; rw = w;\n }\n } else if (direction === \"left\") {\n const size = blockSize * w, pos = x - size + p * (w + size);\n rx = Math.max(x, pos); rw = Math.min(x + w, pos + size) - rx; ry = y; rh = h;\n } else if (direction === \"right\") {\n const size = blockSize * w, pos = x + w - p * (w + size);\n rx = Math.max(x, pos); rw = Math.min(x + w, pos + size) - rx; ry = y; rh = h;\n } else if (direction === \"top\") {\n const size = blockSize * h, pos = y - size + p * (h + size);\n ry = Math.max(y, pos); rh = Math.min(y + h, pos + size) - ry; rx = x; rw = w;\n } else {\n const size = blockSize * h, pos = y + h - p * (h + size);\n ry = Math.max(y, pos); rh = Math.min(y + h, pos + size) - ry; rx = x; rw = w;\n }\n return { x: rx, y: ry, w: rw, h: rh };\n}\n\n/**\n * BlockRevealAnimation (text/caption clips)\n *\n * A coloured block wipes across each text line; where it covers the text, the text is drawn in\n * `textColorInside`. Draws directly on the clip's text container in apply().\n */\nexport class BlockRevealAnimation implements IAnimation {\n readonly id: string;\n readonly type = \"blockReveal\";\n readonly options: Required<AnimationOptions>;\n readonly params: BlockRevealParams;\n\n constructor(params: BlockRevealParams, options: AnimationOptions) {\n this.id = options.id || `block_reveal_${Math.random().toString(36).substring(2, 9)}`;\n this.params = params;\n this.options = {\n duration: options.duration,\n delay: options.delay ?? 0,\n easing: options.easing ?? \"easeInOutCubic\",\n iterCount: options.iterCount ?? 1,\n id: this.id,\n disableGlobalEasing: options.disableGlobalEasing ?? false,\n } as Required<AnimationOptions>;\n }\n\n getTransform(_time: number): AnimationTransform {\n return {};\n }\n\n apply(target: any, time: number): void {\n if (!(target instanceof Container) || target.destroyed) return;\n const t = target as any;\n const { duration, delay, easing } = this.options;\n const elapsed = time - delay;\n if (elapsed < 0) {\n this.cleanup(t);\n return;\n }\n const progress = getEasing(easing as any)(Math.min(elapsed / duration, 1));\n if (progress >= 1) {\n this.cleanup(t);\n return;\n }\n\n const textOnly = target.children.find((c) => c.label === \"TextOnlyContainer\") as Container | undefined;\n if (!textOnly || textOnly.destroyed) return;\n\n const blockColor = parseColor(this.params.blockColor as any) ?? 0xffffff;\n const insideColor = parseColor(this.params.textColorInside as any) ?? 0x000000;\n const direction = this.params.direction ?? \"right\";\n const mode = this.params.mode ?? \"reveal\";\n const blockSize = this.params.blockSize ?? 0.3;\n\n let block: Graphics = t.__blockGraphics;\n let invert: Container = t.__invertTextContainer;\n let mask: Graphics = t.__maskGraphics;\n if (!block || block.destroyed) {\n block = new Graphics();\n block.label = \"BlockReveal_Block\";\n target.addChild(block);\n t.__blockGraphics = block;\n } else if (target.children.indexOf(block) === -1) target.addChild(block);\n if (!invert || invert.destroyed) {\n invert = createInvertTextContainer(textOnly, insideColor);\n target.addChild(invert);\n t.__invertTextContainer = invert;\n } else if (target.children.indexOf(invert) === -1) target.addChild(invert);\n if (!mask || mask.destroyed) {\n mask = new Graphics();\n mask.label = \"BlockReveal_Mask\";\n target.addChild(mask);\n t.__maskGraphics = mask;\n invert.mask = mask;\n } else if (target.children.indexOf(mask) === -1) target.addChild(mask);\n\n // z-order: text < block < inverted text\n const textIdx = target.children.indexOf(textOnly);\n const blockIdx = target.children.indexOf(block);\n const invertIdx = target.children.indexOf(invert);\n if (textIdx !== -1 && blockIdx !== -1 && invertIdx !== -1) {\n if (blockIdx < textIdx) target.setChildIndex(block, textIdx + 1);\n const newBlockIdx = target.children.indexOf(block);\n if (invertIdx < newBlockIdx) target.setChildIndex(invert, newBlockIdx + 1);\n }\n\n const clip = t.__clip;\n const bounds = target.getLocalBounds();\n const lineRects: Rect[] | undefined = clip?._lineRects;\n block.clear();\n mask.clear();\n let drew = false;\n const draw = (r: Rect) => {\n if (r.w > 0 && r.h > 0) {\n block.rect(r.x, r.y, r.w, r.h).fill({ color: blockColor });\n mask.rect(r.x, r.y, r.w, r.h).fill({ color: 0xffffff });\n drew = true;\n }\n };\n if (lineRects && lineRects.length > 0) {\n const width = clip ? clip.width : bounds.width;\n const left = clip ? 0 : bounds.x;\n for (const line of lineRects) draw(blockRect({ x: left, y: line.y, w: width, h: line.h }, progress, direction, mode, blockSize));\n } else {\n draw(blockRect({ x: bounds.x, y: bounds.y, w: bounds.width, h: bounds.height }, progress, direction, mode, blockSize));\n }\n block.visible = drew;\n invert.visible = drew;\n }\n\n cleanup(target: any): void {\n if (target.__blockGraphics) {\n if (!target.__blockGraphics.destroyed) target.__blockGraphics.destroy();\n target.__blockGraphics = null;\n }\n if (target.__invertTextContainer) {\n if (!target.__invertTextContainer.destroyed) target.__invertTextContainer.destroy({ children: true });\n target.__invertTextContainer = null;\n }\n if (target.__maskGraphics) {\n if (!target.__maskGraphics.destroyed) target.__maskGraphics.destroy();\n target.__maskGraphics = null;\n }\n }\n}\n","import { getEasing } from \"./easings\";\nimport {\n AnimationOptions,\n AnimationTransform,\n IAnimation,\n MaskPainter,\n MaskTransform,\n} from \"./types\";\n\n/**\n * Base class for all mask animations.\n * Subclasses override `buildMask(progress)` to define the mask shape.\n */\nabstract class BaseMaskAnimation implements IAnimation {\n readonly id: string;\n abstract readonly type: string;\n readonly options: Required<AnimationOptions>;\n readonly params: any;\n\n constructor(params: any, options: AnimationOptions) {\n this.id = options.id || `mask_${Math.random().toString(36).substr(2, 9)}`;\n this.params = params;\n this.options = {\n duration: options.duration,\n delay: options.delay ?? 0,\n easing: options.easing ?? \"linear\",\n iterCount: options.iterCount ?? 1,\n id: this.id,\n disableGlobalEasing: options.disableGlobalEasing ?? false,\n };\n }\n\n getTransform(time: number): AnimationTransform {\n const { duration, delay, easing, iterCount } = this.options;\n const offsetTime = time - delay;\n\n const isReveal = this.params.mode !== \"conceal\";\n const isFinished = iterCount !== Infinity && offsetTime >= duration;\n\n if (isReveal && isFinished) {\n return {};\n }\n if (!isReveal && offsetTime < 0) {\n return {};\n }\n\n let rawProgress: number;\n if (offsetTime < 0) {\n rawProgress = 0;\n } else if (iterCount !== Infinity && offsetTime >= duration) {\n rawProgress = 1;\n } else {\n const cycleDuration = iterCount === Infinity ? duration : duration / iterCount;\n rawProgress = (offsetTime % cycleDuration) / cycleDuration;\n }\n\n const easingFn = getEasing(easing);\n const progress = easingFn(rawProgress);\n const finalProgress = this.params.mode === \"conceal\" ? 1 - progress : progress;\n\n const mask = this.buildMask(finalProgress);\n // Propagate initialProgress from params so the renderer can remap\n if (this.params.initialProgress != null) {\n mask.initialProgress = this.params.initialProgress as number;\n }\n return { mask };\n }\n\n protected abstract buildMask(progress: number): MaskTransform;\n}\n\n// ─── CircleReveal ────────────────────────────────────────────────────────────\n\nexport interface CircleRevealParams {\n mode?: \"reveal\" | \"conceal\";\n /** Origin of expansion. Default: \"center\" */\n origin?: MaskTransform[\"origin\"];\n /** Feather (soft edge) in pixels */\n feather?: number;\n}\n\n/**\n * CircleReveal / CircleConceal\n *\n * An ellipse mask that expands from an origin point outward (or contracts inward).\n * Works on any clip type.\n *\n * ```ts\n * clip.addAnimation(\"circleReveal\", { duration: 1_000_000, easing: \"easeOutCubic\" }, {\n * mode: \"reveal\",\n * origin: \"center\",\n * feather: 10,\n * });\n * ```\n */\nexport class CircleRevealAnimation extends BaseMaskAnimation {\n readonly type = \"circleReveal\";\n\n constructor(params: CircleRevealParams, options: AnimationOptions) {\n super(params, options);\n }\n\n protected buildMask(progress: number): MaskTransform {\n return {\n shape: \"circle\",\n progress,\n origin: this.params.origin ?? \"center\",\n feather: this.params.feather ?? 0,\n };\n }\n}\n\n// ─── RectExpand ──────────────────────────────────────────────────────────────\n\nexport interface RectExpandParams {\n mode?: \"reveal\" | \"conceal\";\n /** Origin of expansion. Default: \"center\" */\n origin?: MaskTransform[\"origin\"];\n /** Feather in pixels */\n feather?: number;\n}\n\n/**\n * RectExpand / RectShrink\n *\n * A rectangle mask that grows outward from an origin (or shrinks inward).\n * Useful for \"iris box\" style reveals.\n *\n * ```ts\n * clip.addAnimation(\"rectExpand\", { duration: 1_000_000, easing: \"easeInOutQuad\" }, {\n * mode: \"reveal\",\n * origin: \"center\",\n * });\n * ```\n */\nexport class RectExpandAnimation extends BaseMaskAnimation {\n readonly type = \"rectExpand\";\n\n constructor(params: RectExpandParams, options: AnimationOptions) {\n super(params, options);\n }\n\n protected buildMask(progress: number): MaskTransform {\n const origin = this.params.origin ?? \"center\";\n\n const painter: MaskPainter = (g, width, height, p) => {\n // Determine origin point in local space (centered at 0,0)\n let ox = 0;\n let oy = 0;\n switch (origin) {\n case \"topLeft\":\n ox = -width / 2;\n oy = -height / 2;\n break;\n case \"topRight\":\n ox = width / 2;\n oy = -height / 2;\n break;\n case \"bottomLeft\":\n ox = -width / 2;\n oy = height / 2;\n break;\n case \"bottomRight\":\n ox = width / 2;\n oy = height / 2;\n break;\n default:\n ox = 0;\n oy = 0; // center\n }\n\n // Expand rect symmetrically from origin, clamped to clip bounds\n const halfW = (width / 2) * p;\n const halfH = (height / 2) * p;\n const rx = Math.max(-width / 2, ox - halfW);\n const ry = Math.max(-height / 2, oy - halfH);\n const rw = Math.min(width, halfW * 2);\n const rh = Math.min(height, halfH * 2);\n\n if (rw > 0 && rh > 0) {\n g.rect(rx, ry, rw, rh).fill({ color: 0xffffff });\n }\n };\n\n return { shape: \"custom\", progress, painter };\n }\n}\n\n// ─── CenterExpand ────────────────────────────────────────────────────────────\n\nexport interface CenterExpandParams {\n mode?: \"reveal\" | \"conceal\";\n /**\n * Axis of expansion:\n * \"vertical\" → starts full-width, expands top + bottom (default)\n * \"horizontal\" → starts full-height, expands left + right\n * \"both\" → expands in all directions simultaneously (true center iris)\n */\n axis?: \"vertical\" | \"horizontal\" | \"both\";\n}\n\n/**\n * CenterExpand\n *\n * Reveals the clip from the center outward.\n * Default: starts as a full-width zero-height bar, expands up and down.\n *\n * ```ts\n * clip.addAnimation(\"centerExpand\", { duration: 1_000_000, easing: \"easeOutCubic\" }, {\n * mode: \"reveal\",\n * axis: \"vertical\",\n * });\n * ```\n */\nexport class CenterExpandAnimation extends BaseMaskAnimation {\n readonly type = \"centerExpand\";\n\n constructor(params: CenterExpandParams, options: AnimationOptions) {\n super(params, options);\n }\n\n protected buildMask(progress: number): MaskTransform {\n const axis = this.params.axis ?? \"vertical\";\n\n const painter: MaskPainter = (g, width, height, p) => {\n let rw: number;\n let rh: number;\n\n switch (axis) {\n case \"horizontal\":\n rw = width * p;\n rh = height;\n break;\n case \"both\":\n rw = width * p;\n rh = height * p;\n break;\n default: // \"vertical\"\n rw = width;\n rh = height * p;\n break;\n }\n\n g.rect(-rw / 2, -rh / 2, rw, rh).fill({ color: 0xffffff });\n };\n\n return { shape: \"custom\", progress, painter };\n }\n}\n\n// ─── AngleWipe ───────────────────────────────────────────────────────────────\n\nexport interface AngleWipeParams {\n mode?: \"reveal\" | \"conceal\";\n /** Wipe angle in degrees. 0 = left→right, 90 = top→bottom, 45 = diagonal */\n angle?: number;\n /** Feather in pixels */\n feather?: number;\n}\n\n/**\n * AngleWipe\n *\n * A wipe that sweeps at an arbitrary angle (diagonal, rotated, etc.).\n * The `angle` param rotates the sweep direction from the default left→right.\n *\n * ```ts\n * clip.addAnimation(\"angleWipe\", { duration: 1_000_000, easing: \"linear\" }, {\n * mode: \"reveal\",\n * angle: 45, // diagonal\n * });\n * ```\n */\nexport class AngleWipeAnimation extends BaseMaskAnimation {\n readonly type = \"angleWipe\";\n\n constructor(params: AngleWipeParams, options: AnimationOptions) {\n super(params, options);\n }\n\n protected buildMask(progress: number): MaskTransform {\n return {\n shape: \"rect\",\n progress,\n direction: \"left\",\n angle: this.params.angle ?? 0,\n feather: this.params.feather ?? 0,\n };\n }\n}\n\n// ─── StarReveal ──────────────────────────────────────────────────────────────\n\nexport interface StarRevealParams {\n mode?: \"reveal\" | \"conceal\";\n /** Number of star points. Default: 5 */\n points?: number;\n /** Inner radius ratio relative to outer (0–1). Default: 0.4 */\n innerRatio?: number;\n}\n\n/**\n * StarReveal\n *\n * Reveals the clip through a star-shaped mask that grows from the center.\n * Demonstrates the custom `painter` pattern — no renderer changes needed.\n *\n * ```ts\n * clip.addAnimation(\"starReveal\", { duration: 1_000_000, easing: \"easeOutBack\" }, {\n * mode: \"reveal\",\n * points: 5,\n * innerRatio: 0.4,\n * });\n * ```\n */\nexport class StarRevealAnimation extends BaseMaskAnimation {\n readonly type = \"starReveal\";\n\n constructor(params: StarRevealParams, options: AnimationOptions) {\n super(params, options);\n }\n\n protected buildMask(progress: number): MaskTransform {\n const { points = 5, innerRatio = 0.4 } = this.params as StarRevealParams;\n\n const painter: MaskPainter = (g, width, height, p) => {\n const maxR = Math.hypot(width, height) / 2;\n const outerR = maxR * p;\n const innerR = outerR * innerRatio;\n const cx = 0;\n const cy = 0;\n const totalPoints = points * 2;\n const coords: number[] = [];\n\n for (let i = 0; i < totalPoints; i++) {\n const angle = (Math.PI / points) * i - Math.PI / 2;\n const r = i % 2 === 0 ? outerR : innerR;\n coords.push(cx + Math.cos(angle) * r, cy + Math.sin(angle) * r);\n }\n\n g.poly(coords, true).fill({ color: 0xffffff });\n };\n\n return { shape: \"custom\", progress, painter };\n }\n}\n\n// ─── EdgeCrop ────────────────────────────────────────────────────────────────\n\nexport interface EdgeCropParams {\n mode?: \"reveal\" | \"conceal\";\n /** Edge(s) the crop is anchored to. \"center\" crops all four edges. Default: \"center\" */\n origin?: \"center\" | \"topLeft\" | \"topRight\" | \"bottomLeft\" | \"bottomRight\";\n /** Horizontal crop in canvas pixels at the start of the reveal. Default: 100 */\n xDistance?: number;\n /** Vertical crop in canvas pixels at the start of the reveal. Default: 100 */\n yDistance?: number;\n /** Corner radius of the visible area. Default: 0 */\n maskBorderRadius?: number;\n feather?: number;\n}\n\n/**\n * EdgeCrop (ported from @openvideo/engine-pixi 1.4.0)\n *\n * Crops the clip's edges by a fixed pixel distance and animates the crop away.\n * Unlike the other masks the clip is never fully hidden: at progress 0 only the\n * cropped band is removed. The distances stay in canvas pixels even while the\n * clip itself is scaled by other animations.\n */\nexport class EdgeCropAnimation extends BaseMaskAnimation {\n readonly type = \"edgeCrop\";\n\n constructor(params: EdgeCropParams, options: AnimationOptions) {\n super(params, options);\n }\n\n protected buildMask(progress: number): MaskTransform {\n const p = this.params as EdgeCropParams;\n return {\n shape: \"edgeCrop\",\n progress,\n origin: p.origin ?? \"center\",\n xDistance: p.xDistance ?? 100,\n yDistance: p.yDistance ?? 100,\n maskBorderRadius: p.maskBorderRadius ?? 0,\n feather: p.feather ?? 0,\n };\n }\n}\n","import { KeyframeAnimation } from \"./keyframe-animation\";\nimport { GsapAnimation } from \"./gsap-animation\";\nimport { WipeAnimation } from \"./wipe-animation\";\nimport { BlockRevealAnimation } from \"./block-reveal-animation\";\nimport {\n CircleRevealAnimation,\n RectExpandAnimation,\n AngleWipeAnimation,\n StarRevealAnimation,\n EdgeCropAnimation,\n CenterExpandAnimation,\n} from \"./mask-animation\";\nimport { AnimationOptions, IAnimation, KeyframeData } from \"./types\";\n\nexport type AnimationFactory = (options: AnimationOptions, params?: any) => IAnimation;\n\nclass AnimationRegistry {\n private factories = new Map<string, AnimationFactory>();\n\n constructor() {\n this.register(\n \"keyframes\",\n (options, params: KeyframeData) => new KeyframeAnimation(params, options),\n );\n const staggerFactory: AnimationFactory = (options, params) =>\n new GsapAnimation(params, options, \"stagger\");\n this.register(\"stagger\", staggerFactory);\n this.register(\"wipe\", (options, params) => new WipeAnimation(params, options));\n this.register(\"circleReveal\", (options, params) => new CircleRevealAnimation(params, options));\n this.register(\"rectExpand\", (options, params) => new RectExpandAnimation(params, options));\n this.register(\"angleWipe\", (options, params) => new AngleWipeAnimation(params, options));\n this.register(\"starReveal\", (options, params) => new StarRevealAnimation(params, options));\n this.register(\"centerExpand\", (options, params) => new CenterExpandAnimation(params, options));\n this.register(\"edgeCrop\", (options, params) => new EdgeCropAnimation(params, options));\n this.register(\"blockReveal\", (options, params) => new BlockRevealAnimation(params, options));\n }\n\n register(name: string, factory: AnimationFactory) {\n this.factories.set(name, factory);\n }\n\n create(name: string, options: AnimationOptions, params?: any): IAnimation {\n const factory = this.factories.get(name);\n if (!factory) {\n throw new Error(`Animation \"${name}\" not found in registry`);\n }\n return factory(options, params);\n }\n\n has(name: string): boolean {\n return this.factories.has(name);\n }\n}\n\nexport const animationRegistry = new AnimationRegistry();\n","import EventEmitter from \"../event-emitter\";\nimport { IAnimation, AnimationTransform, animationRegistry } from \"../animation\";\nimport { IChromaKeyOpts } from \"../clips/iclip\";\nimport { ColorAdjustment } from \"../utils/color-adjustment\";\nimport { IClipTiming } from \"@agrhub/core\";\ntype IRectBaseProps = any;\ninterface IAnimationOptions {\n duration: number;\n delay?: number;\n iterCount?: number;\n}\n\ntype TAnimateProps = IRectBaseProps & { opacity: number };\n\nexport type TAnimationKeyFrame = Array<[number, Partial<TAnimateProps>]>;\n\ntype TKeyFrameOptions = Partial<Record<`${number}%` | \"from\" | \"to\", Partial<TAnimateProps>>>;\n\nexport interface BaseSpriteEvents {\n propsChange: Partial<{\n left: number;\n top: number;\n width: number;\n height: number;\n angle: number;\n zIndex: number;\n opacity: number;\n volume: number;\n animations: IAnimation[];\n locked: boolean;\n muted: boolean;\n }>;\n [key: string]: any;\n [key: symbol]: any;\n}\n\n/**\n * Sprite base class\n *\n * @see {@link OffscreenSprite}\n */\nexport abstract class BaseSprite<\n T extends BaseSpriteEvents = BaseSpriteEvents,\n> extends EventEmitter<T> {\n /**\n * Unique identifier for the sprite/clip\n */\n id = \"\";\n /**\n * Name of the sprite/clip\n */\n name = \"\";\n\n /**\n * Nested timing property group (Phase 1 Refactoring)\n */\n public timing: IClipTiming = {\n display: { from: 0, to: 0 },\n trim: { from: 0, to: 0 },\n duration: 0,\n playbackRate: 1,\n };\n\n /**\n * Control display time range of clips, commonly used in editing scenario timeline (track) module\n * from: start time offset in microseconds\n * to: end time (from + duration) in microseconds\n */\n get display(): { from: number; to: number } {\n return this.timing.display;\n }\n set display(v: { from: number; to: number }) {\n this.timing.display = v;\n }\n\n /**\n * Duration of the clip in microseconds\n * Cannot exceed the duration of the referenced {@link IClip}\n */\n get duration(): number {\n return this.timing.duration;\n }\n set duration(v: number) {\n this.timing.duration = v;\n }\n\n /**\n * Playback rate of current clip, 1 means normal playback\n * **Note**\n * 1. When setting playbackRate, duration must be actively corrected\n * 2. Audio uses the simplest interpolation algorithm to change rate, so changing rate will cause pitch variation, for custom algorithm please use {@link Video.tickInterceptor} to implement\n */\n get playbackRate(): number {\n return this.timing.playbackRate;\n }\n set playbackRate(v: number) {\n this.timing.playbackRate = v;\n }\n\n /**\n * Trim range of the source media in microseconds\n * from: start time in microseconds\n * to: end time in microseconds\n */\n get trim(): { from: number; to: number } {\n return this.timing.trim;\n }\n set trim(v: { from: number; to: number }) {\n this.timing.trim = v;\n }\n\n constructor() {\n super();\n }\n\n // Spatial properties\n protected _left = 0;\n /**\n * Left position (x coordinate)\n */\n get left(): number {\n return this._left;\n }\n set left(v: number) {\n const changed = this._left !== v;\n this._left = v;\n if (changed) this.emit(\"propsChange\", { left: v });\n }\n\n protected _top = 0;\n /**\n * Top position (y coordinate)\n */\n get top(): number {\n return this._top;\n }\n set top(v: number) {\n const changed = this._top !== v;\n this._top = v;\n if (changed) this.emit(\"propsChange\", { top: v });\n }\n\n protected _width = 0;\n /**\n * Width\n */\n get width(): number {\n return this._width;\n }\n set width(v: number) {\n const changed = this._width !== v;\n this._width = v;\n if (changed) this.emit(\"propsChange\", { width: v });\n }\n\n protected _height = 0;\n /**\n * Height\n */\n get height(): number {\n return this._height;\n }\n set height(v: number) {\n const changed = this._height !== v;\n this._height = v;\n if (changed) this.emit(\"propsChange\", { height: v });\n }\n\n private _angle = 0;\n /**\n * Rotation angle in degrees\n */\n get angle(): number {\n return this._angle;\n }\n set angle(v: number) {\n const changed = this._angle !== v;\n this._angle = v;\n if (changed) this.emit(\"propsChange\", { angle: v });\n }\n\n /**\n * Center point calculated from position and dimensions\n */\n get center(): { x: number; y: number } {\n return {\n x: this.left + this.width / 2,\n y: this.top + this.height / 2,\n };\n }\n\n private _zIndex = 0;\n get zIndex(): number {\n return this._zIndex;\n }\n\n /**\n * Control layering relationship between clips, clips with smaller zIndex will be occluded\n */\n set zIndex(v: number) {\n const changed = this._zIndex !== v;\n this._zIndex = v;\n if (changed) this.emit(\"propsChange\", { zIndex: v });\n }\n\n private _opacity = 1;\n /**\n * Opacity (0.0 to 1.0)\n */\n get opacity(): number {\n return this._opacity;\n }\n set opacity(v: number) {\n const changed = this._opacity !== v;\n this._opacity = v;\n if (changed) this.emit(\"propsChange\", { opacity: v } as any);\n }\n\n private _volume = 1;\n /**\n * Audio volume level (0.0 to 1.0)\n */\n get volume(): number {\n return this._volume;\n }\n set volume(v: number) {\n const changed = this._volume !== v;\n this._volume = v;\n if (changed) this.emit(\"propsChange\", { volume: v } as any);\n }\n\n private _locked = false;\n /**\n * Whether the sprite is locked (preventing interactions)\n */\n get locked(): boolean {\n return this._locked;\n }\n set locked(v: boolean) {\n const changed = this._locked !== v;\n this._locked = v;\n if (changed) this.emit(\"propsChange\", { locked: v } as any);\n }\n\n private _muted = false;\n /**\n * Whether the clip's audio is muted (volume is kept, so unmuting restores it)\n */\n get muted(): boolean {\n return this._muted;\n }\n set muted(v: boolean) {\n const changed = this._muted !== v;\n this._muted = v;\n if (changed) this.emit(\"propsChange\", { muted: v } as any);\n }\n\n private _trackMuted = false;\n /**\n * Set by Studio/Compositor when the clip's track is muted. Not serialized and does not emit\n * propsChange, so it can be refreshed every frame.\n */\n get trackMuted(): boolean {\n return this._trackMuted;\n }\n set trackMuted(v: boolean) {\n if (this._trackMuted === v) return;\n this._trackMuted = v;\n this.onEffectiveVolumeChange();\n }\n\n /** Called when the track-level mute flips (clip-level changes arrive via propsChange). */\n protected onEffectiveVolumeChange(): void {}\n\n /** Volume actually applied to audio output: 0 when the clip or its track is muted. */\n get effectiveVolume(): number {\n return this._muted || this.trackMuted ? 0 : this.volume;\n }\n\n /**\n * Flip clip horizontally or vertically\n */\n flip: { x: boolean; y: boolean } | null = null;\n\n effects: Array<{\n id: string;\n key: string;\n startTime: number;\n duration: number;\n targets?: number[];\n }> = [];\n\n /**\n * Chroma key settings (green screen removal)\n */\n chromaKey?: IChromaKeyOpts;\n\n colorAdjustment?: ColorAdjustment;\n\n /**\n * Styling properties (e.g., stroke, dropShadow, borderRadius)\n * This is a generic object to hold visual styles across different clip types\n */\n protected _style: any = {};\n\n get style(): any {\n return this._style;\n }\n\n set style(v: any) {\n this._style = v;\n }\n\n private animatKeyFrame: TAnimationKeyFrame | null = null;\n\n private animatOptions: Required<IAnimationOptions> | null = null;\n\n private _animations: IAnimation[] = [];\n\n /**\n * List of active animations.\n * When setting this property, raw objects are automatically converted to IAnimation instances.\n */\n public get animations(): IAnimation[] {\n return this._animations;\n }\n\n public set animations(v: IAnimation[]) {\n if (!Array.isArray(v)) {\n this._animations.forEach((a) => {\n if (a && typeof (a as any).destroy === \"function\") {\n (a as any).destroy();\n }\n });\n this._animations = [];\n return;\n }\n\n // Identify and destroy old animations that are being removed or replaced by new configs\n this._animations.forEach((oldAnim) => {\n if (oldAnim && oldAnim.id) {\n const matchingNew = v.find((anim: any) => anim && anim.id === oldAnim.id);\n const isReplaced = matchingNew && typeof (matchingNew as any).getTransform !== \"function\";\n const isRemoved = !matchingNew;\n if ((isRemoved || isReplaced) && typeof (oldAnim as any).destroy === \"function\") {\n (oldAnim as any).destroy();\n }\n }\n });\n\n this._animations = v.map((anim: any) => {\n // If it's already an instantiated animation, return it\n if (anim && typeof anim.getTransform === \"function\") {\n return anim;\n }\n // If it's a raw object from JSON/Core, instantiate it\n if (anim && anim.type && anim.options) {\n try {\n return animationRegistry.create(anim.type, anim.options, anim.params);\n } catch (err) {\n console.error(`[BaseSprite] Failed to instantiate animation: ${anim.type}`, err);\n return anim;\n }\n }\n return anim;\n });\n }\n\n /**\n * Current transform offsets/multipliers from animations\n * Resets every frame in animate()\n */\n public renderTransform: AnimationTransform = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n scale: 1,\n scaleX: 1,\n scaleY: 1,\n opacity: 1,\n angle: 0,\n blur: 0,\n brightness: 1,\n mirror: 0,\n motionBlur: 0,\n };\n\n /**\n * @see {@link IClip.ready}\n * For clips, this should be Promise<IClipMeta>, but for BaseSprite it's just Promise<void>\n */\n protected _render(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D): void {\n const { center } = this;\n ctx.setTransform(\n // Horizontal scale, skew\n this.flip?.x ? -1 : 1,\n 0,\n // Vertical skew, scale\n 0,\n this.flip?.y ? -1 : 1,\n // Coordinate origin offset x y\n center.x,\n center.y,\n );\n\n ctx.globalAlpha =\n this.opacity * (this.renderTransform.opacity ?? 1) * (this.renderTransform.brightness ?? 1);\n\n const x = this.renderTransform.x ?? 0;\n const y = this.renderTransform.y ?? 0;\n const angleOffset = this.renderTransform.angle ?? 0;\n const scale = this.renderTransform.scale ?? 1;\n const scaleX = this.renderTransform.scaleX ?? 1;\n const scaleY = this.renderTransform.scaleY ?? 1;\n\n ctx.translate(x, y);\n ctx.scale(scale * scaleX, scale * scaleY);\n ctx.rotate(((this.flip == null ? 1 : -1) * (angleOffset * Math.PI)) / 180);\n }\n\n /**\n * Add animation to clip, usage reference CSS animation\n *\n * @example\n * sprite.setAnimation(\n * {\n * '0%': { x: 0, y: 0 },\n * '25%': { x: 1200, y: 680 },\n * '50%': { x: 1200, y: 0 },\n * '75%': { x: 0, y: 680 },\n * '100%': { x: 0, y: 0 },\n * },\n * { duration: 4e6, iterCount: 1 },\n * );\n *\n */\n setAnimation(keyFrame: TKeyFrameOptions, options: IAnimationOptions): void {\n this.animatKeyFrame = Object.entries(keyFrame).map(([k, val]) => {\n const numK = { from: 0, to: 100 }[k] ?? Number(k.slice(0, -1));\n if (isNaN(numK) || numK > 100 || numK < 0) {\n throw Error(\"keyFrame must between 0~100\");\n }\n return [numK / 100, val];\n }) as TAnimationKeyFrame;\n this.animatOptions = Object.assign({}, this.animatOptions, {\n duration: options.duration,\n delay: options.delay ?? 0,\n iterCount: options.iterCount ?? Infinity,\n });\n this.emit(\"propsChange\", { animations: this.animations } as any);\n }\n\n /**\n * If current sprite has animation set, set sprite's animation properties to state at specified time\n */\n animate(time: number, target?: any): void {\n // Reset render transforms\n this.renderTransform = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n scale: 1,\n scaleX: 1,\n scaleY: 1,\n opacity: 1,\n angle: 0,\n blur: 0,\n brightness: 1,\n mirror: 0,\n motionBlur: 0,\n __lastSpriteTime: time,\n } as any;\n\n // Sort animations chronologically by delay to ensure correct application order (e.g. entrance before exit)\n const sortedAnims = [...this.animations].sort(\n (a, b) => (a.options?.delay ?? 0) - (b.options?.delay ?? 0),\n );\n\n // Pre-restore target elements to their original properties to ensure clean state transitions\n if (target) {\n for (const anim of sortedAnims) {\n if (anim.type === \"stagger\" && (anim as any).restoreOriginals) {\n (anim as any).restoreOriginals(target);\n }\n }\n }\n\n // 1. Process new modular animations\n for (const anim of sortedAnims) {\n const transform = anim.getTransform(time);\n if (transform.x !== undefined) this.renderTransform.x! += transform.x;\n if (transform.y !== undefined) this.renderTransform.y! += transform.y;\n if (transform.width !== undefined) this.renderTransform.width! += transform.width;\n if (transform.height !== undefined) this.renderTransform.height! += transform.height;\n if (transform.angle !== undefined) this.renderTransform.angle! += transform.angle;\n if (transform.blur !== undefined) this.renderTransform.blur! += transform.blur;\n if (transform.motionBlur !== undefined)\n this.renderTransform.motionBlur! += transform.motionBlur;\n if (transform.scale !== undefined) this.renderTransform.scale! *= transform.scale;\n if (transform.scaleX !== undefined) this.renderTransform.scaleX! *= transform.scaleX;\n if (transform.scaleY !== undefined) this.renderTransform.scaleY! *= transform.scaleY;\n if (transform.opacity !== undefined) this.renderTransform.opacity! *= transform.opacity;\n if (transform.brightness !== undefined)\n this.renderTransform.brightness! *= transform.brightness;\n if (transform.mirror !== undefined)\n this.renderTransform.mirror = Math.max(this.renderTransform.mirror || 0, transform.mirror);\n\n // Mask: last animation with a mask wins (overwrite, not accumulate)\n if (transform.mask !== undefined) this.renderTransform.mask = transform.mask;\n\n if (target && anim.apply) {\n anim.apply(target, time);\n }\n }\n\n // 2. Process legacy keyframe animation (for backward compatibility)\n if (\n this.animatKeyFrame == null ||\n this.animatOptions == null ||\n time < this.animatOptions.delay\n )\n return;\n\n const updateProps = linearTimeFn(time, this.animatKeyFrame, this.animatOptions);\n // Only update properties that are actually in the animation keyframes\n // This ensures manual property settings (like opacity) are preserved if not animated\n for (const k in updateProps) {\n switch (k) {\n case \"opacity\":\n this.opacity = updateProps[k] as number;\n break;\n case \"x\":\n this.left = updateProps[k] as number;\n break;\n case \"y\":\n this.top = updateProps[k] as number;\n break;\n case \"w\":\n this.width = updateProps[k] as number;\n break;\n case \"h\":\n this.height = updateProps[k] as number;\n break;\n case \"angle\":\n this.angle = updateProps[k] as number;\n break;\n }\n }\n }\n\n /**\n * Add a modular animation to the clip\n * @param name Preset name or 'keyframes'\n * @param opts Animation options (duration, delay, etc.)\n * @param params Preset-specific parameters or KeyframeData\n */\n addAnimation(name: string, options: any, params?: any): string {\n const anim = animationRegistry.create(name, options, params);\n this.animations.push(anim);\n this.emit(\"propsChange\", { animations: this.animations } as any);\n return anim.id;\n }\n\n /**\n * Remove an animation by ID\n */\n removeAnimation(id: string): void {\n const toRemove = this.animations.find((a) => a.id === id);\n if (toRemove && typeof (toRemove as any).destroy === \"function\") {\n (toRemove as any).destroy();\n }\n this.animations = this.animations.filter((a) => a.id !== id);\n this.emit(\"propsChange\", { animations: this.animations } as any);\n }\n\n /**\n * Clear all modular animations\n */\n clearAnimations(): void {\n this.animations.forEach((a) => {\n if (a && typeof (a as any).destroy === \"function\") {\n (a as any).destroy();\n }\n });\n this.animations = [];\n this.emit(\"propsChange\", { animations: this.animations } as any);\n }\n\n /**\n * Update an existing animation by ID\n * @param id Animation ID to update\n * @param type Animation type (preset name or 'keyframes')\n * @param opts Animation options\n * @param params Preset-specific parameters or KeyframeData\n */\n updateAnimation(id: string, type: string, options: any, params?: any): void {\n const index = this.animations.findIndex((a) => a.id === id);\n if (index === -1) return;\n\n const oldAnim = this.animations[index];\n if (oldAnim && typeof (oldAnim as any).destroy === \"function\") {\n (oldAnim as any).destroy();\n }\n\n const newAnim = animationRegistry.create(type, { ...options, id }, params);\n this.animations[index] = newAnim;\n this.emit(\"propsChange\", { animations: this.animations } as any);\n }\n\n /**\n * Copy current sprite's properties to target\n *\n * Used for cloning or copying state between {@link OffscreenSprite} instances\n */\n copyStateTo<T extends BaseSprite>(target: T) {\n target.animatKeyFrame = this.animatKeyFrame;\n target.animatOptions = this.animatOptions;\n target.zIndex = this.zIndex;\n target.opacity = this.opacity;\n target.volume = this.volume;\n target.flip = this.flip;\n target.left = this.left;\n target.top = this.top;\n target.width = this.width;\n target.height = this.height;\n target.angle = this.angle;\n target.display = { ...this.display };\n target.duration = this.duration;\n target.playbackRate = this.playbackRate;\n target.trim = { ...this.trim };\n // Copy fade settings so they are preserved when cloning for the compositor\n if (this.timing.fadeIn !== undefined) {\n target.timing.fadeIn = { ...this.timing.fadeIn };\n }\n if (this.timing.fadeOut !== undefined) {\n target.timing.fadeOut = { ...this.timing.fadeOut };\n }\n target.style = JSON.parse(JSON.stringify(this.style || {}));\n target.animations = [...this.animations];\n if (this.chromaKey !== undefined) target.chromaKey = { ...this.chromaKey };\n if (this.colorAdjustment !== undefined)\n target.colorAdjustment = JSON.parse(JSON.stringify(this.colorAdjustment));\n target.locked = this.locked;\n target.muted = this.muted;\n // Copy src if target is a BaseClip\n if (\"src\" in this && \"src\" in target) {\n (target as any).src = (this as any).src;\n }\n // Copy metadata if target is a BaseClip\n if (\"metadata\" in this && \"metadata\" in target) {\n (target as any).metadata = JSON.parse(JSON.stringify((this as any).metadata || {}));\n }\n }\n\n /**\n * Update multiple properties at once\n */\n update(updates: Partial<this>) {\n Object.assign(this, updates);\n this.emit(\"propsChange\", updates as any);\n }\n\n protected destroy() {\n this.animations.forEach((a) => {\n if (a && typeof (a as any).destroy === \"function\") {\n (a as any).destroy();\n }\n });\n this.animations = [];\n this.all.clear();\n }\n}\n\nexport function linearTimeFn(\n time: number,\n keyFrame: TAnimationKeyFrame,\n options: Required<IAnimationOptions>,\n): Partial<TAnimateProps> {\n const offsetTime = time - options.delay;\n const t = offsetTime % options.duration;\n const progress =\n offsetTime / options.duration >= options.iterCount || offsetTime === options.duration\n ? 1\n : t / options.duration;\n\n const idx = keyFrame.findIndex((it) => it[0] >= progress);\n if (idx === -1) return {};\n\n const startState = keyFrame[idx - 1];\n const nextState = keyFrame[idx];\n const nextFrame = nextState[1];\n if (startState == null) return nextFrame;\n const startFrame = startState[1];\n\n const result: Partial<TAnimateProps> = {};\n // Progress between two Frame states\n const stateProcess = (progress - startState[0]) / (nextState[0] - startState[0]);\n for (const prop in nextFrame) {\n if (!Object.hasOwn(nextFrame, prop)) continue;\n // Skip symbol keys - only process string keys\n if (typeof prop !== \"string\") continue;\n const p = prop as Extract<keyof TAnimateProps, string>;\n if (startFrame[p] == null) continue;\n result[p] = (nextFrame[p] - startFrame[p]) * stateProcess + startFrame[p];\n }\n\n return result;\n}\n","import { Log } from \"../utils/log\";\nimport { BaseSprite, BaseSpriteEvents } from \"../sprite/base-sprite\";\nimport { changePCMPlaybackRate } from \"../utils\";\nimport type { IClip, IClipMeta, ITransitionInfo } from \"./iclip\";\nimport type { ClipJSON } from \"../json-serialization\";\n\n/** Convert a VideoFrame to ImageBitmap and release the frame. */\nasync function videoFrameToImageBitmap(video: VideoFrame): Promise<ImageBitmap> {\n try {\n const bitmap = await createImageBitmap(video);\n video.close();\n return bitmap;\n } catch {\n const w = video.displayWidth;\n const h = video.displayHeight;\n if (w <= 0 || h <= 0) {\n video.close();\n throw new Error(\"VideoFrame has invalid dimensions\");\n }\n const canvas = new OffscreenCanvas(w, h);\n const ctx = canvas.getContext(\"2d\");\n if (ctx == null) {\n video.close();\n throw new Error(\"Failed to get 2d context for VideoFrame conversion\");\n }\n ctx.drawImage(video, 0, 0, w, h);\n video.close();\n return createImageBitmap(canvas);\n }\n}\n\n/**\n * Base class for all clips that extends BaseSprite\n * Provides common functionality for sprite operations (position, animation, timing)\n * and frame management\n */\nexport abstract class BaseClip<T extends BaseSpriteEvents = BaseSpriteEvents>\n extends BaseSprite<T>\n implements IClip<T>\n{\n abstract readonly type: string;\n // Keep last frame, if clip has no data at current frame, render last frame\n // Store as ImageBitmap for reusability (VideoFrames cannot be reused after close)\n private lastVf: ImageBitmap | null = null;\n\n protected destroyed = false;\n\n /**\n * Source URL or identifier for this clip\n * Used for serialization and reloading from JSON\n */\n src: string = \"\";\n\n /**\n * User-defined metadata\n */\n metadata: Record<string, any> = {};\n\n /**\n * Transition info (optional)\n */\n transition?: ITransitionInfo;\n\n /**\n * When set, the clip's RenderTexture is larger than its logical bounds by this many pixels\n * on each side. Provides overflow room for animations (slide, zoom) without visual clipping.\n */\n renderTexturePadding?: number;\n\n abstract tick(time: number): Promise<{\n video?: VideoFrame | ImageBitmap | null;\n audio?: Float32Array[];\n state: \"done\" | \"success\";\n }>;\n\n // Override ready from BaseSprite to return IClipMeta instead of void\n // This is set by subclasses in their constructors\n declare ready: Promise<IClipMeta>;\n abstract readonly meta: IClipMeta;\n abstract clone(): Promise<this>;\n abstract split?(time: number): Promise<[this, this]>;\n\n constructor() {\n super();\n // Note: ready will be set by subclasses in their constructors\n // This default implementation is just a placeholder\n }\n\n /**\n * Get video frame and audio at specified time without rendering to canvas\n * Useful for Pixi.js rendering where canvas context is not needed\n * @param time Specified time in microseconds\n */\n async getFrame(time: number): Promise<{\n video: VideoFrame | ImageBitmap | null;\n audio: Float32Array[];\n done: boolean;\n }> {\n // Note: animate() is called by Compositor before getFrame(), so we don't call it here\n // to avoid applying playback rate twice\n const timestamp = time * this.playbackRate;\n const { video, audio, state } = await this.tick(timestamp);\n\n let outAudio = audio ?? [];\n if (audio != null && this.playbackRate !== 1) {\n outAudio = audio.map((pcm) => changePCMPlaybackRate(pcm, this.playbackRate));\n }\n\n // Always hand ImageBitmap to renderers. VideoFrames are single-use and\n // Texture.from() may upload asynchronously; closing the VideoFrame early\n // (before upload completes) produces a black first frame during export.\n let frameSource: VideoFrame | ImageBitmap | null = null;\n if (video != null) {\n if (video instanceof VideoFrame) {\n this.lastVf?.close();\n const bitmap = await videoFrameToImageBitmap(video);\n this.lastVf = bitmap;\n frameSource = bitmap;\n } else {\n // ImageBitmap — store directly for reuse\n this.lastVf?.close();\n this.lastVf = video;\n frameSource = video;\n }\n } else if (this.lastVf != null) {\n // Reuse last frame if no new frame available\n frameSource = this.lastVf;\n }\n\n return {\n video: frameSource,\n audio: outAudio,\n done: state === \"done\",\n };\n }\n\n /**\n * Draw image at specified time to canvas context and return corresponding audio data\n * @param time Specified time in microseconds\n */\n async offscreenRender(\n ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,\n time: number,\n ): Promise<{\n audio: Float32Array[];\n done: boolean;\n }> {\n const timestamp = time * this.playbackRate;\n this.animate(timestamp);\n super._render(ctx);\n const { width: w, height: h } = this;\n const { video, audio, state } = await this.tick(timestamp);\n let outAudio = audio ?? [];\n if (audio != null && this.playbackRate !== 1) {\n outAudio = audio.map((pcm) => changePCMPlaybackRate(pcm, this.playbackRate));\n }\n\n if (state === \"done\") {\n return {\n audio: outAudio,\n done: true,\n };\n }\n\n // Draw texture\n const imgSource: VideoFrame | ImageBitmap | null = video ?? this.lastVf;\n if (imgSource != null) {\n const borderRadius = this.style.borderRadius || 0;\n const shadow = this.style.shadow;\n\n ctx.save();\n\n // 1. Apply Drop Shadow (Canvas2D native)\n if (\n shadow &&\n (shadow.blur > 0 || shadow.offsetX !== undefined || shadow.offsetY !== undefined)\n ) {\n ctx.shadowColor = shadow.color || \"#000000\";\n ctx.shadowBlur = shadow.blur || 0;\n ctx.shadowOffsetX = shadow.offsetX ?? 0;\n ctx.shadowOffsetY = shadow.offsetY ?? 0;\n }\n\n // 2. Apply Border Radius (Clipping)\n if (borderRadius > 0) {\n const r = Math.min(borderRadius, w / 2, h / 2);\n ctx.beginPath();\n ctx.roundRect(-w / 2, -h / 2, w, h, r);\n ctx.clip();\n }\n\n ctx.drawImage(imgSource, -w / 2, -h / 2, w, h);\n ctx.restore();\n\n // 3. Render Stroke (on top of clipped image)\n const stroke = this.style.stroke;\n if (stroke && stroke.width > 0) {\n ctx.save();\n ctx.strokeStyle = stroke.color;\n ctx.lineWidth = stroke.width;\n\n if (borderRadius > 0) {\n const r = Math.min(borderRadius, w / 2, h / 2);\n ctx.beginPath();\n ctx.roundRect(-w / 2, -h / 2, w, h, r);\n ctx.stroke();\n } else {\n ctx.strokeRect(-w / 2, -h / 2, w, h);\n }\n ctx.restore();\n }\n }\n\n // Store frame for reuse (convert VideoFrame to ImageBitmap if needed)\n if (video != null) {\n this.lastVf?.close();\n // Note: For offscreenRender, we keep video as-is for now since it's used with canvas\n // But since lastVf is ImageBitmap, we should convert VideoFrame if present\n // However, offscreenRender is mainly for compatibility, getFrame() is the main path\n // For now, only store ImageBitmap in lastVf (video might be VideoFrame)\n if (video instanceof ImageBitmap) {\n this.lastVf = video;\n }\n // If it's a VideoFrame, we don't store it since lastVf expects ImageBitmap\n // The video frame will be used directly in drawImage above\n }\n\n return {\n audio: outAudio,\n done: false,\n };\n }\n\n /**\n * Set clip properties (position, size, display timeline)\n * @param props Properties to set\n * @param fps Optional FPS for frame-to-time conversion (default: 30)\n * @returns this for method chaining\n *\n * @example\n * // Using frames (will be converted to microseconds)\n * clip.set({\n * display: {\n * from: 150, // frames\n * to: 450, // frames (10 seconds at 30fps)\n * },\n * }, 30);\n *\n * // Using microseconds directly\n * clip.set({\n * display: {\n * from: 5000000, // microseconds\n * to: 15000000, // microseconds\n * },\n * });\n */\n set(\n props: {\n display?: {\n from?: number;\n to?: number;\n };\n x?: number;\n y?: number;\n width?: number;\n height?: number;\n duration?: number;\n timing?: {\n display?: {\n from?: number;\n to?: number;\n };\n trim?: {\n from?: number;\n to?: number;\n };\n duration?: number;\n playbackRate?: number;\n fadeIn?: {\n duration: number;\n curve?: \"linear\" | \"ease-in\" | \"ease-out\" | \"ease-in-out\";\n };\n fadeOut?: {\n duration: number;\n curve?: \"linear\" | \"ease-in\" | \"ease-out\" | \"ease-in-out\";\n };\n };\n },\n _fps: number = 30,\n ): this {\n if (props.timing) {\n if (props.timing.display) {\n if (props.timing.display.from !== undefined) {\n this.timing.display.from = props.timing.display.from;\n }\n if (props.timing.display.to !== undefined) {\n this.timing.display.to = props.timing.display.to;\n }\n }\n if (props.timing.trim) {\n if (props.timing.trim.from !== undefined) {\n this.timing.trim.from = props.timing.trim.from;\n }\n if (props.timing.trim.to !== undefined) {\n this.timing.trim.to = props.timing.trim.to;\n }\n }\n if (props.timing.duration !== undefined) {\n this.timing.duration = props.timing.duration;\n }\n if (props.timing.playbackRate !== undefined) {\n this.timing.playbackRate = props.timing.playbackRate;\n }\n if (props.timing.fadeIn !== undefined) {\n this.timing.fadeIn = props.timing.fadeIn;\n }\n if (props.timing.fadeOut !== undefined) {\n this.timing.fadeOut = props.timing.fadeOut;\n }\n }\n\n if (props.display) {\n if (props.display.from !== undefined) {\n this.display.from = props.display.from;\n }\n if (props.display.to !== undefined) {\n this.display.to = props.display.to;\n }\n }\n\n if (props.x !== undefined) this.left = props.x;\n if (props.y !== undefined) this.top = props.y;\n if (props.width !== undefined) this.width = props.width;\n if (props.height !== undefined) this.height = props.height;\n\n if (props.duration !== undefined) {\n this.duration = props.duration;\n // Update display.to if duration is set and display.from is set\n if (this.display.from !== undefined) {\n this.display.to = this.display.from + this.duration;\n }\n }\n\n return this;\n }\n\n /**\n * Base implementation of toJSON that handles common clip properties\n * Subclasses should override to add their specific options\n * @param main Whether this is the main clip (for Compositor)\n */\n toJSON(main: boolean = false): ClipJSON {\n const animation =\n (this as any).animatKeyFrame && (this as any).animatOptions\n ? {\n keyFrames: (this as any).animatKeyFrame.reduce(\n (acc: any, [progress, props]: [number, any]) => {\n const key =\n progress === 0\n ? \"from\"\n : progress === 1\n ? \"to\"\n : `${Math.round(progress * 100)}%`;\n acc[key] = props;\n return acc;\n },\n {},\n ),\n options: (this as any).animatOptions,\n }\n : undefined;\n\n // Extract new modular animations\n const animations = this.animations.map((a) => {\n if (\"toJSON\" in a && typeof (a as any).toJSON === \"function\") {\n return (a as any).toJSON();\n }\n return {\n type: a.type,\n options: a.options,\n params: a.params || {},\n };\n });\n\n const style = this.style ? JSON.parse(JSON.stringify(this.style)) : undefined;\n\n return {\n type: this.type as ClipJSON[\"type\"],\n id: this.id,\n name: this.name,\n src: this.src,\n timing: {\n display: {\n from: this.timing.display.from,\n to: this.timing.display.to,\n },\n trim: {\n from: this.timing.trim.from,\n to: this.timing.trim.to,\n },\n duration: this.timing.duration,\n playbackRate: this.timing.playbackRate,\n fadeIn: this.timing.fadeIn,\n fadeOut: this.timing.fadeOut,\n },\n transform: {\n x: this.left,\n y: this.top,\n width: this.width,\n height: this.height,\n angle: this.angle,\n opacity: this.opacity,\n zIndex: this.zIndex,\n flip: this.flip,\n },\n style,\n ...(animation && { animation }),\n ...(animations.length > 0 && { animations }),\n ...(main && { main: true }),\n ...(this.chromaKey !== undefined && { chromaKey: this.chromaKey }),\n ...(this.colorAdjustment !== undefined && { colorAdjustment: this.colorAdjustment }),\n locked: this.locked,\n muted: this.muted,\n metadata: this.metadata,\n } as ClipJSON;\n }\n\n /**\n * Get the list of visible transformer handles for this clip type\n * Default implementation returns all handles\n * Override in subclasses to customize handle visibility (e.g., TextClip)\n */\n getVisibleHandles(): Array<\"tl\" | \"tr\" | \"bl\" | \"br\" | \"ml\" | \"mr\" | \"mt\" | \"mb\" | \"rot\"> {\n return [\"tl\", \"tr\", \"bl\", \"br\", \"ml\", \"mr\", \"mt\", \"mb\", \"rot\"];\n }\n\n /**\n * Scale clip to fit within the scene dimensions while maintaining aspect ratio\n * @param sceneWidth Scene width\n * @param sceneHeight Scene height\n */\n async scaleToFit(sceneWidth: number, sceneHeight: number): Promise<void> {\n await this.ready;\n const { width, height } = this.meta;\n if (width === 0 || height === 0) return;\n\n const scale = Math.min(sceneWidth / width, sceneHeight / height);\n this.width = width * scale;\n this.height = height * scale;\n }\n\n /**\n * Scale clip to fill the scene dimensions while maintaining aspect ratio\n * May crop parts of the clip.\n * @param sceneWidth Scene width\n * @param sceneHeight Scene height\n */\n async scaleToFill(sceneWidth: number, sceneHeight: number): Promise<void> {\n await this.ready;\n const { width, height } = this.meta;\n if (width === 0 || height === 0) return;\n\n const scale = Math.max(sceneWidth / width, sceneHeight / height);\n this.width = width * scale;\n this.height = height * scale;\n }\n\n /**\n * Center the clip within the scene dimensions\n * @param sceneWidth Scene width\n * @param sceneHeight Scene height\n */\n centerInScene(sceneWidth: number, sceneHeight: number): void {\n this.left = (sceneWidth - this.width) / 2;\n this.top = (sceneHeight - this.height) / 2;\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n\n Log.info(\"BaseClip destroy\");\n super.destroy();\n this.lastVf?.close();\n this.lastVf = null;\n }\n\n /**\n * Applies all common properties from JSON to a clip instance.\n * This handles transform, timing, style, animation, transitions, chroma key, color adjustment, and generic metadata.\n */\n static deserializeBaseProperties(clip: BaseClip, json: any): void {\n if (json.transform) {\n clip.left = json.transform.x ?? clip.left;\n clip.top = json.transform.y ?? clip.top;\n clip.width = json.transform.width ?? clip.width;\n clip.height = json.transform.height ?? clip.height;\n clip.angle = json.transform.angle ?? clip.angle;\n clip.zIndex = json.transform.zIndex ?? clip.zIndex;\n clip.opacity = json.transform.opacity ?? clip.opacity;\n if (json.transform.flip !== undefined) {\n clip.flip = json.transform.flip ?? null;\n }\n }\n\n const timing = json.timing || {\n display: json.display || { from: 0, to: 0 },\n trim: json.trim || { from: 0, to: 0 },\n duration: json.duration ?? 0,\n playbackRate: json.playbackRate ?? 1,\n };\n\n clip.display.from = timing.display.from ?? clip.display.from;\n clip.display.to = timing.display.to ?? clip.display.to;\n clip.duration = timing.duration ?? clip.duration;\n clip.playbackRate = timing.playbackRate ?? clip.playbackRate;\n\n if (timing.trim) {\n clip.trim = {\n from: timing.trim.from ?? clip.trim.from,\n to: timing.trim.to ?? clip.trim.to,\n };\n }\n\n if (timing.fadeIn !== undefined) clip.timing.fadeIn = timing.fadeIn;\n if (timing.fadeOut !== undefined) clip.timing.fadeOut = timing.fadeOut;\n\n if (json.style) {\n const currentStyle = clip.style || {};\n const newStyle = { ...currentStyle, ...json.style };\n if (JSON.stringify(currentStyle) !== JSON.stringify(newStyle)) {\n clip.style = newStyle;\n }\n }\n\n // Apply animation if present\n if (json.animation) {\n clip.setAnimation(json.animation.keyFrames, json.animation.options);\n }\n\n // Apply modular animations if present\n if (json.animations && Array.isArray(json.animations)) {\n clip.clearAnimations();\n for (const anim of json.animations) {\n clip.addAnimation(anim.type, anim.options, anim.params);\n }\n }\n\n // Apply basic properties\n if (json.id) clip.id = json.id;\n if (json.name) clip.name = json.name;\n if (json.metadata) clip.metadata = json.metadata;\n if (json.locked !== undefined) clip.locked = json.locked;\n if (json.muted !== undefined) clip.muted = json.muted;\n\n if (json.transition) {\n clip.transition = json.transition;\n }\n\n if (json.chromaKey?.enabled) {\n clip.chromaKey = { ...clip.chromaKey, ...json.chromaKey };\n }\n\n if (json.colorAdjustment?.enabled) {\n clip.colorAdjustment = {\n ...clip.colorAdjustment,\n ...json.colorAdjustment,\n };\n }\n }\n}\n","import type { BaseSprite, BaseSpriteEvents } from \"../sprite/base-sprite\";\nimport { getDefaultAudioCodec, getCachedAudioCodec } from \"../utils/audio-codec-detector\";\nimport { ColorAdjustment } from \"../utils/color-adjustment\";\n\nexport interface IClipMeta {\n width: number;\n height: number;\n duration: number;\n}\n\nexport interface ITransitionInfo {\n name: string;\n duration: number; // in microseconds\n textureUrl?: string;\n prevClipId?: string;\n fromClipId?: string;\n toClipId?: string;\n start?: number;\n end?: number;\n}\n\nexport interface IChromaKeyOpts {\n enabled: boolean;\n color: string;\n similarity: number;\n spill: number;\n}\n\n/**\n * Interface that all clips must implement\n *\n * Clips are abstractions of different data types, providing data to other modules\n *\n *\n * You only need to implement this interface to create custom clips, giving you maximum flexibility to generate video content such as animations and transition effects\n *\n */\nexport interface IClip<T extends BaseSpriteEvents = BaseSpriteEvents> extends Omit<\n BaseSprite<T>,\n \"destroy\" | \"ready\"\n> {\n // Override destroy to be public (BaseSprite has it as protected)\n // Override ready to return IClipMeta instead of Promise<void>\n destroy: () => void;\n readonly ready: Promise<IClipMeta>;\n\n /**\n * Clip type (e.g., 'video', 'image', 'text', 'audio')\n */\n readonly type: string;\n\n /**\n * Name of this clip\n */\n name: string;\n\n /**\n * User-defined metadata\n */\n metadata: Record<string, any>;\n\n /**\n * Source URL or identifier for this clip\n */\n src: string;\n\n // Clip-specific methods\n /**\n * Extract data from clip at specified time\n * @param time Time in microseconds\n */\n tick: (time: number) => Promise<{\n video?: VideoFrame | ImageBitmap | null;\n audio?: Float32Array[];\n state: \"done\" | \"success\";\n }>;\n\n /**\n * Get video frame and audio at specified time\n * This method is provided by BaseClip and used by Compositor\n */\n getFrame(time: number): Promise<{\n video: VideoFrame | ImageBitmap | null;\n audio: Float32Array[];\n done: boolean;\n }>;\n\n /**\n * Data metadata\n */\n readonly meta: IClipMeta;\n\n /**\n * When set, the clip's RenderTexture is larger than its logical bounds by this many pixels\n * on each side (top, right, bottom, left). This provides transparent overflow room so that\n * animations (e.g. slide, zoom) can move content outside the clip boundary without clipping.\n * Selection handles, hit areas, and position sync all use the logical bounds, not the texture size.\n */\n renderTexturePadding?: number;\n\n /**\n * Clone and return a new clip\n */\n clone: () => Promise<this>;\n\n /**\n * Split at specified time, return two new clips before and after that moment, commonly used in editing scenarios to split clips by time\n *\n * This method will not corrupt original clip data\n *\n * @param time Time in microseconds\n * @returns\n */\n split?: (time: number) => Promise<[this, this]>;\n\n /**\n * Serialize clip to JSON format\n * Returns a plain object with only serializable data (no circular references)\n * @param main Whether this is the main clip (for Compositor)\n */\n toJSON(main?: boolean): any;\n\n /**\n * Set an external renderer (e.g., from Studio)\n * This is called by Studio when adding clips to provide a shared renderer\n * @param renderer The PixiJS renderer to use\n */\n setRenderer?(renderer: any): void;\n\n /**\n * Transition info (optional)\n */\n transition?: ITransitionInfo;\n\n /**\n * Audio volume level (0-1)\n */\n volume: number;\n\n /**\n * Styling properties (e.g., stroke, dropShadow, borderRadius)\n */\n style: any;\n\n /**\n * Get the list of visible transformer handles for this clip type\n * Similar to Fabric.js v6 controls visibility pattern\n * @returns Array of handle kinds that should be visible\n */\n getVisibleHandles?: () => Array<\"tl\" | \"tr\" | \"bl\" | \"br\" | \"ml\" | \"mr\" | \"mt\" | \"mb\" | \"rot\">;\n\n /**\n * Scale clip to fit within the scene dimensions while maintaining aspect ratio\n */\n scaleToFit(sceneWidth: number, sceneHeight: number): Promise<void>;\n\n /**\n * Scale clip to fill the scene dimensions while maintaining aspect ratio\n */\n scaleToFill(sceneWidth: number, sceneHeight: number): Promise<void>;\n\n /**\n * Center the clip within the scene dimensions\n */\n centerInScene(sceneWidth: number, sceneHeight: number): void;\n\n /**\n * Add a modular animation to the clip\n * @param name Preset name or 'keyframes'\n * @param opts Animation options (duration, delay, etc.)\n * @param params Preset-specific parameters or KeyframeData\n */\n addAnimation(name: string, options: any, params?: any): string;\n\n /**\n * Remove an animation by ID\n */\n removeAnimation(id: string): void;\n\n /**\n * Clear all modular animations\n */\n clearAnimations(): void;\n\n /**\n * List of active animations\n */\n readonly animations: any[];\n\n /**\n * Chroma key settings (green screen removal)\n */\n chromaKey?: IChromaKeyOpts;\n\n /**\n * Clip color adjustment settings\n */\n colorAdjustment?: ColorAdjustment;\n\n /**\n * Whether the clip is locked (preventing interactions)\n */\n locked: boolean;\n\n /**\n * Whether the clip's audio is muted\n */\n muted: boolean;\n}\n\n/**\n * Optional interface for clips that support HTML media element playback\n * Used by Studio for interactive preview\n */\nexport interface IPlaybackCapable {\n /**\n * Create and initialize HTML media element for playback\n * @returns Promise resolving to the media element and optional object URL for cleanup\n */\n createPlaybackElement(): Promise<{\n element: HTMLVideoElement | HTMLAudioElement;\n objectUrl?: string;\n }>;\n\n /**\n * Start playback at a specific time\n * @param element The HTML media element\n * @param timeSeconds Time in seconds (relative to clip start)\n */\n play(element: HTMLVideoElement | HTMLAudioElement, timeSeconds: number): Promise<void>;\n\n /**\n * Pause playback\n * @param element The HTML media element\n */\n pause(element: HTMLVideoElement | HTMLAudioElement): void;\n\n /**\n * Seek to a specific time\n * @param element The HTML media element\n * @param timeSeconds Time in seconds (relative to clip start)\n */\n seek(element: HTMLVideoElement | HTMLAudioElement, timeSeconds: number): Promise<void>;\n\n /**\n * Sync playback state during preview\n * @param element The HTML media element\n * @param isPlaying Whether playback should be active\n * @param timeSeconds Current time in seconds (relative to clip start)\n */\n syncPlayback(\n element: HTMLVideoElement | HTMLAudioElement,\n isPlaying: boolean,\n timeSeconds: number,\n ): void;\n\n /**\n * Clean up playback element and resources\n * @param element The HTML media element\n * @param objectUrl Optional object URL to revoke\n */\n cleanupPlayback(element: HTMLVideoElement | HTMLAudioElement, objectUrl?: string): void;\n}\n\n/**\n * Default audio settings, ⚠️ do not change its values ⚠️\n * Automatically selects the best supported audio codec:\n * - Prefers AAC (mp4a.40.2) for better quality and compatibility\n * - Falls back to Opus when AAC is not supported (e.g., some Linux browsers)\n */\n\n// Initialize codec detection immediately\nlet audioCodecPromise: Promise<{\n codec: string;\n sampleRate: number;\n channelCount: number;\n}> | null = null;\n\n/**\n * Get the default audio configuration\n * This function returns a promise that resolves to the best supported audio codec\n */\nexport async function getDefaultAudioConf() {\n if (audioCodecPromise === null) {\n audioCodecPromise = getDefaultAudioCodec();\n }\n return await audioCodecPromise;\n}\n\n/**\n * Synchronous version that returns cached codec or a default fallback\n * Use this only when you need synchronous access (e.g., in constants)\n * Prefer getDefaultAudioConf() for async contexts\n */\nexport const DEFAULT_AUDIO_CONF = {\n get codec() {\n return getCachedAudioCodec()?.codec ?? \"mp4a.40.2\";\n },\n get codecType(): \"aac\" | \"opus\" {\n return getCachedAudioCodec()?.codecType ?? \"aac\";\n },\n get sampleRate() {\n return getCachedAudioCodec()?.sampleRate ?? 48000;\n },\n get channelCount() {\n return getCachedAudioCodec()?.channelCount ?? 2;\n },\n} as const;\n","import { file, write } from \"opfs-tools\";\n\n/**\n * Persistent (OPFS) copy of remote assets, keyed by a hash of the URL.\n *\n * Writes to one key are serialised and a \".done\" marker is written only after the content, so a\n * concurrent or interrupted write is never served as a cached file. (opfs-tools allows one writer\n * per file: two overlapping puts used to throw \"Other writer have not been closed\", and readers could\n * pick up a half-written file.)\n */\nexport class AssetManager {\n private static writes = new Map<string, Promise<unknown>>();\n\n private static async getCacheKey(url: string): Promise<string> {\n const data = new TextEncoder().encode(url);\n const hashBuffer = await crypto.subtle.digest(\"SHA-1\", data);\n return Array.from(new Uint8Array(hashBuffer))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n }\n\n private static getPath(key: string): string {\n return `assets/${key}`;\n }\n\n static async get(url: string) {\n const path = this.getPath(await this.getCacheKey(url));\n const pendingWrite = this.writes.get(path);\n if (pendingWrite) await pendingWrite.catch(() => {});\n const f = file(path);\n if ((await file(`${path}.done`).exists()) && (await f.exists())) {\n return f;\n }\n return null;\n }\n\n static async put(url: string, data: ReadableStream<Uint8Array> | Blob) {\n const path = this.getPath(await this.getCacheKey(url));\n const previous = this.writes.get(path) ?? Promise.resolve();\n const job = previous\n .catch(() => {})\n .then(async () => {\n const marker = file(`${path}.done`);\n if (await marker.exists()) await marker.remove();\n const f = file(path);\n const source = data instanceof Blob ? (data.stream() as ReadableStream<Uint8Array>) : data;\n await write(f, source as any);\n await write(marker, \"1\");\n return f;\n });\n this.writes.set(path, job);\n try {\n return await job;\n } finally {\n if (this.writes.get(path) === job) this.writes.delete(path);\n }\n }\n}\n","import { AssetManager } from \"./asset-manager\";\n\n/**\n * Shared media cache for video/audio/image/font bytes.\n *\n * Every consumer (clip creation, preload, split/duplicate, export Compositor, app timeline\n * thumbnails/waveforms) gets the same bytes for a URL:\n * 1. in-flight requests are shared (one network fetch per URL at a time),\n * 2. completed downloads stay in an in-memory LRU of Blobs (byte budget; browsers keep large\n * Blobs in their blob store, not the JS heap),\n * 3. remote URLs are persisted to OPFS (AssetManager) for later sessions.\n *\n * It is a globalThis singleton so duplicated bundle copies share one cache.\n */\nexport interface MediaCacheOptions {\n /** Total bytes kept in memory (default 768 MB) */\n maxMemoryBytes?: number;\n /** Larger entries are not kept in memory, only in OPFS (default 400 MB) */\n maxEntryBytes?: number;\n}\n\ninterface Entry {\n blob: Blob;\n size: number;\n}\n\nconst isLocalUrl = (url: string) => url.startsWith(\"data:\") || url.startsWith(\"blob:\");\n\nexport class MediaCache {\n private memory = new Map<string, Entry>(); // insertion order = LRU order\n private memoryBytes = 0;\n private inflight = new Map<string, Promise<Blob>>();\n private maxMemoryBytes: number;\n private maxEntryBytes: number;\n\n constructor(opts: MediaCacheOptions = {}) {\n this.maxMemoryBytes = opts.maxMemoryBytes ?? 768 * 1024 * 1024;\n this.maxEntryBytes = opts.maxEntryBytes ?? 400 * 1024 * 1024;\n }\n\n configure(opts: MediaCacheOptions) {\n if (opts.maxMemoryBytes != null) this.maxMemoryBytes = opts.maxMemoryBytes;\n if (opts.maxEntryBytes != null) this.maxEntryBytes = opts.maxEntryBytes;\n this.evict();\n }\n\n /** Cache key: absolute URL (relative paths resolve against the page) */\n key(url: string): string {\n if (isLocalUrl(url)) return url;\n try {\n return typeof location !== \"undefined\" ? new URL(url, location.href).href : url;\n } catch {\n return url;\n }\n }\n\n /** Bytes for a URL, from memory, an in-flight request, OPFS, or the network (in that order) */\n getBlob(url: string): Promise<Blob> {\n const key = this.key(url);\n const hit = this.memory.get(key);\n if (hit) {\n // refresh LRU position\n this.memory.delete(key);\n this.memory.set(key, hit);\n return Promise.resolve(hit.blob);\n }\n const pending = this.inflight.get(key);\n if (pending) return pending;\n\n const load = this.load(key).finally(() => this.inflight.delete(key));\n this.inflight.set(key, load);\n return load;\n }\n\n async getStream(url: string): Promise<ReadableStream<Uint8Array>> {\n return (await this.getBlob(url)).stream() as ReadableStream<Uint8Array>;\n }\n\n /** A fresh ImageBitmap per call (callers own and may close it); the bytes are shared */\n async getImageBitmap(url: string): Promise<ImageBitmap> {\n return createImageBitmap(await this.getBlob(url));\n }\n\n async getArrayBuffer(url: string): Promise<ArrayBuffer> {\n return (await this.getBlob(url)).arrayBuffer();\n }\n\n /** Warm the cache; resolves once every URL is loaded (failures are ignored) */\n async preload(urls: string[]): Promise<void> {\n const unique = [...new Set(urls.filter((u) => u && !isLocalUrl(u)))];\n await Promise.allSettled(unique.map((u) => this.getBlob(u)));\n }\n\n has(url: string): boolean {\n return this.memory.has(this.key(url));\n }\n\n /** Forget a URL in memory (OPFS copy stays) */\n release(url: string) {\n const key = this.key(url);\n const entry = this.memory.get(key);\n if (entry) {\n this.memory.delete(key);\n this.memoryBytes -= entry.size;\n }\n }\n\n clearMemory() {\n this.memory.clear();\n this.memoryBytes = 0;\n }\n\n private async load(key: string): Promise<Blob> {\n if (isLocalUrl(key)) {\n const blob = await (await fetch(key)).blob();\n this.remember(key, blob);\n return blob;\n }\n\n const cached = await AssetManager.get(key).catch(() => null);\n if (cached) {\n const file = await cached.getOriginFile().catch(() => null);\n if (file && file.size > 0) {\n this.remember(key, file);\n return file;\n }\n }\n\n const response = await fetch(key);\n if (!response.ok) throw new Error(`Failed to fetch ${key}: ${response.status} ${response.statusText}`);\n const blob = await response.blob();\n this.remember(key, blob);\n // Persist for later sessions; never blocks the caller and never exposes a partial file\n AssetManager.put(key, blob).catch((err) => console.warn(`[MediaCache] Failed to persist ${key}:`, err));\n return blob;\n }\n\n private remember(key: string, blob: Blob) {\n if (blob.size > this.maxEntryBytes) return;\n const prev = this.memory.get(key);\n if (prev) this.memoryBytes -= prev.size;\n this.memory.delete(key);\n this.memory.set(key, { blob, size: blob.size });\n this.memoryBytes += blob.size;\n this.evict();\n }\n\n private evict() {\n for (const [key, entry] of this.memory) {\n if (this.memoryBytes <= this.maxMemoryBytes) break;\n this.memory.delete(key);\n this.memoryBytes -= entry.size;\n }\n }\n}\n\nconst GLOBAL_KEY = Symbol.for(\"agrhub.engine.mediaCache\");\nconst g = globalThis as any;\nexport const mediaCache: MediaCache = g[GLOBAL_KEY] ?? (g[GLOBAL_KEY] = new MediaCache());\n","import { file } from \"opfs-tools\";\nimport { AssetManager } from \"../utils/asset-manager\";\nimport { mediaCache } from \"../utils/media-cache\";\n\nexport enum ResourceStatus {\n PENDING = \"pending\",\n LOADING = \"loading\",\n COMPLETED = \"completed\",\n FAILED = \"failed\",\n}\n\nexport interface ResourceItem {\n url: string;\n status: ResourceStatus;\n localFile?: ReturnType<typeof file>;\n error?: Error;\n}\n\n/**\n * ResourceManager handles asset preloading and caching in OPFS.\n * It ensures that resources are downloaded only once and reused across sessions.\n */\nexport class ResourceManager {\n private resources = new Map<string, ResourceItem>();\n private loadingPromises = new Map<string, Promise<ResourceItem>>();\n\n /**\n * Preload a batch of URLs in parallel.\n * @param urls Array of URLs to preload\n */\n async preload(urls: string[]): Promise<void> {\n const uniqueUrls = [...new Set(urls)].filter((url) => {\n // Skip data URLs and blob URLs\n return url && !url.startsWith(\"data:\") && !url.startsWith(\"blob:\");\n });\n\n const promises = uniqueUrls.map((url) => this.loadResource(url));\n await Promise.allSettled(promises);\n }\n\n /**\n * Get a ReadableStream for the given URL. Backed by the shared media cache: concurrent and repeated\n * requests for a URL share one download (memory LRU + OPFS).\n */\n static async getReadableStream(url: string): Promise<ReadableStream<Uint8Array>> {\n return mediaCache.getStream(url);\n }\n\n /**\n * Get an ImageBitmap for the given URL (a new bitmap per call; the bytes are shared and cached).\n */\n static async getImageBitmap(url: string): Promise<ImageBitmap> {\n return mediaCache.getImageBitmap(url);\n }\n\n /**\n * Load a single resource, using cache if available.\n * @param url URL to load\n */\n async loadResource(url: string): Promise<ResourceItem> {\n // If already loading or loaded, return the existing promise or result\n const existingPromise = this.loadingPromises.get(url);\n if (existingPromise) return existingPromise;\n\n if (this.resources.has(url)) {\n const res = this.resources.get(url)!;\n if (res.status === ResourceStatus.COMPLETED) return res;\n }\n\n const loadPromise = (async (): Promise<ResourceItem> => {\n const item: ResourceItem = { url, status: ResourceStatus.LOADING };\n this.resources.set(url, item);\n\n try {\n // Same in-flight download the clips use (preload no longer races clip creation)\n await mediaCache.getBlob(url);\n item.status = ResourceStatus.COMPLETED;\n item.localFile = (await AssetManager.get(url)) ?? undefined;\n return item;\n } catch (err) {\n item.status = ResourceStatus.FAILED;\n item.error = err instanceof Error ? err : new Error(String(err));\n return item;\n } finally {\n this.loadingPromises.delete(url);\n }\n })();\n\n this.loadingPromises.set(url, loadPromise);\n return loadPromise;\n }\n\n /**\n * Resolve a URL to its local OPFS file if available.\n * @param url URL to resolve\n */\n async resolve(url: string): Promise<ReturnType<typeof file> | string> {\n // If it's not a remote URL, return as is\n if (!url || url.startsWith(\"data:\") || url.startsWith(\"blob:\")) {\n return url;\n }\n\n const item = await this.loadResource(url);\n if (item.status === ResourceStatus.COMPLETED && item.localFile) {\n return item.localFile;\n }\n\n return url;\n }\n\n /**\n * Get the status of a specific resource.\n */\n getStatus(url: string): ResourceItem | undefined {\n return this.resources.get(url);\n }\n\n /**\n * Clear instance state (not OPFS cache).\n */\n clear(): void {\n this.resources.clear();\n this.loadingPromises.clear();\n }\n}\n","import { Log } from \"../utils/log\";\nimport { extractPCM4AudioBuffer, ringSliceFloat32Array, getEaseFactor } from \"../utils\";\nimport { BaseClip } from \"./base-clip\";\nimport { DEFAULT_AUDIO_CONF, type IClip, type IPlaybackCapable } from \"./iclip\";\nimport type { AudioJSON } from \"../json-serialization\";\nimport { ResourceManager } from \"../studio/resource-manager\";\n\ninterface IAudioOpts {\n loop?: boolean;\n volume?: number;\n}\n\n/**\n * Audio clip providing audio data for creating and editing audio/video\n *\n * @example\n * // Load audio clip asynchronously\n * const audioClip = await Audio.fromUrl('path/to/audio.mp3', {\n * loop: true,\n * });\n *\n * @example\n * // Traditional approach (for advanced use)\n * new Audio((await fetch('<mp3 url>')).body, {\n * loop: true,\n * }),\n */\nexport class Audio extends BaseClip implements IPlaybackCapable {\n readonly type = \"Audio\";\n static ctx: AudioContext | null = null;\n\n ready: IClip[\"ready\"];\n\n private _meta = {\n // microseconds\n duration: 0,\n width: 0,\n height: 0,\n };\n\n /**\n * Audio metadata\n *\n * ⚠️ Note, these are converted (normalized) metadata, not original audio metadata\n */\n get meta() {\n return {\n ...this._meta,\n sampleRate: DEFAULT_AUDIO_CONF.sampleRate,\n chanCount: 2,\n };\n }\n\n // Use type assertion to avoid type compatibility issues between ArrayBufferLike and ArrayBuffer\n private chan0Buf: Float32Array = new Float32Array();\n private chan1Buf: Float32Array = new Float32Array();\n /**\n * Get complete PCM data from audio clip\n */\n getPCMData(): Float32Array[] {\n return [this.chan0Buf, this.chan1Buf];\n }\n\n private opts;\n\n /**\n * Whether to loop the audio (hybrid JSON structure)\n */\n loop: boolean = false;\n\n /**\n * Load an audio clip from a URL\n * @param url Audio URL\n * @param opts Audio configuration (loop, volume)\n * @returns Promise that resolves to an audio clip\n *\n * @example\n * const audioClip = await Audio.fromUrl('path/to/audio.mp3', {\n * loop: true,\n * volume: 0.8,\n * });\n */\n static async fromUrl(url: string, opts: IAudioOpts = {}): Promise<Audio> {\n const stream = await ResourceManager.getReadableStream(url);\n const clip = new Audio(stream, opts, url);\n // await clip.ready; - Removed for performance\n return clip;\n }\n\n /**\n * Create an Audio instance from a JSON object (fabric.js pattern)\n * @param json The JSON object representing the clip\n * @returns Promise that resolves to an Audio instance\n */\n static async fromObject(json: AudioJSON): Promise<Audio> {\n if (json.type !== \"Audio\") {\n throw new Error(`Expected Audio, got ${json.type}`);\n }\n if (!json.src || json.src.trim() === \"\") {\n throw new Error(\"Audio requires a valid source URL\");\n }\n\n // Support both new flat structure and old options structure\n const options: IAudioOpts = {};\n if (json.loop !== undefined) options.loop = json.loop;\n if (json.volume !== undefined) options.volume = json.volume;\n const clip = await Audio.fromUrl(json.src, options);\n\n BaseClip.deserializeBaseProperties(clip, json);\n\n return clip;\n }\n\n /**\n *\n * @param dataSource Audio file stream\n * @param opts Audio configuration, controls volume and whether to loop\n */\n constructor(\n dataSource: ReadableStream<Uint8Array> | Float32Array[],\n opts: IAudioOpts = {},\n src?: string,\n ) {\n super();\n // Always set src, defaulting to empty string if not provided\n this.src = src !== undefined ? src : \"\";\n this.opts = {\n loop: false,\n volume: 1,\n ...opts,\n };\n this.loop = this.opts.loop ?? false;\n this.volume = this.opts.volume ?? 1;\n\n // Override the ready promise from BaseClip with our initialization\n this.ready = this.init(dataSource).then((_meta_t) => {\n // audio has no width/height, no need to draw\n const clipMeta = {\n width: 0,\n height: 0,\n duration: opts.loop ? Infinity : this._meta.duration,\n };\n // Update rect and duration from meta (BaseClip pattern)\n this.width = this.width === 0 ? clipMeta.width : this.width;\n this.height = this.height === 0 ? clipMeta.height : this.height;\n this.duration = this.duration === 0 ? clipMeta.duration : this.duration;\n // Update display.to when duration changes\n this.display.to = this.display.from + this.duration;\n\n // Update trim.to if not set or exceeds meta duration\n this.trim.to =\n this.trim.to === 0 ? this._meta.duration : Math.min(this.trim.to, this._meta.duration);\n this.trim.from = Math.min(this.trim.from, this.trim.to);\n\n return clipMeta;\n });\n }\n\n private async init(dataSource: ReadableStream<Uint8Array> | Float32Array[]): Promise<void> {\n if (Audio.ctx == null) {\n Audio.ctx = new AudioContext({\n sampleRate: DEFAULT_AUDIO_CONF.sampleRate,\n });\n }\n\n const pcm =\n dataSource instanceof ReadableStream\n ? await parseStream2PCM(dataSource, Audio.ctx)\n : dataSource;\n\n this._meta.duration = (pcm[0].length / DEFAULT_AUDIO_CONF.sampleRate) * 1e6;\n\n this.chan0Buf = pcm[0];\n // Mono to stereo conversion\n this.chan1Buf = pcm[1] ?? this.chan0Buf;\n }\n\n /**\n * Intercept data returned by {@link Audio.tick} method for secondary processing of audio data\n * @param time Time when tick was called\n * @param tickRet Data returned by tick\n *\n */\n tickInterceptor: <T extends Awaited<ReturnType<Audio[\"tick\"]>>>(\n time: number,\n tickRet: T,\n ) => Promise<T> = async (_, tickRet) => tickRet;\n\n // microseconds\n private timestamp = 0;\n private frameOffset = 0;\n /**\n * Return audio PCM data corresponding to the time difference between last and current moments\n *\n * If the difference exceeds 3s or current time is less than last time, reset state\n * @example\n * tick(0) // => []\n * tick(1e6) // => [leftChanPCM(1s), rightChanPCM(1s)]\n *\n */\n async tick(time: number): Promise<{\n audio: Float32Array[];\n state: \"success\" | \"done\";\n }> {\n const trimmedTime = time + this.trim.from;\n const deltaTime = trimmedTime - this.timestamp;\n\n // reset\n if (trimmedTime < this.timestamp || deltaTime > 3e6) {\n this.timestamp = trimmedTime;\n this.frameOffset = Math.ceil((this.timestamp / 1e6) * DEFAULT_AUDIO_CONF.sampleRate);\n return await this.tickInterceptor(time, {\n audio: [new Float32Array(0), new Float32Array(0)],\n state: \"success\",\n });\n }\n\n this.timestamp = trimmedTime;\n const frameCnt = Math.ceil((deltaTime / 1e6) * DEFAULT_AUDIO_CONF.sampleRate);\n const endIdx = this.frameOffset + frameCnt;\n const audio = this.opts.loop\n ? [\n ringSliceFloat32Array(this.chan0Buf, this.frameOffset, endIdx),\n ringSliceFloat32Array(this.chan1Buf, this.frameOffset, endIdx),\n ]\n : [\n this.chan0Buf.slice(this.frameOffset, endIdx),\n this.chan1Buf.slice(this.frameOffset, endIdx),\n ];\n\n const volume = this.effectiveVolume;\n if (volume === 0) {\n for (const chan of audio) chan.fill(0);\n } else if (volume !== 1) {\n for (const chan of audio) {\n for (let i = 0; i < chan.length; i++) {\n chan[i] *= volume;\n }\n }\n }\n\n this.frameOffset = endIdx;\n\n return await this.tickInterceptor(time, { audio, state: \"success\" });\n }\n\n /**\n * Split is handled by core state, not implemented here\n */\n async split(_time: number): Promise<[this, this]> {\n throw new Error(\"Audio.split is not implemented - use core state instead\");\n }\n\n async clone() {\n await this.ready;\n const clip = new Audio(this.getPCMData(), this.opts, this.src) as this;\n await clip.ready;\n // Copy sprite state (animations, opacity, rect, etc.) to the cloned clip\n this.copyStateTo(clip);\n return clip;\n }\n\n /**\n * Destroy instance and release resources\n */\n destroy(): void {\n this.chan0Buf = new Float32Array(0);\n this.chan1Buf = new Float32Array(0);\n Log.info(\"---- audioclip destroy ----\");\n super.destroy();\n }\n\n toJSON(_main: boolean = false): AudioJSON {\n return {\n id: this.id,\n type: \"Audio\",\n name: this.name,\n src: this.src,\n timing: {\n display: {\n from: this.timing.display.from,\n to: this.timing.display.to,\n },\n trim: {\n from: this.timing.trim.from,\n to: this.timing.trim.to,\n },\n duration: this.timing.duration,\n playbackRate: this.timing.playbackRate,\n fadeIn: this.timing.fadeIn,\n fadeOut: this.timing.fadeOut,\n },\n loop: this.loop,\n volume: this.volume,\n locked: this.locked,\n metadata: this.metadata,\n } as AudioJSON;\n }\n\n /**\n * Create HTMLAudioElement for playback\n */\n async createPlaybackElement(): Promise<{\n element: HTMLAudioElement;\n objectUrl?: string;\n }> {\n await this.ready;\n\n if (!this.src || this.src.trim() === \"\") {\n throw new Error(\"Audio requires a source URL for playback\");\n }\n\n // For AudioClip, src is already a URL (from fromUrl or JSON)\n const objectUrl = this.src.startsWith(\"blob:\") ? this.src : undefined;\n const audio = document.createElement(\"audio\");\n\n audio.crossOrigin = \"anonymous\";\n audio.autoplay = false;\n audio.preload = \"auto\";\n audio.loop = this.opts.loop || false;\n audio.src = this.src;\n\n // Wait for audio to be ready\n await new Promise<void>((resolve, reject) => {\n const onLoadedData = () => {\n audio.removeEventListener(\"loadeddata\", onLoadedData);\n audio.removeEventListener(\"error\", onError);\n audio.pause();\n audio.currentTime = 0;\n resolve();\n };\n const onError = () => {\n audio.removeEventListener(\"loadeddata\", onLoadedData);\n audio.removeEventListener(\"error\", onError);\n reject(new Error(\"Failed to load audio\"));\n };\n audio.addEventListener(\"loadeddata\", onLoadedData, { once: true });\n audio.addEventListener(\"error\", onError, { once: true });\n audio.load();\n });\n\n return { element: audio, objectUrl };\n }\n\n async play(element: HTMLVideoElement | HTMLAudioElement, timeSeconds: number): Promise<void> {\n const audio = element as HTMLAudioElement;\n const trimmedTime = timeSeconds + this.trim.from / 1e6;\n // Set time if needed\n if (Math.abs(audio.currentTime - trimmedTime) > 0.1) {\n audio.currentTime = trimmedTime;\n }\n\n if (audio.paused) {\n try {\n await audio.play();\n } catch (_err) {\n // Retry once on failure\n try {\n await audio.play();\n } catch (retryErr) {\n console.warn(\"Failed to play audio:\", retryErr);\n }\n }\n }\n }\n\n pause(element: HTMLVideoElement | HTMLAudioElement): void {\n const audio = element as HTMLAudioElement;\n audio.pause();\n }\n\n async seek(element: HTMLVideoElement | HTMLAudioElement, timeSeconds: number): Promise<void> {\n const audio = element as HTMLAudioElement;\n const trimmedTime = timeSeconds + this.trim.from / 1e6;\n audio.pause();\n audio.currentTime = trimmedTime;\n\n // Wait for seek to complete\n return new Promise<void>((resolve) => {\n if (Math.abs(audio.currentTime - timeSeconds) < 0.01) {\n resolve();\n return;\n }\n\n const onSeeked = () => {\n audio.removeEventListener(\"seeked\", onSeeked);\n resolve();\n };\n\n audio.addEventListener(\"seeked\", onSeeked, { once: true });\n\n // Timeout after 500ms\n setTimeout(() => {\n audio.removeEventListener(\"seeked\", onSeeked);\n resolve();\n }, 500);\n });\n }\n\n syncPlayback(\n element: HTMLVideoElement | HTMLAudioElement,\n isPlaying: boolean,\n timeSeconds: number,\n ): void {\n const audio = element as HTMLAudioElement;\n const clipDuration =\n this.duration && this.duration !== Infinity\n ? this.duration / 1e6\n : (this.display.to - this.display.from) / 1e6;\n const isWithinClip = timeSeconds >= 0 && timeSeconds < clipDuration;\n\n const trimmedTime = timeSeconds + this.trim.from / 1e6;\n // Compute fade volume multiplier for preview\n const clipDurationMs = clipDuration * 1000;\n const timeMs = timeSeconds * 1000;\n let fadeMultiplier = 1.0;\n if (\n this.timing.fadeIn &&\n this.timing.fadeIn.duration > 0 &&\n timeMs < this.timing.fadeIn.duration\n ) {\n fadeMultiplier *= getEaseFactor(\n timeMs / this.timing.fadeIn.duration,\n this.timing.fadeIn.curve,\n );\n }\n if (this.timing.fadeOut && this.timing.fadeOut.duration > 0) {\n const fadeOutStartMs = clipDurationMs - this.timing.fadeOut.duration;\n if (timeMs >= fadeOutStartMs) {\n const t = 1.0 - (timeMs - fadeOutStartMs) / this.timing.fadeOut.duration;\n fadeMultiplier *= getEaseFactor(t, this.timing.fadeOut.curve);\n }\n }\n // Sync volume with fade applied\n audio.volume = Math.max(0, Math.min(1, this.effectiveVolume * fadeMultiplier));\n\n if (isPlaying && isWithinClip) {\n // Should be playing\n if (audio.paused) {\n this.play(audio, timeSeconds).catch(console.warn);\n }\n } else {\n // Should be paused\n if (!audio.paused) {\n audio.pause();\n }\n\n // Update time when paused\n if (isWithinClip && Math.abs(audio.currentTime - trimmedTime) > 0.1) {\n audio.currentTime = trimmedTime;\n }\n }\n }\n\n cleanupPlayback(element: HTMLVideoElement | HTMLAudioElement, objectUrl?: string): void {\n const audio = element as HTMLAudioElement;\n audio.pause();\n audio.removeAttribute(\"src\");\n audio.load();\n\n if (objectUrl && objectUrl.startsWith(\"blob:\")) {\n URL.revokeObjectURL(objectUrl);\n }\n }\n}\n\nasync function parseStream2PCM(\n stream: ReadableStream<Uint8Array>,\n ctx: AudioContext | OfflineAudioContext,\n): Promise<Float32Array[]> {\n const buf = await new Response(stream).arrayBuffer();\n return extractPCM4AudioBuffer(await ctx.decodeAudioData(buf));\n}\n","import { Color, Filter, GlProgram, GpuProgram, UniformGroup } from \"pixi.js\";\n\n// Inline shader code to avoid build issues with unknown module types\nconst fragment = `precision highp float;\nin vec2 vTextureCoord;\nout vec4 finalColor;\n\nuniform sampler2D uTexture;\nuniform float uThickness;\nuniform vec3 uBorderColor;\n\nuniform vec4 uInputClamp;\nuniform vec4 uInputSize;\n\nconst float PI = 3.14159265359;\n\nfloat getOutlineAlpha(vec2 pos) {\n vec2 thickness = vec2(uThickness) / uInputSize.xy;\n float maxAlpha = 0.0;\n\n // Sample 16 directions for smoother outline\n for (int i = 0; i < 16; i++) {\n float angle = float(i) * (PI * 0.125);\n vec2 offset = thickness * vec2(cos(angle), sin(angle));\n vec4 sample = texture(uTexture, clamp(pos + offset, uInputClamp.xy, uInputClamp.zw));\n maxAlpha = max(maxAlpha, sample.a);\n }\n\n return maxAlpha;\n}\n\nvoid main(void) {\n vec4 content = texture(uTexture, vTextureCoord);\n float outlineAlpha = getOutlineAlpha(vTextureCoord) * (1.0 - content.a);\n vec4 outline = vec4(uBorderColor * outlineAlpha, outlineAlpha);\n finalColor = content + outline;\n}\n`;\n\nconst vertex = `in vec2 aPosition;\nout vec2 vTextureCoord;\n\nuniform vec4 uInputSize;\nuniform vec4 uOutputFrame;\nuniform vec4 uOutputTexture;\nvec4 filterVertexPosition( void ) {\n vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;\n position.x = position.x * (2.0 / uOutputTexture.x) - 1.0;\n position.y = position.y * (2.0*uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;\n return vec4(position, 0.0, 1.0);\n}\nvec2 filterTextureCoord( void ) {\n return aPosition * (uOutputFrame.zw * uInputSize.zw);\n}\nvoid main(void) {\n gl_Position = filterVertexPosition();\n vTextureCoord = filterTextureCoord();\n}\n`;\n\nconst source = `struct GlobalFilterUniforms {\n uInputSize:vec4<f32>,\n uInputPixel:vec4<f32>,\n uInputClamp:vec4<f32>,\n uOutputFrame:vec4<f32>,\n uGlobalFrame:vec4<f32>,\n uOutputTexture:vec4<f32>,\n};\n\nstruct OutlineUniforms {\n uThickness:f32,\n uBorderColor:vec3<f32>,\n};\n\n@group(0) @binding(0) var<uniform> gfu: GlobalFilterUniforms;\n@group(0) @binding(1) var uTexture: texture_2d<f32>;\n@group(0) @binding(2) var uSampler : sampler;\n\n@group(1) @binding(0) var<uniform> outlineUniforms : OutlineUniforms;\n\nstruct VSOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) uv : vec2<f32>,\n};\n\nfn filterVertexPosition(aPosition:vec2<f32>) -> vec4<f32>\n{\n var position = aPosition * gfu.uOutputFrame.zw + gfu.uOutputFrame.xy;\n position.x = position.x * (2.0 / gfu.uOutputTexture.x) - 1.0;\n position.y = position.y * (2.0*gfu.uOutputTexture.z / gfu.uOutputTexture.y) - gfu.uOutputTexture.z;\n return vec4(position, 0.0, 1.0);\n}\n\nfn filterTextureCoord(aPosition:vec2<f32>) -> vec2<f32>\n{\n return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);\n}\n\n@vertex\nfn mainVertex(@location(0) aPosition: vec2<f32>) -> VSOutput {\n return VSOutput(filterVertexPosition(aPosition), filterTextureCoord(aPosition));\n}\n\nconst PI: f32 = 3.14159265359;\n\nfn getOutlineAlpha(pos: vec2<f32>) -> f32 {\n let thickness = vec2<f32>(outlineUniforms.uThickness) / gfu.uInputSize.xy;\n var maxAlpha: f32 = 0.0;\n\n // Sample 16 directions for smoother outline\n for (var i: i32 = 0; i < 16; i++) {\n let angle = f32(i) * (PI * 0.125);\n let offset = thickness * vec2<f32>(cos(angle), sin(angle));\n let sample = textureSample(uTexture, uSampler, clamp(pos + offset, gfu.uInputClamp.xy, gfu.uInputClamp.zw));\n maxAlpha = max(maxAlpha, sample.a);\n }\n\n return maxAlpha;\n}\n\n@fragment\nfn mainFragment(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {\n let content = textureSample(uTexture, uSampler, uv);\n let outlineAlpha = getOutlineAlpha(uv) * (1.0 - content.a);\n let outline = vec4<f32>(outlineUniforms.uBorderColor * outlineAlpha, outlineAlpha);\n return content + outline;\n}\n`;\n\nconst defaultOptions = {\n thickness: 1,\n borderColor: 0x000000,\n};\n\n/**\n * OutlineFilter creates outline/stroke effects for text.\n * Replaces default PixiJS stroke option with a custom shader implementation.\n *\n * @example\n * ```js\n * import { OutlineFilter } from './outline-filter';\n *\n * const outlineFilter = new OutlineFilter({\n * thickness: 2.0,\n * borderColor: 0x000000\n * });\n * text.filters = [outlineFilter];\n * ```\n */\nexport class OutlineFilter extends Filter {\n constructor(options: { thickness?: number; borderColor?: number }) {\n const { thickness, borderColor } = {\n ...defaultOptions,\n ...options,\n };\n\n const gpuProgram = GpuProgram.from({\n vertex: {\n source,\n entryPoint: \"mainVertex\",\n },\n fragment: {\n source,\n entryPoint: \"mainFragment\",\n },\n });\n\n const glProgram = GlProgram.from({\n vertex,\n fragment,\n name: \"outline-filter\",\n });\n\n super({\n gpuProgram,\n glProgram,\n padding: thickness * 4,\n resources: {\n outlineUniforms: new UniformGroup({\n uThickness: { value: thickness, type: \"f32\" },\n uBorderColor: { value: new Color(borderColor), type: \"vec3<f32>\" },\n }),\n },\n });\n }\n\n /**\n * The thickness of the outline effect.\n * @default 2.0\n */\n get thickness() {\n const uniforms = this.resources.outlineUniforms.uniforms;\n\n return uniforms.uThickness;\n }\n\n set thickness(value) {\n const uniforms = this.resources.outlineUniforms.uniforms;\n\n uniforms.uThickness = value;\n }\n}\n","import { CanvasTextMetrics } from \"pixi.js\";\n\nexport interface IFont {\n name: string;\n url: string;\n}\n\ninterface LoadedFont {\n face: FontFace;\n url: string;\n}\n\nconst GLOBAL_KEY = Symbol.for(\"agrhub.engine.fontManager\");\n\nexport class FontManager {\n private static instance: FontManager;\n private fonts: Map<string, LoadedFont> = new Map();\n /** In-flight loads, so concurrent addFont calls for one font share a single FontFace load */\n private loading: Map<string, Promise<void>> = new Map();\n private warnedConflicts = new Set<string>();\n\n private constructor() {}\n\n public static getInstance(): FontManager {\n // Shared through globalThis so duplicated bundle copies still use one registry\n const g = globalThis as any;\n if (!FontManager.instance) FontManager.instance = g[GLOBAL_KEY] ?? new FontManager();\n g[GLOBAL_KEY] = FontManager.instance;\n return FontManager.instance;\n }\n\n public async addFont(font: IFont): Promise<void> {\n const existing = this.fonts.get(font.name);\n if (existing) {\n this.warnOnConflict(font, existing.url);\n return;\n }\n const pending = this.loading.get(font.name);\n if (pending) return pending;\n\n const load = (async () => {\n try {\n const fontFace = new FontFace(font.name, `url(${font.url})`);\n const loadedFace = await fontFace.load();\n document.fonts.add(loadedFace);\n this.fonts.set(font.name, { face: loadedFace, url: font.url });\n // Text measured while this family was still loading was measured with the fallback font\n CanvasTextMetrics.clearMetrics();\n } catch (error) {\n console.error(`Failed to load font ${font.name}:`, error);\n // We don't throw here to allow other fonts to load if one fails in a batch\n } finally {\n this.loading.delete(font.name);\n }\n })();\n this.loading.set(font.name, load);\n return load;\n }\n\n /** The first registration of a name wins; a different URL for it is almost always a data bug */\n private warnOnConflict(font: IFont, loadedUrl: string) {\n if (!font.url || font.url === loadedUrl || this.warnedConflicts.has(font.name)) return;\n this.warnedConflicts.add(font.name);\n console.warn(\n `[FontManager] Font \"${font.name}\" is already loaded from ${loadedUrl}; ignoring different URL ${font.url}`,\n );\n }\n\n public async loadFonts(fonts: IFont[]): Promise<void> {\n await Promise.all(fonts.map((font) => this.addFont(font)));\n }\n\n public removeFont(fontName: string): void {\n const loaded = this.fonts.get(fontName);\n if (loaded) {\n document.fonts.delete(loaded.face);\n this.fonts.delete(fontName);\n }\n }\n\n public clear(): void {\n this.fonts.forEach(({ face }) => {\n document.fonts.delete(face);\n });\n this.fonts.clear();\n }\n\n public getLoadedFonts(): string[] {\n return Array.from(this.fonts.keys());\n }\n}\n\nexport const fontManager = FontManager.getInstance();\n","import {\n type Application,\n SplitBitmapText,\n TextStyle,\n RenderTexture,\n Color,\n FillGradient,\n type Texture,\n Container,\n Graphics,\n CanvasTextMetrics,\n BitmapFont,\n Cache,\n} from \"pixi.js\";\nimport gsap from \"gsap\";\nimport { OutlineFilter } from \"../filters/outline-filter\";\nimport { DropShadowFilter } from \"pixi-filters\";\nimport { Log } from \"../utils/log\";\nimport { BaseClip } from \"./base-clip\";\nimport type { IClip } from \"./iclip\";\nimport { parseColor, resolveColor } from \"../utils/color\";\nimport type { BaseSpriteEvents } from \"../sprite/base-sprite\";\nimport { fontManager } from \"../utils/fonts\";\n\n/**\n * Shared style options used by both Text and Caption clips.\n */\nexport interface IBaseTextOpts {\n fontSize?: number;\n fontFamily?: string;\n fontWeight?: string;\n fontStyle?: string;\n fontUrl?: string;\n color?:\n | string\n | number\n | {\n type: \"gradient\";\n x0: number;\n y0: number;\n x1: number;\n y1: number;\n colors: Array<{ ratio: number; color: string | number }>;\n };\n stroke?:\n | string\n | number\n | {\n color: string | number;\n width: number;\n join?: \"miter\" | \"round\" | \"bevel\";\n cap?: \"butt\" | \"round\" | \"square\";\n miterLimit?: number;\n };\n strokeWidth?: number;\n align?: \"left\" | \"center\" | \"right\";\n textAlign?: \"left\" | \"center\" | \"right\";\n verticalAlign?: \"top\" | \"center\" | \"bottom\" | \"underline\" | \"overline\" | \"strikethrough\";\n shadow?: {\n color?: string | number;\n alpha?: number;\n blur?: number;\n offsetX?: number;\n offsetY?: number;\n };\n wordWrapWidth?: number;\n wordWrap?: boolean;\n lineHeight?: number;\n letterSpacing?: number;\n textCase?: \"none\" | \"uppercase\" | \"lowercase\" | \"title\";\n background?: {\n color?: string;\n opacity?: number;\n borderRadius?: number;\n paddingX?: number;\n paddingY?: number;\n };\n}\n\n/** Whether the font for these style options is loaded (system/unknown families count as ready) */\nfunction isFontReady(styleOptions: any): boolean {\n if (typeof document === \"undefined\" || !document.fonts?.check) return true;\n const family = String(styleOptions.fontFamily || \"Roboto\")\n .split(\",\")[0]\n .trim()\n .replace(/^[\"']|[\"']$/g, \"\");\n const size = Number(styleOptions.fontSize) || 30;\n const spec = `${styleOptions.fontStyle || \"normal\"} ${styleOptions.fontWeight || \"normal\"} ${size}px \"${family}\"`;\n try {\n return document.fonts.check(spec);\n } catch {\n return true;\n }\n}\n\nexport function getOrInstallFont(styleOptions: any): string {\n const parts: string[] = [];\n parts.push(styleOptions.fontFamily || \"Roboto\");\n parts.push(String(styleOptions.fontSize || 30));\n parts.push(String(styleOptions.fontWeight || \"normal\"));\n parts.push(String(styleOptions.fontStyle || \"normal\"));\n\n if (styleOptions.fill !== undefined) {\n if (typeof styleOptions.fill === \"number\") {\n parts.push(`f_${styleOptions.fill}`);\n } else {\n parts.push(\"f_obj\");\n }\n }\n\n if (styleOptions.stroke) {\n if (typeof styleOptions.stroke === \"object\") {\n parts.push(\n `s_${styleOptions.stroke.color}_${styleOptions.stroke.width}_${styleOptions.stroke.join || \"\"}`,\n );\n } else {\n parts.push(`s_${styleOptions.stroke}`);\n }\n }\n\n if (styleOptions.dropShadow) {\n parts.push(\n `ds_${styleOptions.dropShadow.color}_${styleOptions.dropShadow.alpha}_${styleOptions.dropShadow.blur}_${styleOptions.dropShadow.angle}_${styleOptions.dropShadow.distance}`,\n );\n }\n\n // A glyph atlas rasterised before the web font finished loading is drawn with the fallback font,\n // and used to be cached under the same name for the rest of the session (captions randomly kept\n // the wrong font/metrics). Key it separately until the font is ready so a correct atlas gets\n // installed once it is.\n if (!isFontReady(styleOptions)) parts.push(\"pending\");\n\n const fontName = \"installed_font_\" + parts.join(\"_\").replace(/[^a-zA-Z0-9_]/g, \"_\");\n\n if (!Cache.has(fontName) && !Cache.has(fontName + \"-bitmap\")) {\n BitmapFont.install({\n name: fontName,\n style: styleOptions,\n });\n }\n\n return fontName;\n}\n\n/**\n * Abstract base class for text-based clips (Text and Caption).\n * Contains all shared PixiJS rendering infrastructure.\n * Subclasses must implement: `get text()`, `get textAlign()`, and `refreshContent()`.\n */\nexport abstract class BaseTextClip<\n TEvents extends BaseSpriteEvents = BaseSpriteEvents,\n> extends BaseClip<TEvents> {\n declare ready: IClip[\"ready\"];\n\n protected _meta = {\n duration: Infinity,\n width: 0,\n height: 0,\n };\n\n get meta() {\n return { ...this._meta };\n }\n\n protected pixiTextContainer: Container | null = null;\n protected wordTexts: SplitBitmapText[] = [];\n protected textStyle!: TextStyle;\n protected textStyleBase!: TextStyle;\n protected renderTexture: RenderTexture | null = null;\n protected outlineFilter: OutlineFilter | null = null;\n protected dropShadowFilter: DropShadowFilter | null = null;\n\n protected _refreshing = false;\n protected _needsRefresh = false;\n /** Settles after the last queued refresh pass (see refreshText) */\n protected _refreshPromise: Promise<void> | null = null;\n protected _spaceWidth = 0;\n /** Per-line boxes from the last layout (read by BlockRevealAnimation) */\n declare public _lineRects?: { x: number; y: number; w: number; h: number }[];\n protected _text: string = \"\";\n\n private externalRenderer: Application[\"renderer\"] | null = null;\n private pixiApp: Application | null = null;\n\n public originalOpts!: IBaseTextOpts;\n\n id: string = `clip_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\n effects: Array<{\n id: string;\n key: string;\n startTime: number;\n duration: number;\n }> = [];\n\n /**\n * The text string to render. Implemented by subclasses.\n */\n abstract get text(): string;\n\n /**\n * Horizontal text alignment. Implemented by subclasses.\n */\n abstract get textAlign(): \"left\" | \"center\" | \"right\";\n\n setRenderer(renderer: Application[\"renderer\"]): void {\n this.externalRenderer = renderer;\n }\n\n protected async getRenderer(): Promise<Application[\"renderer\"]> {\n if (this.externalRenderer != null) return this.externalRenderer;\n if (this.pixiApp?.renderer == null) {\n throw new Error(\"BaseTextClip: No renderer. Provide one via constructor or setRenderer().\");\n }\n return this.pixiApp.renderer;\n }\n\n async getTexture(): Promise<Texture | null> {\n // Never render a container that is mid-rebuild (words removed but not yet laid out again)\n if (this._refreshPromise) await this._refreshPromise.catch(() => {});\n if (this.pixiTextContainer == null || this.renderTexture == null) return null;\n const renderer = await this.getRenderer();\n renderer.render({ container: this.pixiTextContainer, target: this.renderTexture });\n return this.renderTexture;\n }\n\n async tick(_time: number): Promise<{ video: ImageBitmap; state: \"success\" }> {\n await this.ready;\n if (this._refreshPromise) await this._refreshPromise.catch(() => {});\n if (this.pixiTextContainer == null || this.renderTexture == null) {\n throw new Error(\"BaseTextClip not initialized\");\n }\n if (this.renderTexture.width <= 0 || this.renderTexture.height <= 0) {\n throw new Error(\n `Invalid RenderTexture dimensions: ${this.renderTexture.width}x${this.renderTexture.height}`,\n );\n }\n\n const renderer = await this.getRenderer();\n renderer.render({ container: this.pixiTextContainer, target: this.renderTexture });\n\n const source = this.renderTexture.source?.resource?.source;\n let imageBitmap: ImageBitmap;\n\n if (source instanceof HTMLCanvasElement || source instanceof OffscreenCanvas) {\n imageBitmap = await createImageBitmap(source);\n } else {\n const extract = renderer.extract;\n const extractedCanvas = extract.canvas(this.renderTexture);\n if (\n extractedCanvas instanceof HTMLCanvasElement ||\n extractedCanvas instanceof OffscreenCanvas\n ) {\n imageBitmap = await createImageBitmap(extractedCanvas);\n } else {\n throw new Error(\"Unable to extract canvas from render texture\");\n }\n }\n\n return { video: imageBitmap, state: \"success\" };\n }\n\n async split(_time: number): Promise<[this, this]> {\n await this.ready;\n const clone1 = await this.clone();\n const clone2 = await this.clone();\n return [clone1, clone2];\n }\n\n abstract clone(): Promise<this>;\n\n /**\n * Returns true if any animation in the list requires a per-line mask (i.e. has params.mask === true).\n */\n private _hasMaskAnim(anims: any[]): boolean {\n return anims.some((a) => a?.params?.mask === true);\n }\n\n /**\n * Override the animations setter so that when the mask-mode changes\n * (e.g. slideMaskWord → slideByWord or vice-versa), the PIXI scene graph\n * is rebuilt via refreshText(). This removes stale LineMask graphics that\n * would otherwise cause GSAP to access `.y` on null/destroyed nodes.\n */\n override get animations() {\n return super.animations;\n }\n\n override set animations(v: any[]) {\n const wasMask = this._hasMaskAnim(this.animations);\n super.animations = v;\n const isMask = this._hasMaskAnim(this.animations);\n\n // If mask-mode changed, the PIXI scene graph structure is stale – rebuild it.\n if (wasMask !== isMask && this.originalOpts && this.textStyle) {\n void this.refreshText();\n }\n }\n\n override animate(time: number): void {\n super.animate(time, this.pixiTextContainer);\n }\n\n addEffect(effect: { id: string; key: string; startTime: number; duration: number }) {\n this.effects.push(effect);\n }\n\n editEffect(\n effectId: string,\n newEffectData: Partial<{ key: string; startTime: number; duration: number }>,\n ) {\n const effect = this.effects.find((e) => e.id === effectId);\n if (effect) Object.assign(effect, newEffectData);\n }\n\n removeEffect(effectId: string) {\n const idx = this.effects.findIndex((e) => e.id === effectId);\n if (idx !== -1) this.effects.splice(idx, 1);\n }\n\n // ─── Rendering pipeline ──────────────────────────────────────────────────\n\n /**\n * Rebuilds the text layout. Calls made while a rebuild runs are coalesced into one more pass, and\n * every caller's promise resolves only after that final pass — previously they resolved\n * immediately, so \"refresh then emit propsChange\" re-rendered the stale layout.\n */\n protected refreshText(): Promise<void> {\n if (this._refreshing && this._refreshPromise) {\n this._needsRefresh = true;\n return this._refreshPromise;\n }\n this._refreshing = true;\n this._refreshPromise = (async () => {\n try {\n do {\n this._needsRefresh = false;\n await this._doRefreshText();\n } while (this._needsRefresh);\n } finally {\n this._refreshing = false;\n this._refreshPromise = null;\n }\n })();\n return this._refreshPromise;\n }\n\n protected async _doRefreshText(): Promise<void> {\n const snapshotWidth = (this as any)._targetWidth ?? 0;\n const snapshotWordWrap = this.originalOpts.wordWrap;\n const snapshotWordWrapWidth = this.originalOpts.wordWrapWidth;\n const snapshotBackground = this.originalOpts.background;\n\n if (this.originalOpts.fontUrl && this.originalOpts.fontFamily) {\n try {\n await fontManager.addFont({\n name: this.originalOpts.fontFamily,\n url: this.originalOpts.fontUrl,\n });\n } catch (err) {\n console.warn(`[BaseTextClip] Failed to load font:`, err);\n }\n }\n\n if (typeof document !== \"undefined\") {\n await document.fonts.ready;\n }\n\n this._buildTextStyles();\n\n const style = this.textStyle;\n const textToRender = this._applyTextCase(this.text);\n\n if (!this.pixiTextContainer) {\n this.pixiTextContainer = new Container();\n (this.pixiTextContainer as any).__clip = this;\n } else {\n (this.pixiTextContainer as any).__clip = this;\n this.animations.forEach((anim) => {\n if (anim && typeof (anim as any).destroy === \"function\") {\n (anim as any).destroy();\n }\n });\n\n for (const child of this.pixiTextContainer.children) {\n if (child && !child.destroyed) {\n const killAllTweens = (node: any) => {\n if (node) {\n gsap.killTweensOf(node);\n if (node.children) {\n for (const c of node.children) {\n killAllTweens(c);\n }\n }\n }\n };\n killAllTweens(child);\n\n if (child.children) {\n for (const subChild of child.children) {\n if (subChild && subChild.label === \"LineContainer\") {\n subChild.mask = null;\n }\n }\n }\n child.destroy({ children: true });\n }\n }\n this.pixiTextContainer.removeChildren();\n }\n\n const { textOnlyContainer, words } = this._buildWordObjects(textToRender);\n const strokeWidth = this._applyStrokeFilter();\n this._applyShadowFilter(textOnlyContainer);\n\n this.pixiTextContainer.addChild(textOnlyContainer);\n\n const { spaceWidth, measuredTextHeight } = await this._measureSpaceAndHeight();\n this._spaceWidth = spaceWidth;\n\n const lineHeightMultiplier = this.originalOpts.lineHeight ?? 1;\n const fontSize = style.fontSize ?? 40;\n const lineHeight = fontSize * lineHeightMultiplier;\n\n let wrapWidth: number;\n if (snapshotWordWrap) {\n if (snapshotWidth > 0) {\n const liveBgPadX = snapshotBackground?.paddingX ?? 8;\n wrapWidth = Math.max(1, snapshotWidth - liveBgPadX * 2);\n } else {\n wrapWidth = snapshotWordWrapWidth ?? 100;\n }\n } else {\n wrapWidth = 1e5;\n }\n\n const lines = this._breakIntoLines(wrapWidth, lineHeight);\n\n const bgColorOpt = this.originalOpts.background?.color;\n const bgOpacity = this.originalOpts.background?.opacity ?? 1;\n const bgBorderRadius = this.originalOpts.background?.borderRadius ?? 4;\n const bgPadX = this.originalOpts.background?.paddingX ?? 8;\n const bgPadY = this.originalOpts.background?.paddingY ?? 4;\n\n const { containerWidth, containerHeight, contentHeight } = this._calculateDimensions(\n lines,\n measuredTextHeight,\n snapshotWidth,\n snapshotWordWrap,\n snapshotWordWrapWidth,\n snapshotBackground,\n bgPadX,\n bgPadY,\n );\n\n const lineRects = this._positionWords(\n lines,\n containerWidth,\n containerHeight,\n contentHeight,\n measuredTextHeight,\n bgPadX,\n textOnlyContainer,\n );\n\n const decorationGraphics = this._drawDecoration(lines, containerWidth, bgPadX);\n if (decorationGraphics) this.pixiTextContainer.addChild(decorationGraphics);\n\n const bgGraphics = this._buildBackground(lineRects, bgColorOpt, bgOpacity, bgBorderRadius);\n if (bgGraphics) this.pixiTextContainer.addChildAt(bgGraphics, 0);\n this._lineRects = lineRects;\n\n this._createRenderTexture(containerWidth, containerHeight, strokeWidth);\n\n this._meta.width = containerWidth;\n this._meta.height = containerHeight;\n (this as any)._width = containerWidth;\n (this as any)._height = containerHeight;\n\n if (this.duration === 0 && this._meta.duration !== Infinity) {\n this.duration = this._meta.duration;\n this.display.to = this.display.from + this.duration;\n }\n\n this._onAfterRefresh(\n words,\n textOnlyContainer,\n spaceWidth,\n measuredTextHeight,\n lineHeightMultiplier,\n fontSize,\n );\n }\n\n /**\n * Hook called at the end of _doRefreshText. Subclasses can override to run\n * post-layout logic (e.g. populate word cache, apply initial word colors).\n */\n protected _onAfterRefresh(\n _words: string[],\n _textOnlyContainer: Container,\n _spaceWidth: number,\n _measuredTextHeight: number,\n _lineHeightMultiplier: number,\n _fontSize: number,\n ): void {\n // default: no-op\n }\n\n // ─── Style helpers ────────────────────────────────────────────────────────\n\n protected _applyTextCase(text: string): string {\n const textCase = this.originalOpts.textCase;\n if (textCase === \"uppercase\") return text.toUpperCase();\n if (textCase === \"lowercase\") return text.toLowerCase();\n if (textCase === \"title\")\n return text.replace(\n /\\w\\S*/g,\n (txt) => txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase(),\n );\n return text;\n }\n\n protected _buildTextStyles(): { fontName: string; baseFontName: string } {\n const styleOptions = this.createStyleFromOpts(this.originalOpts);\n const {\n wordWrap: _ww,\n wordWrapWidth: _www,\n lineHeight: _lh,\n letterSpacing: _ls,\n fill: _f,\n ...rest\n } = styleOptions;\n const fontName = getOrInstallFont(styleOptions);\n this.textStyle = new TextStyle({ ...styleOptions, fontFamily: fontName });\n const baseFontName = getOrInstallFont(rest);\n this.textStyleBase = new TextStyle({ ...rest, fontFamily: baseFontName });\n return { fontName, baseFontName };\n }\n\n protected _buildWordObjects(textToRender: string): {\n textOnlyContainer: Container;\n words: string[];\n } {\n const words = textToRender.split(/\\s+/).filter((v) => v.length > 0);\n const textOnlyContainer = new Container();\n textOnlyContainer.label = \"TextOnlyContainer\";\n\n this.wordTexts.forEach((w) => {\n if (w && !w.destroyed) {\n w.destroy();\n }\n });\n this.wordTexts = words.map((wordStr) => {\n const wordText = new SplitBitmapText({ text: wordStr, style: this.textStyle });\n textOnlyContainer.addChild(wordText);\n return wordText;\n });\n\n return { textOnlyContainer, words };\n }\n\n protected _applyStrokeFilter(): number {\n const strokeOpt = this.originalOpts.stroke;\n const strokeWidth =\n (strokeOpt !== null && typeof strokeOpt === \"object\" && \"width\" in strokeOpt\n ? strokeOpt.width\n : undefined) ??\n this.originalOpts.strokeWidth ??\n 0;\n const hasStroke = strokeOpt != null && strokeWidth > 0;\n\n if (hasStroke) {\n let strokeColor = 0x000000;\n if (typeof strokeOpt === \"object\" && \"color\" in strokeOpt) {\n const parsed = parseColor(strokeOpt.color);\n if (parsed !== undefined) strokeColor = parsed;\n } else if (typeof strokeOpt === \"string\" || typeof strokeOpt === \"number\") {\n const parsed = parseColor(strokeOpt);\n if (parsed !== undefined) strokeColor = parsed;\n }\n\n if (this.outlineFilter) {\n this.outlineFilter.thickness = strokeWidth;\n this.outlineFilter.padding = strokeWidth * 4;\n const uniforms = this.outlineFilter.resources.outlineUniforms.uniforms;\n uniforms.uBorderColor = new Color(strokeColor);\n } else {\n this.outlineFilter = new OutlineFilter({\n thickness: strokeWidth,\n borderColor: strokeColor,\n });\n }\n\n this.wordTexts.forEach((wordText) => {\n wordText.filters = [this.outlineFilter!];\n });\n } else {\n if (this.outlineFilter) {\n this.wordTexts.forEach((wordText) => {\n wordText.filters = [];\n });\n this.outlineFilter = null;\n }\n }\n\n return hasStroke ? strokeWidth : 0;\n }\n\n protected _applyShadowFilter(textOnlyContainer: Container): void {\n const shadowOpt = this.originalOpts.shadow;\n if (shadowOpt) {\n const offsetX = shadowOpt.offsetX ?? 0;\n const offsetY = shadowOpt.offsetY ?? 0;\n const shadowColor = parseColor(shadowOpt.color ?? \"#000000\");\n const shadowAlpha = shadowOpt.alpha ?? 1;\n const shadowBlur = shadowOpt.blur ?? 4;\n const shadowFilterPadding = Math.ceil(\n shadowBlur * 2.5 + Math.max(Math.abs(offsetX), Math.abs(offsetY)),\n );\n\n if (shadowColor !== undefined) {\n if (this.dropShadowFilter) {\n this.dropShadowFilter.color = shadowColor;\n this.dropShadowFilter.alpha = shadowAlpha;\n this.dropShadowFilter.blur = shadowBlur;\n this.dropShadowFilter.offset = { x: offsetX, y: offsetY };\n this.dropShadowFilter.padding = shadowFilterPadding;\n } else {\n this.dropShadowFilter = new DropShadowFilter({\n color: shadowColor,\n alpha: shadowAlpha,\n blur: shadowBlur,\n offset: { x: offsetX, y: offsetY },\n });\n this.dropShadowFilter.padding = shadowFilterPadding;\n }\n textOnlyContainer.filters = [this.dropShadowFilter];\n }\n } else {\n if (this.dropShadowFilter) {\n textOnlyContainer.filters = [];\n this.dropShadowFilter = null;\n }\n }\n }\n\n protected async _measureSpaceAndHeight(): Promise<{\n spaceWidth: number;\n measuredTextHeight: number;\n }> {\n const spaceFs = this.originalOpts.fontSize || 40;\n const spaceFamily = this.originalOpts.fontFamily || \"Arial\";\n const spaceWeight = String(this.originalOpts.fontWeight || \"normal\");\n const spaceStyle = this.originalOpts.fontStyle || \"normal\";\n const fontSpec = `${spaceStyle} ${spaceWeight} ${spaceFs}px \"${spaceFamily}\"`;\n\n if (typeof document !== \"undefined\") {\n try {\n await document.fonts.load(fontSpec);\n } catch (_) {\n /* ignore */\n }\n }\n\n const spaceMeasureStyle = new TextStyle({\n fontFamily: spaceFamily,\n fontSize: spaceFs,\n fontWeight: spaceWeight as TextStyle[\"fontWeight\"],\n fontStyle: spaceStyle as TextStyle[\"fontStyle\"],\n });\n const metrics = CanvasTextMetrics.measureText(\" \", spaceMeasureStyle);\n\n const textMeasureStyle = new TextStyle({\n fontFamily: spaceFamily,\n fontSize: spaceFs,\n fontWeight: spaceWeight as TextStyle[\"fontWeight\"],\n fontStyle: spaceStyle as TextStyle[\"fontStyle\"],\n });\n const textMeasureMetrics = CanvasTextMetrics.measureText(\"Hg\", textMeasureStyle);\n const fontProps = textMeasureMetrics.fontProperties;\n const measuredTextHeight =\n fontProps && fontProps.ascent > 0 ? Math.ceil(fontProps.ascent + fontProps.descent) : spaceFs;\n\n const tempSpace = new SplitBitmapText({ text: \" \", style: this.textStyleBase });\n const spaceWidth = Math.ceil(\n tempSpace.getLocalBounds().width || tempSpace.width || metrics.width || spaceFs * 0.25,\n );\n tempSpace.destroy();\n\n return { spaceWidth, measuredTextHeight };\n }\n\n protected _breakIntoLines(\n wrapWidth: number,\n lineHeight: number,\n ): { words: SplitBitmapText[]; width: number; height: number }[] {\n const lines: { words: SplitBitmapText[]; width: number; height: number }[] = [];\n let currentLine: SplitBitmapText[] = [];\n let currentLineWidth = 0;\n let currentLineHeight = 0;\n\n this.wordTexts.forEach((wordText) => {\n const bounds = wordText.getLocalBounds();\n const wordWidth = Math.ceil(bounds.width || wordText.width);\n const wordHeight = Math.ceil(bounds.height || wordText.height);\n const projectedWidth =\n currentLineWidth + (currentLineWidth > 0 ? this._spaceWidth : 0) + wordWidth;\n\n if (projectedWidth <= wrapWidth || currentLine.length === 0) {\n currentLine.push(wordText);\n currentLineWidth = projectedWidth;\n currentLineHeight = Math.max(currentLineHeight, wordHeight);\n } else {\n if (currentLine.length > 0) {\n lines.push({\n words: currentLine,\n width: currentLineWidth,\n height: Math.max(currentLineHeight, lineHeight),\n });\n }\n currentLine = [wordText];\n currentLineWidth = wordWidth;\n currentLineHeight = wordHeight;\n }\n });\n\n if (currentLine.length > 0) {\n lines.push({\n words: currentLine,\n width: currentLineWidth,\n height: Math.max(currentLineHeight, lineHeight),\n });\n }\n return lines;\n }\n\n protected _calculateDimensions(\n lines: { words: SplitBitmapText[]; width: number; height: number }[],\n measuredTextHeight: number,\n snapshotWidth: number,\n snapshotWordWrap: boolean | undefined,\n snapshotWordWrapWidth: number | undefined,\n snapshotBackground: IBaseTextOpts[\"background\"],\n bgPadX: number,\n bgPadY: number,\n ): {\n containerWidth: number;\n containerHeight: number;\n contentWidth: number;\n contentHeight: number;\n } {\n const bgLineHeight = measuredTextHeight + bgPadY * 2;\n lines.forEach((line) => {\n line.height = Math.max(line.height, bgLineHeight);\n });\n\n let maxLineWidth = 0;\n let totalHeight = 0;\n lines.forEach((line) => {\n maxLineWidth = Math.max(maxLineWidth, line.width);\n totalHeight += line.height;\n });\n\n let contentWidth = maxLineWidth;\n if (snapshotWordWrap && snapshotWidth > 0) {\n const snapshotBgPadX = snapshotBackground?.paddingX ?? 8;\n const innerTargetWidth = snapshotWidth - snapshotBgPadX * 2;\n contentWidth = Math.max(contentWidth, innerTargetWidth);\n } else if (snapshotWordWrap && snapshotWordWrapWidth != null && snapshotWordWrapWidth > 0) {\n contentWidth = Math.max(contentWidth, snapshotWordWrapWidth);\n }\n const contentHeight = totalHeight;\n\n contentWidth += bgPadX * 2;\n\n const effectiveWidth = snapshotWidth > 0 ? snapshotWidth : ((this as any)._width as number);\n const isAutoWidth = effectiveWidth === 0;\n const isAutoHeight = !(this as any)._explicitHeight || this.height === 0;\n\n const containerWidth = isAutoWidth ? contentWidth : Math.max(contentWidth, effectiveWidth);\n const containerHeight = isAutoHeight\n ? contentHeight\n : Math.max(contentHeight, this.height || 0);\n\n return { containerWidth, containerHeight, contentWidth, contentHeight };\n }\n\n protected _positionWords(\n lines: { words: SplitBitmapText[]; width: number; height: number }[],\n containerWidth: number,\n containerHeight: number,\n contentHeight: number,\n measuredTextHeight: number,\n bgPadX: number,\n textOnlyContainer: Container,\n ): { x: number; y: number; w: number; h: number }[] {\n const finalVAlign = (this.originalOpts as any).verticalAlign || \"top\";\n let startY = 0;\n if (finalVAlign === \"center\") startY = (containerHeight - contentHeight) / 2;\n else if (finalVAlign === \"bottom\") startY = containerHeight - contentHeight;\n\n let currentY = startY;\n const lineRects: { x: number; y: number; w: number; h: number }[] = [];\n\n lines.forEach((line) => {\n let currentX = 0;\n const finalAlign = this.textAlign;\n if (finalAlign === \"center\") {\n currentX = (containerWidth - line.width) / 2;\n } else if (finalAlign === \"right\") {\n currentX = containerWidth - line.width - bgPadX * 2;\n } else {\n currentX = bgPadX;\n }\n\n const lineXStart = currentX;\n\n // Group words of this line into a LineContainer\n const lineContainer = new Container();\n lineContainer.label = \"LineContainer\";\n lineContainer.x = 0;\n lineContainer.y = 0;\n\n const hasMaskAnimation = this.animations.some((anim: any) => anim?.params?.mask === true);\n\n if (hasMaskAnimation) {\n // Draw a rectangular Graphics mask matching the line coordinates\n const mask = new Graphics();\n mask.label = \"LineMask\";\n // Mask vertically using currentY and line.height.\n // Horizontally, span the entire width of the container.\n mask.rect(0, currentY, containerWidth, line.height);\n mask.fill(0xffffff);\n lineContainer.mask = mask;\n\n // Add mask to textOnlyContainer\n textOnlyContainer.addChild(mask);\n }\n\n // Add lineContainer to textOnlyContainer\n textOnlyContainer.addChild(lineContainer);\n\n line.words.forEach((wordText, wordIndex) => {\n wordText.x = Math.round(currentX);\n wordText.y = Math.round(currentY + (line.height - measuredTextHeight) / 2 - 9);\n currentX +=\n (wordText.getLocalBounds().width || wordText.width) +\n (wordIndex < line.words.length - 1 ? this._spaceWidth : 0);\n\n // Move the word into the LineContainer\n lineContainer.addChild(wordText);\n });\n\n lineRects.push({\n x: lineXStart - bgPadX,\n y: currentY,\n w: line.width + bgPadX * 2,\n h: line.height,\n });\n\n currentY += line.height;\n });\n\n return lineRects;\n }\n\n protected _drawDecoration(\n lines: { words: SplitBitmapText[]; width: number; height: number }[],\n containerWidth: number,\n bgPadX: number,\n ): Graphics | null {\n const decoration =\n (this.originalOpts as any).textDecoration || (this.originalOpts as any).verticalAlign;\n if (\n !decoration ||\n decoration === \"none\" ||\n ![\"underline\", \"overline\", \"strikethrough\", \"line-through\"].includes(decoration)\n ) {\n return null;\n }\n\n const style = this.textStyle;\n const fontSize = style.fontSize ?? 40;\n const finalDecoration = decoration === \"strikethrough\" ? \"line-through\" : decoration;\n const lineThickness = Math.max(1, fontSize / 12);\n\n let lineColor = 0xffffff;\n if (typeof style.fill === \"number\") lineColor = style.fill;\n\n const graphics = new Graphics();\n let currentY = 0;\n\n lines.forEach((line) => {\n let lineXStart = bgPadX;\n const finalAlign = this.textAlign;\n if (finalAlign === \"center\") lineXStart = (containerWidth - line.width) / 2;\n else if (finalAlign === \"right\") lineXStart = containerWidth - line.width - bgPadX * 2;\n\n let yOffset = 0;\n if (finalDecoration === \"underline\") yOffset = line.height;\n else if (finalDecoration === \"line-through\") yOffset = line.height / 2;\n\n graphics.rect(lineXStart, currentY + yOffset, line.width, lineThickness);\n graphics.fill(lineColor);\n currentY += line.height;\n });\n\n return graphics;\n }\n\n protected _buildBackground(\n lineRects: { x: number; y: number; w: number; h: number }[],\n bgColorOpt: string | undefined,\n bgOpacity: number,\n bgBorderRadius: number,\n ): Graphics | null {\n if (!lineRects.length || !bgColorOpt || bgColorOpt === \"transparent\" || bgColorOpt === \"\") {\n return null;\n }\n const parsedBgColor = parseColor(bgColorOpt);\n const bgGraphics = new Graphics();\n this.drawRoundedMultilinePath(\n bgGraphics,\n lineRects,\n bgBorderRadius,\n parsedBgColor ?? 0x000000,\n bgOpacity,\n );\n return bgGraphics;\n }\n\n protected _createRenderTexture(\n containerWidth: number,\n containerHeight: number,\n strokeWidth: number,\n ): void {\n const ANIM_PAD = 300;\n const filterPadding = strokeWidth > 0 ? strokeWidth * 2.1 : 0;\n let shadowPadding = 0;\n if (this.dropShadowFilter) {\n const shadowBlur = this.dropShadowFilter.blur ?? 0;\n const shadowOffset = this.dropShadowFilter.offset;\n const shadowDistance = shadowOffset\n ? Math.sqrt(shadowOffset.x ** 2 + shadowOffset.y ** 2)\n : 0;\n shadowPadding = shadowBlur + shadowDistance;\n }\n const totalPad = ANIM_PAD + filterPadding + shadowPadding;\n const paddedWidth = containerWidth + totalPad * 2;\n const paddedHeight = containerHeight + totalPad * 2;\n\n if (this.pixiTextContainer) {\n this.pixiTextContainer.x = totalPad;\n this.pixiTextContainer.y = totalPad;\n }\n\n if (this.renderTexture) this.renderTexture.destroy();\n this.renderTexture = RenderTexture.create({ width: paddedWidth, height: paddedHeight });\n this.renderTexturePadding = totalPad;\n }\n\n protected _normalizeStyleOpts(opts: Partial<IBaseTextOpts>): Partial<IBaseTextOpts> {\n let processed = { ...opts } as any;\n\n if (processed.style) {\n processed = { ...processed, ...processed.style };\n delete processed.style;\n }\n if (processed.fill !== undefined) {\n processed.color = processed.fill;\n delete processed.fill;\n }\n if (processed.dropShadow !== undefined) {\n processed.shadow = processed.dropShadow;\n delete processed.dropShadow;\n }\n if (processed.textAlign !== undefined) {\n processed.align = processed.textAlign;\n delete processed.textAlign;\n }\n\n const hasUnderline = processed.underline;\n const hasOverline = processed.overline;\n const hasLinethrough = processed.linethrough;\n if (hasUnderline !== undefined || hasOverline !== undefined || hasLinethrough !== undefined) {\n if (hasUnderline) processed.textDecoration = \"underline\";\n else if (hasOverline) processed.textDecoration = \"overline\";\n else if (hasLinethrough) processed.textDecoration = \"line-through\";\n else processed.textDecoration = \"none\";\n delete processed.underline;\n delete processed.overline;\n delete processed.linethrough;\n }\n\n return processed as Partial<IBaseTextOpts>;\n }\n\n protected _cloneColorOpts(colorToNumber: (c: any) => number | undefined): IBaseTextOpts[\"color\"] {\n const originalOpts = this.originalOpts;\n if (\n originalOpts.color &&\n typeof originalOpts.color === \"object\" &&\n \"type\" in originalOpts.color &&\n originalOpts.color.type === \"gradient\"\n ) {\n return originalOpts.color;\n }\n return colorToNumber(this.textStyle.fill) ?? 0xffffff;\n }\n\n protected _cloneStrokeOpts(colorToNumber: (c: any) => number | undefined): {\n stroke: IBaseTextOpts[\"stroke\"];\n strokeWidth: number;\n } {\n const originalOpts = this.originalOpts;\n const style = this.textStyle;\n if (\n originalOpts.stroke &&\n typeof originalOpts.stroke === \"object\" &&\n \"color\" in originalOpts.stroke\n ) {\n return { stroke: originalOpts.stroke, strokeWidth: 0 };\n }\n const strokeColor = colorToNumber(style.stroke);\n const strokeWidth = originalOpts.strokeWidth ?? (style as any).strokeThickness ?? 0;\n return { stroke: strokeColor !== undefined ? strokeColor : undefined, strokeWidth };\n }\n\n protected _cloneShadowOpts(\n colorToNumber: (c: any) => number | undefined,\n ): IBaseTextOpts[\"shadow\"] | undefined {\n const originalOpts = this.originalOpts;\n const style = this.textStyle;\n if (originalOpts.shadow) return originalOpts.shadow;\n if (style.dropShadow) {\n const ds = style.dropShadow;\n const shadowColor = colorToNumber(ds.color);\n if (shadowColor !== undefined) {\n const angle = ds.angle ?? 0;\n const distance = ds.distance ?? 0;\n return {\n color: shadowColor,\n alpha: ds.alpha,\n blur: ds.blur,\n offsetX: Math.cos(angle) * distance,\n offsetY: Math.sin(angle) * distance,\n };\n }\n }\n return undefined;\n }\n\n protected createStyleFromOpts(opts: IBaseTextOpts): any {\n const fontSize = opts.fontSize ?? 40;\n const lineHeightMultiplier = opts.lineHeight ?? 1;\n\n const styleOptions: any = {\n fontSize,\n fontFamily: opts.fontFamily ?? \"Roboto\",\n fontWeight: (opts.fontWeight as any) ?? \"normal\",\n fontStyle: opts.fontStyle ?? \"normal\",\n align: opts.align ?? \"left\",\n wordWrap: opts.wordWrap ?? false,\n wordWrapWidth: opts.wordWrapWidth ?? 100,\n lineHeight: fontSize * lineHeightMultiplier,\n letterSpacing: opts.letterSpacing ?? 0,\n };\n\n const colorOpt = opts.color ?? \"#ffffff\";\n if (\n colorOpt &&\n typeof colorOpt === \"object\" &&\n \"type\" in colorOpt &&\n colorOpt.type === \"gradient\"\n ) {\n const gradient = new FillGradient(colorOpt.x0, colorOpt.y0, colorOpt.x1, colorOpt.y1);\n colorOpt.colors.forEach(({ ratio, color }) => {\n const colorNumber = typeof color === \"number\" ? color : (parseColor(color) ?? 0xffffff);\n gradient.addColorStop(ratio, colorNumber);\n });\n styleOptions.fill = { fill: gradient };\n } else {\n const { color: fillColor, alpha: fillAlpha } = resolveColor(colorOpt as string);\n styleOptions.fill = fillColor;\n if (fillAlpha < 1) {\n styleOptions.fillAlpha = fillAlpha;\n }\n }\n\n return styleOptions;\n }\n\n protected drawRoundedMultilinePath(\n graphics: Graphics,\n rects: { x: number; y: number; w: number; h: number }[],\n radius: number,\n color: number,\n alpha: number = 1,\n ) {\n if (rects.length === 0) return;\n\n const threshold = Math.max(radius * 0.8, 15);\n let changed = true;\n let passes = 0;\n while (changed && passes < 5) {\n changed = false;\n passes++;\n for (let i = 0; i < rects.length; i++) {\n for (let j = i + 1; j < rects.length; j++) {\n const r1Right = rects[i].x + rects[i].w;\n const r2Right = rects[j].x + rects[j].w;\n if (Math.abs(r1Right - r2Right) > 0.1 && Math.abs(r1Right - r2Right) < threshold) {\n const maxR = Math.max(r1Right, r2Right);\n rects[i].w = maxR - rects[i].x;\n rects[j].w = maxR - rects[j].x;\n changed = true;\n }\n if (\n Math.abs(rects[i].x - rects[j].x) > 0.1 &&\n Math.abs(rects[i].x - rects[j].x) < threshold\n ) {\n const minX = Math.min(rects[i].x, rects[j].x);\n rects[i].w += rects[i].x - minX;\n rects[i].x = minX;\n rects[j].w += rects[j].x - minX;\n rects[j].x = minX;\n changed = true;\n }\n }\n }\n }\n\n const points: { x: number; y: number }[] = [];\n points.push({ x: rects[0].x, y: rects[0].y });\n points.push({ x: rects[0].x + rects[0].w, y: rects[0].y });\n\n for (let i = 0; i < rects.length - 1; i++) {\n const r1 = rects[i];\n const r2 = rects[i + 1];\n if (Math.abs(r1.x + r1.w - (r2.x + r2.w)) > 0.1) {\n const midY = (r1.y + r1.h + r2.y) / 2;\n points.push({ x: r1.x + r1.w, y: midY });\n points.push({ x: r2.x + r2.w, y: midY });\n }\n }\n\n points.push({\n x: rects[rects.length - 1].x + rects[rects.length - 1].w,\n y: rects[rects.length - 1].y + rects[rects.length - 1].h,\n });\n points.push({\n x: rects[rects.length - 1].x,\n y: rects[rects.length - 1].y + rects[rects.length - 1].h,\n });\n\n for (let i = rects.length - 1; i > 0; i--) {\n const r1 = rects[i];\n const r2 = rects[i - 1];\n if (Math.abs(r1.x - r2.x) > 0.1) {\n const midY = (r1.y + r2.y + r2.h) / 2;\n points.push({ x: r1.x, y: midY });\n points.push({ x: r2.x, y: midY });\n }\n }\n\n graphics.clear();\n const pLast = points[points.length - 1];\n const pFirst = points[0];\n graphics.moveTo((pLast.x + pFirst.x) / 2, (pLast.y + pFirst.y) / 2);\n for (let i = 0; i < points.length; i++) {\n const p1 = points[i];\n const p2 = points[(i + 1) % points.length];\n graphics.arcTo(p1.x, p1.y, (p1.x + p2.x) / 2, (p1.y + p2.y) / 2, radius);\n }\n graphics.fill({ color, alpha });\n }\n\n destroy(): void {\n if (this.destroyed) return;\n Log.info(`${this.constructor.name} destroy`);\n\n try {\n if (this.pixiTextContainer != null && !this.pixiTextContainer.destroyed) {\n for (const child of this.pixiTextContainer.children) {\n if (child && !child.destroyed) {\n const killAllTweens = (node: any) => {\n if (node) {\n gsap.killTweensOf(node);\n if (node.children) {\n for (const c of node.children) {\n killAllTweens(c);\n }\n }\n }\n };\n killAllTweens(child);\n\n if (child.children) {\n for (const subChild of child.children) {\n if (subChild && subChild.label === \"LineContainer\") {\n subChild.mask = null;\n }\n }\n }\n }\n }\n this.pixiTextContainer.destroy({ children: true });\n }\n } catch (_) {\n /* ignore */\n } finally {\n this.pixiTextContainer = null;\n }\n\n try {\n if (this.renderTexture != null && !(this.renderTexture as any).destroyed) {\n this.renderTexture.destroy(true);\n }\n } catch (_) {\n /* ignore */\n } finally {\n this.renderTexture = null;\n }\n\n this.externalRenderer = null;\n\n if (this.pixiApp != null) {\n try {\n const anyApp = this.pixiApp as any;\n if (anyApp.destroyed !== true && anyApp.renderer != null) {\n this.pixiApp.destroy(true, { children: true, texture: true });\n }\n } catch (_) {\n /* ignore */\n } finally {\n this.pixiApp = null;\n }\n }\n\n super.destroy();\n }\n\n toJSON(main: boolean = false): any {\n const base = super.toJSON(main);\n const { chromaKey: _chromaKey, colorAdjustment: _colorAdjustment, ...rest } = base;\n return rest;\n }\n}\n","import { type Application, Container, Graphics, SplitBitmapText } from \"pixi.js\";\nimport { redistributeCaptionWords, type ICaptionWord } from \"@agrhub/core\";\nimport type { IClip } from \"./iclip\";\nimport type { ClipContext } from \"./clip-registry\";\nimport type {\n CaptionJSON,\n TextStyleJSON,\n CaptionDataJSON,\n CaptionPositioningJSON,\n} from \"../json-serialization\";\nimport { isTransparent, parseColor, resolveColor } from \"../utils/color\";\nimport { BaseClip } from \"./base-clip\";\nimport { BaseTextClip, type IBaseTextOpts } from \"./base-text-clip\";\nimport type { BaseSpriteEvents } from \"../sprite/base-sprite\";\nimport type { ICaptionWordAnimation } from \"../json-serialization\";\n\nexport type { ICaptionWord, ICaptionWordAnimation };\n\n/** Style applied to a single word state (active / future / keyword) */\nexport interface ICaptionWordStyle {\n color?: string;\n border?: { color?: string; width?: number };\n background?: string;\n}\n\n/** Caption color configuration */\nexport interface ICaptionColors {\n /** Currently spoken word — null/undefined to disable */\n active?: ICaptionWordStyle | null;\n /** Upcoming / future words — null/undefined to disable */\n future?: ICaptionWordStyle | null;\n /** Keyword words (isKeyWord=true) — null/undefined to disable */\n keyword?: { color?: string; preserveAfterSpoken?: boolean } | null;\n}\n\n/**\n * Options for constructing a Caption clip.\n *\n * Color model:\n * - `style.color` → appeared (already-spoken) words\n * - `caption.colors.active` → currently spoken word (color + background + border)\n * - `caption.colors.future` → upcoming words (color + border)\n * - `caption.colors.keyword` → isKeyWord=true override\n */\nexport interface ICaptionOpts extends IBaseTextOpts {\n words?: ICaptionWord[];\n wordAnimation?: ICaptionWordAnimation;\n wordsPerLine?: \"single\" | \"multiple\";\n mediaId?: string;\n videoWidth?: number;\n videoHeight?: number;\n bottomOffset?: number;\n /** Nested caption data (flattened into opts on construction) */\n caption?: {\n words?: ICaptionWord[];\n colors?: ICaptionColors;\n wordAnimation?: ICaptionWordAnimation;\n positioning?: {\n videoWidth?: number;\n videoHeight?: number;\n bottomOffset?: number;\n };\n };\n /** Internal: skip initial auto-positioning when restoring from JSON */\n initialLayoutApplied?: boolean;\n /** Resolved color objects (flat access after construction) */\n activeStyle?: ICaptionWordStyle;\n futureStyle?: ICaptionWordStyle;\n keywordColor?: string;\n keywordPreserveAfterSpoken?: boolean;\n}\n\nexport interface ICaptionEvents extends BaseSpriteEvents {\n propsChange: Partial<\n {\n left: number;\n top: number;\n width: number;\n height: number;\n angle: number;\n text: string;\n style: any;\n } & ICaptionOpts\n >;\n}\n\ninterface CaptionSplitBitmapText extends SplitBitmapText {\n segmentIndex: number;\n}\n\nexport class Caption extends BaseTextClip<ICaptionEvents> implements IClip {\n readonly type = \"Caption\";\n declare ready: IClip[\"ready\"];\n\n private _lastTickTime = 0;\n protected _isWidthConstrained = false;\n\n private _words: ICaptionWord[] = [];\n\n declare public originalOpts: ICaptionOpts;\n\n // ── Resolved color state (refreshed by _syncOpts) ──────────────────────────\n private _activeStyle: ICaptionWordStyle = {};\n private _futureStyle: ICaptionWordStyle = {};\n private _keywordColor = \"\";\n private _keywordPreserveAfterSpoken = false;\n private _wordAnimation: ICaptionWordAnimation = { type: \"scale\", application: \"none\", value: 1 };\n private _wordsPerLine: \"single\" | \"multiple\" = \"multiple\";\n protected _videoWidth = 1280;\n protected _videoHeight = 720;\n protected _bottomOffset = 100;\n\n // ─── text / textAlign ─────────────────────────────────────────────────────\n\n get text(): string {\n return this._text;\n }\n\n set text(v: string) {\n if (this._text === v) return;\n const prev = this._text;\n this._text = v;\n if (prev !== \"\" && this._words.length > 0) {\n this._words = redistributeCaptionWords(v, this._words, this.duration || 5e6);\n }\n if (this.originalOpts && this.textStyle) {\n this.refreshText().then(() => this.emit(\"propsChange\", { text: v }));\n }\n }\n\n get textAlign(): \"left\" | \"center\" | \"right\" {\n return this.originalOpts?.align ?? \"left\";\n }\n\n // ─── caption getter/setter (bridge integration) ───────────────────────────\n\n get caption(): ICaptionOpts[\"caption\"] {\n const opts = this.originalOpts ?? {};\n return {\n words: this._words,\n colors: {\n active: opts.activeStyle,\n future: opts.futureStyle,\n keyword: opts.keywordColor\n ? { color: opts.keywordColor, preserveAfterSpoken: opts.keywordPreserveAfterSpoken }\n : undefined,\n },\n wordAnimation: opts.wordAnimation,\n positioning: {\n videoWidth: this._videoWidth,\n videoHeight: this._videoHeight,\n bottomOffset: this._bottomOffset,\n },\n };\n }\n\n set caption(v: ICaptionOpts[\"caption\"]) {\n if (!v) return;\n if (v.words) {\n this._words = v.words;\n if (this.originalOpts) this.originalOpts.words = v.words;\n }\n if (v.colors) {\n if (\"active\" in v.colors) this.originalOpts.activeStyle = v.colors.active ?? undefined;\n if (\"future\" in v.colors) this.originalOpts.futureStyle = v.colors.future ?? undefined;\n if (\"keyword\" in v.colors) {\n if (v.colors.keyword != null) {\n this.originalOpts.keywordColor = v.colors.keyword.color;\n this.originalOpts.keywordPreserveAfterSpoken = v.colors.keyword.preserveAfterSpoken;\n } else {\n this.originalOpts.keywordColor = undefined;\n this.originalOpts.keywordPreserveAfterSpoken = undefined;\n }\n }\n }\n if (v.wordAnimation !== undefined) this.originalOpts.wordAnimation = v.wordAnimation;\n if (v.positioning) {\n if (v.positioning.videoWidth !== undefined) this._videoWidth = v.positioning.videoWidth;\n if (v.positioning.videoHeight !== undefined) this._videoHeight = v.positioning.videoHeight;\n if (v.positioning.bottomOffset !== undefined) this._bottomOffset = v.positioning.bottomOffset;\n }\n this._syncOpts();\n }\n\n // ─── Words ────────────────────────────────────────────────────────────────\n\n get words(): ICaptionWord[] {\n return this._words;\n }\n\n set words(v: ICaptionWord[]) {\n this._words = v;\n if (this.originalOpts) this.originalOpts.words = v;\n this.refreshText().then(() => this.emit(\"propsChange\", { style: this.style }));\n }\n\n get mediaId(): string | undefined {\n return this.originalOpts?.mediaId;\n }\n\n set mediaId(v: string | undefined) {\n if (this.originalOpts) this.originalOpts.mediaId = v;\n }\n\n get wordsPerLine(): \"single\" | \"multiple\" {\n return this._wordsPerLine;\n }\n\n set wordsPerLine(v: \"single\" | \"multiple\") {\n this._wordsPerLine = v;\n if (this.originalOpts) this.originalOpts.wordsPerLine = v;\n this.refreshText();\n }\n\n // ─── Style proxy ──────────────────────────────────────────────────────────\n\n override get style(): any {\n const opts = this.originalOpts ?? {};\n return {\n fontSize: opts.fontSize,\n fontFamily: opts.fontFamily,\n fontWeight: opts.fontWeight,\n fontStyle: opts.fontStyle,\n color: opts.color,\n align: opts.align,\n stroke: opts.stroke,\n shadow: opts.shadow,\n wordWrap: opts.wordWrap,\n wordWrapWidth: opts.wordWrapWidth,\n lineHeight: opts.lineHeight,\n letterSpacing: opts.letterSpacing,\n textCase: opts.textCase,\n };\n }\n\n override set style(opts: Partial<ICaptionOpts>) {\n this.updateStyle(opts);\n }\n\n async updateStyle(opts: Partial<ICaptionOpts>): Promise<void> {\n const processed = this._normalizeStyleOpts(opts) as Partial<ICaptionOpts>;\n this.originalOpts = { ...this.originalOpts, ...processed };\n if (processed.words !== undefined) this._words = processed.words;\n this._syncOpts();\n this._buildTextStyles();\n await this.refreshText();\n this.emit(\"propsChange\", opts);\n }\n\n // ─── Width / height overrides ─────────────────────────────────────────────\n\n override get width(): number {\n return (this as any)._width;\n }\n\n override set width(v: number) {\n if (Math.abs(this.width - v) < 0.1) return;\n (this as any)._width = v;\n if (v > 0) this._isWidthConstrained = true;\n this.refreshText();\n }\n\n override get height(): number {\n return (this as any)._height;\n }\n\n override set height(v: number) {\n if (Math.abs(this.height - v) < 0.1) return;\n (this as any)._height = v;\n this.refreshText();\n }\n\n // ─── animate override ─────────────────────────────────────────────────────\n\n override animate(time: number): void {\n this._lastTickTime = time;\n super.animate(time);\n }\n\n // ─── Constructor ──────────────────────────────────────────────────────────\n\n constructor(text: string, opts: ICaptionOpts = {}, renderer?: Application[\"renderer\"]) {\n super();\n this.originalOpts = { ...opts };\n this._text = text;\n if (renderer) this.setRenderer(renderer);\n\n // Flatten nested caption structure\n if (opts.caption) {\n if (opts.caption.words) this._words = opts.caption.words;\n const c = opts.caption;\n if (c.colors && \"active\" in c.colors)\n this.originalOpts.activeStyle = c.colors.active ?? undefined;\n if (c.colors && \"future\" in c.colors)\n this.originalOpts.futureStyle = c.colors.future ?? undefined;\n if (c.colors && \"keyword\" in c.colors) {\n if (c.colors.keyword != null) {\n this.originalOpts.keywordColor = c.colors.keyword.color;\n this.originalOpts.keywordPreserveAfterSpoken = c.colors.keyword.preserveAfterSpoken;\n } else {\n this.originalOpts.keywordColor = undefined;\n this.originalOpts.keywordPreserveAfterSpoken = undefined;\n }\n }\n if (c.wordAnimation !== undefined) this.originalOpts.wordAnimation = c.wordAnimation;\n if (c.positioning?.videoWidth !== undefined)\n this.originalOpts.videoWidth = c.positioning.videoWidth;\n if (c.positioning?.videoHeight !== undefined)\n this.originalOpts.videoHeight = c.positioning.videoHeight;\n if (c.positioning?.bottomOffset !== undefined)\n this.originalOpts.bottomOffset = c.positioning.bottomOffset;\n }\n if (opts.words) this._words = opts.words;\n void opts.initialLayoutApplied;\n\n this._syncOpts();\n this._buildTextStyles();\n\n this.ready = (async () => {\n await this.refreshText();\n return { ...this.meta };\n })();\n }\n\n protected override createStyleFromOpts(opts: any): any {\n const style = super.createStyleFromOpts(opts);\n style.fill = 0xffffff;\n return style;\n }\n\n private _syncOpts(): void {\n const o = this.originalOpts ?? {};\n this._activeStyle = o.activeStyle ?? {};\n this._futureStyle = o.futureStyle ?? {};\n this._keywordColor = o.keywordColor ?? \"\";\n this._keywordPreserveAfterSpoken = o.keywordPreserveAfterSpoken ?? false;\n this._wordAnimation = o.wordAnimation ?? { type: \"scale\", application: \"none\", value: 1 };\n this._wordsPerLine = o.wordsPerLine ?? \"multiple\";\n this._videoWidth = o.videoWidth ?? 1280;\n this._videoHeight = o.videoHeight ?? 720;\n this._bottomOffset = o.bottomOffset ?? 100;\n }\n\n // ─── Rendering overrides ──────────────────────────────────────────────────\n\n protected override _buildWordObjects(textToRender: string): {\n textOnlyContainer: Container;\n words: string[];\n } {\n const textOnlyContainer = new Container();\n textOnlyContainer.label = \"TextOnlyContainer\";\n this.wordTexts.forEach((w) => w.destroy());\n this.wordTexts = [];\n\n const allWords: string[] = [];\n const textCase = this.originalOpts?.textCase;\n\n const makeWordText = (wordStr: string, segmentIndex: number): CaptionSplitBitmapText => {\n const wt = new SplitBitmapText({\n text: wordStr,\n style: this.textStyle,\n }) as unknown as CaptionSplitBitmapText;\n wt.segmentIndex = segmentIndex;\n const colorOpt = this.originalOpts?.color;\n const fillToParse =\n typeof colorOpt === \"object\" && colorOpt !== null && \"type\" in colorOpt\n ? 0xffffff\n : (colorOpt as string | number);\n const initialColor = parseColor(fillToParse);\n wt.tint = initialColor ?? 0xffffff;\n return wt;\n };\n\n if (this._words.length > 0) {\n this._words.forEach((segment, segmentIndex) => {\n let segText = segment.text || \"\";\n if (textCase === \"uppercase\") segText = segText.toUpperCase();\n else if (textCase === \"lowercase\") segText = segText.toLowerCase();\n else if (textCase === \"title\")\n segText = segText.replace(\n /\\w\\S*/g,\n (t) => t.charAt(0).toUpperCase() + t.substring(1).toLowerCase(),\n );\n\n const subWords = segText.split(/\\s+/).filter((v) => v.length > 0);\n subWords.forEach((wordStr) => {\n const wt = makeWordText(wordStr, segmentIndex);\n textOnlyContainer.addChild(wt);\n this.wordTexts.push(wt as unknown as SplitBitmapText);\n allWords.push(wordStr);\n });\n });\n } else {\n textToRender\n .split(/\\s+/)\n .filter((v) => v.length > 0)\n .forEach((wordStr, idx) => {\n const wt = makeWordText(wordStr, idx);\n textOnlyContainer.addChild(wt);\n this.wordTexts.push(wt as unknown as SplitBitmapText);\n allWords.push(wordStr);\n });\n }\n\n return { textOnlyContainer, words: allWords };\n }\n\n protected override _onAfterRefresh(): void {\n this.updateState(this._lastTickTime);\n }\n\n override async tick(time: number): Promise<{ video: ImageBitmap; state: \"success\" }> {\n this.updateState(time);\n return super.tick(time);\n }\n\n // ─── updateState ─────────────────────────────────────────────────────────\n\n updateState(currentTimeUs: number): void {\n this._lastTickTime = currentTimeUs;\n const currentTimeMs = currentTimeUs / 1000;\n\n (this.wordTexts as unknown as CaptionSplitBitmapText[]).forEach((wordText) => {\n const word = this._words[wordText.segmentIndex];\n if (!word) return;\n\n wordText.scale.set(1, 1);\n\n const isActive = currentTimeMs >= word.from && currentTimeMs < word.to;\n const hasBeenActive = currentTimeMs >= word.to;\n const isFuture = !isActive && !hasBeenActive;\n\n // ── Word animation ────────────────────────────────────────────────────\n const wa = this._wordAnimation;\n let animationFactor = 0;\n let shouldApply = false;\n\n if (wa && wa.application !== \"none\") {\n if (wa.application === \"active\" && isActive) shouldApply = true;\n else if (wa.application === \"keyword\" && word.isKeyWord) shouldApply = true;\n\n if (shouldApply) {\n if (wa.mode === \"dynamic\" && isActive) {\n const dur = word.to - word.from;\n if (dur > 0) {\n const progress = Math.max(0, Math.min(1, (currentTimeMs - word.from) / dur));\n animationFactor = wa.value < 1 ? progress : Math.sin(progress * Math.PI);\n } else {\n animationFactor = 1;\n }\n } else {\n animationFactor = 1;\n }\n\n if (wa.type === \"scale\") {\n const scale =\n wa.value < 1 && wa.mode === \"dynamic\" && isActive\n ? wa.value + (1 - wa.value) * animationFactor\n : 1 + (wa.value - 1) * animationFactor;\n wordText.scale.set(scale, scale);\n }\n }\n }\n\n // ── Colour resolution ─────────────────────────────────────────────────\n // Priority: keyword (if active/preserve) > active/future > appeared (style.color)\n let textColor = 0xffffff;\n let textAlpha = 1;\n\n const isKeywordWithColor = word.isKeyWord && !isTransparent(this._keywordColor);\n\n if (isKeywordWithColor && (isActive || (hasBeenActive && this._keywordPreserveAfterSpoken))) {\n ({ color: textColor, alpha: textAlpha } = resolveColor(this._keywordColor, 0xffff00));\n } else if (isActive) {\n const c = this._activeStyle.color;\n if (c && !isTransparent(c)) {\n ({ color: textColor, alpha: textAlpha } = resolveColor(c, 0xffffff));\n } else {\n // no active color set → default to white (style.color is for appeared words)\n textColor = 0xffffff;\n textAlpha = 1;\n }\n } else if (isFuture) {\n const c = this._futureStyle.color;\n if (c && !isTransparent(c)) {\n ({ color: textColor, alpha: textAlpha } = resolveColor(c, 0xffffff));\n } else {\n // no future color set → default to white (style.color is for appeared words)\n textColor = 0xffffff;\n textAlpha = 1;\n }\n } else {\n // appeared — use style.color\n const colorOpt = this.originalOpts?.color;\n const fill =\n typeof colorOpt === \"object\" && colorOpt !== null && \"type\" in colorOpt\n ? 0xffffff\n : (colorOpt as string | number);\n ({ color: textColor, alpha: textAlpha } = resolveColor(fill as any));\n }\n\n if (shouldApply && wa?.type === \"opacity\") {\n const opacityFactor =\n wa.value < 1 && wa.mode === \"dynamic\" && isActive\n ? wa.value + (1 - wa.value) * animationFactor\n : 1 + (wa.value - 1) * animationFactor;\n textAlpha *= opacityFactor;\n }\n\n // Apply colour directly to the word container (same mechanism as initial tint setup).\n // This ensures caption-specific colours (active/future/keyword) always win over\n // the base style.color that _buildWordObjects bakes into wt.tint at construction.\n wordText.tint = textColor;\n const applyAlpha = (obj: any) => {\n if (\n obj.label === \"bgRect\" ||\n obj.label === \"tiktokBackground\" ||\n obj.label === \"containerBackground\" ||\n (typeof obj.label === \"string\" && obj.label.startsWith(\"bgRect_\"))\n )\n return;\n if (\"alpha\" in obj) obj.alpha = textAlpha;\n if (obj.children) obj.children.forEach(applyAlpha);\n };\n wordText.children.forEach(applyAlpha);\n\n // ── Background pill (active word) ─────────────────────────────────────\n const parentContainer = wordText.parent as Container | null;\n const bgLabel = `bgRect_${wordText.segmentIndex}`;\n const existingBg = parentContainer\n ? (parentContainer.getChildByLabel(bgLabel) as Graphics | null)\n : null;\n\n const activeBgColor = isActive ? (this._activeStyle.background ?? \"\") : \"\";\n const hasActiveBg =\n isActive && !!activeBgColor && !isTransparent(activeBgColor) && activeBgColor !== \"none\";\n\n if (hasActiveBg && parentContainer) {\n const { color: bgColor, alpha: bgAlpha } = resolveColor(activeBgColor, 0xffa500);\n const padding = 15;\n const paddingX = 40;\n\n const sx = wordText.scale.x;\n const visualW = (wordText.getLocalBounds().width || wordText.width) * sx;\n const visualH = (this.originalOpts?.fontSize ?? 40) * sx;\n const pillarX = wordText.x;\n const pillarY = wordText.y + 9;\n\n const bg = existingBg ?? new Graphics();\n bg.label = bgLabel;\n bg.clear();\n bg.roundRect(\n pillarX - paddingX / 2,\n pillarY - padding / 2,\n visualW + paddingX,\n visualH + padding,\n 10,\n );\n bg.fill({ color: bgColor, alpha: bgAlpha });\n bg.tint = 0xffffff;\n\n if (!existingBg) parentContainer.addChildAt(bg, 0);\n } else {\n if (existingBg && parentContainer) {\n parentContainer.removeChild(existingBg);\n existingBg.destroy();\n }\n }\n });\n }\n\n // ─── clone / toJSON / fromObject ──────────────────────────────────────────\n\n async clone(): Promise<this> {\n await this.ready;\n const newClip = new Caption(this.text, {\n ...this.originalOpts,\n words: [...this._words],\n }) as this;\n this.copyStateTo(newClip);\n newClip.id = this.id;\n newClip.effects = [...this.effects];\n return newClip;\n }\n\n toJSON(main: boolean = false): CaptionJSON {\n const base = super.toJSON(main);\n const opts = this.originalOpts ?? {};\n\n const style: TextStyleJSON = {};\n if (opts.fontSize !== undefined) style.fontSize = opts.fontSize;\n if (opts.fontFamily !== undefined) style.fontFamily = opts.fontFamily;\n if (opts.fontWeight !== undefined) style.fontWeight = opts.fontWeight as any;\n if (opts.fontStyle !== undefined) style.fontStyle = opts.fontStyle;\n if (opts.color !== undefined) style.color = opts.color as any;\n if (opts.align !== undefined) style.align = opts.align;\n if (opts.textCase !== undefined) style.textCase = opts.textCase;\n if (opts.fontUrl !== undefined) style.fontUrl = opts.fontUrl;\n if (opts.verticalAlign !== undefined) style.verticalAlign = opts.verticalAlign as any;\n if (opts.wordWrapWidth !== undefined) style.wordWrapWidth = opts.wordWrapWidth;\n if (opts.wordWrap !== undefined) style.wordWrap = opts.wordWrap;\n if (opts.wordAnimation !== undefined) style.wordAnimation = opts.wordAnimation;\n\n if (opts.stroke) {\n if (typeof opts.stroke === \"object\") {\n style.stroke = { color: opts.stroke.color, width: opts.stroke.width };\n } else {\n style.stroke = { color: opts.stroke, width: opts.strokeWidth ?? 0 };\n }\n }\n if (opts.shadow) {\n style.shadow = {\n color: (opts.shadow.color ?? \"#000000\") as string,\n alpha: opts.shadow.alpha ?? 0.5,\n blur: opts.shadow.blur ?? 4,\n offsetX: opts.shadow.offsetX ?? 0,\n offsetY: opts.shadow.offsetY ?? 0,\n };\n }\n\n const caption: CaptionDataJSON = {};\n if (this._words.length > 0) caption.words = this._words;\n\n const colors: CaptionDataJSON[\"colors\"] = {};\n if (opts.activeStyle) colors.active = opts.activeStyle;\n if (opts.futureStyle) colors.future = opts.futureStyle;\n if (opts.keywordColor) {\n colors.keyword = {\n color: opts.keywordColor,\n preserveAfterSpoken: opts.keywordPreserveAfterSpoken,\n };\n }\n if (Object.keys(colors).length > 0) caption.colors = colors;\n\n if (opts.wordAnimation !== undefined) caption.wordAnimation = opts.wordAnimation;\n\n const positioning: CaptionPositioningJSON = {};\n if (opts.videoWidth !== undefined) positioning.videoWidth = opts.videoWidth;\n if (opts.videoHeight !== undefined) positioning.videoHeight = opts.videoHeight;\n if (opts.bottomOffset !== undefined) positioning.bottomOffset = opts.bottomOffset;\n if (Object.keys(positioning).length > 0) caption.positioning = positioning;\n\n return {\n ...base,\n type: \"Caption\",\n text: this.text,\n style,\n caption: Object.keys(caption).length > 0 ? caption : undefined,\n id: this.id,\n effects: this.effects,\n mediaId: this.mediaId,\n wordsPerLine: this.wordsPerLine,\n fontUrl: opts.fontUrl,\n } as CaptionJSON;\n }\n\n static async fromObject(json: CaptionJSON, context?: ClipContext): Promise<Caption> {\n if (json.type !== \"Caption\") throw new Error(`Expected Caption, got ${json.type}`);\n\n const trackCaptionConfig = context?.captionConfig;\n const text = json.text || \"\";\n // Merge track config style as base, clip-level style overrides on top\n const style = { ...(trackCaptionConfig?.style ?? {}), ...(json.style ?? {}) };\n const captionOpts: ICaptionOpts = {};\n\n if (style.fontSize !== undefined) captionOpts.fontSize = style.fontSize;\n if (style.fontFamily !== undefined) captionOpts.fontFamily = style.fontFamily;\n if (style.fontWeight !== undefined) captionOpts.fontWeight = style.fontWeight as any;\n if (style.fontStyle !== undefined) captionOpts.fontStyle = style.fontStyle as any;\n if (style.color !== undefined) captionOpts.color = style.color;\n else if ((style as any).fill !== undefined) captionOpts.color = (style as any).fill;\n if (style.align !== undefined) captionOpts.align = style.align;\n if (style.textCase !== undefined) captionOpts.textCase = style.textCase;\n if (style.verticalAlign !== undefined) captionOpts.verticalAlign = style.verticalAlign as any;\n if (style.wordWrapWidth !== undefined) captionOpts.wordWrapWidth = style.wordWrapWidth;\n if (style.wordWrap !== undefined) captionOpts.wordWrap = style.wordWrap;\n if (style.wordAnimation !== undefined) captionOpts.wordAnimation = style.wordAnimation;\n if (style.fontUrl !== undefined) captionOpts.fontUrl = style.fontUrl;\n else if (json.fontUrl !== undefined) captionOpts.fontUrl = json.fontUrl;\n const isSet = (v: unknown) => v !== undefined && v !== null && v !== \"\";\n if (isSet(style.wordsPerLine)) captionOpts.wordsPerLine = style.wordsPerLine;\n else if (isSet(json.wordsPerLine)) captionOpts.wordsPerLine = json.wordsPerLine;\n\n // Previously dropped, so presets with a background box / custom spacing / clip-level case never\n // rendered them. Accept both the nested `background` object and the flat app fields.\n const anyStyle = style as any;\n if (anyStyle.lineHeight !== undefined) captionOpts.lineHeight = anyStyle.lineHeight;\n if (anyStyle.letterSpacing !== undefined) captionOpts.letterSpacing = anyStyle.letterSpacing;\n if (captionOpts.textCase === undefined && (json as any).textCase !== undefined) {\n captionOpts.textCase = (json as any).textCase;\n }\n if (anyStyle.background && typeof anyStyle.background === \"object\") {\n captionOpts.background = { ...anyStyle.background };\n } else if (isSet(anyStyle.backgroundColor) && anyStyle.backgroundColor !== \"transparent\") {\n const padding = Number(anyStyle.padding);\n captionOpts.background = {\n color: anyStyle.backgroundColor,\n opacity: anyStyle.backgroundOpacity ?? 0.7,\n borderRadius: anyStyle.borderRadius ?? 8,\n paddingX: Number.isFinite(padding) ? padding : 10,\n paddingY: Number.isFinite(padding) ? Math.round(padding * 0.6) : 6,\n };\n }\n\n if (json.mediaId) captionOpts.mediaId = json.mediaId;\n\n if (style.stroke) {\n captionOpts.stroke = style.stroke.color;\n captionOpts.strokeWidth = style.stroke.width;\n }\n if (style.shadow) {\n captionOpts.shadow = {\n color: style.shadow.color,\n alpha: style.shadow.alpha,\n blur: style.shadow.blur,\n offsetX: style.shadow.offsetX ?? 0,\n offsetY: style.shadow.offsetY ?? 0,\n };\n }\n\n if (json.caption) {\n // Merge track config as fallback for colors and positioning\n const resolvedCaption = { ...json.caption } as ICaptionOpts[\"caption\"];\n if (!resolvedCaption!.colors && trackCaptionConfig?.colors) {\n resolvedCaption!.colors = trackCaptionConfig.colors;\n }\n if (!resolvedCaption!.positioning && trackCaptionConfig?.positioning) {\n resolvedCaption!.positioning = trackCaptionConfig.positioning;\n }\n captionOpts.caption = resolvedCaption;\n if (json.caption.wordAnimation) captionOpts.wordAnimation = json.caption.wordAnimation;\n } else if (trackCaptionConfig) {\n // No caption object on clip at all — build one from track config\n captionOpts.caption = {\n colors: trackCaptionConfig.colors,\n positioning: trackCaptionConfig.positioning,\n };\n }\n\n captionOpts.initialLayoutApplied = true;\n\n const clip = new Caption(text, captionOpts);\n BaseClip.deserializeBaseProperties(clip, json);\n // An empty string (\"not set\") must not override the track's value\n clip.wordsPerLine = (isSet(json.wordsPerLine) ? json.wordsPerLine : undefined) ?? trackCaptionConfig?.wordsPerLine ?? \"multiple\";\n if (json.effects) clip.effects = json.effects;\n await clip.ready;\n return clip;\n }\n\n override getVisibleHandles(): Array<\n \"tl\" | \"tr\" | \"bl\" | \"br\" | \"ml\" | \"mr\" | \"mt\" | \"mb\" | \"rot\"\n > {\n return [\"mr\", \"mb\", \"br\", \"rot\"];\n }\n}\n","import { Texture } from \"pixi.js\";\nimport { Log } from \"../utils/log\";\nimport { decodeImg } from \"../utils\";\nimport { BaseClip } from \"./base-clip\";\nimport { type IClip } from \"./iclip\";\nimport { type ClipJSON, type ImageJSON } from \"../json-serialization\";\nimport { ResourceManager } from \"../studio/resource-manager\";\n\ntype AnimateImgType = \"avif\" | \"webp\" | \"png\" | \"gif\";\n\n/**\n * Image clip supporting animated images\n *\n * Ordinary text can be converted to image clip using {@link renderTxt2ImgBitmap}\n *\n * @example\n * // Load from URL using PixiJS Assets (optimized for Studio)\n * const imgClip = await Image.fromUrl('path/to/image.png');\n *\n * @example\n * // Traditional approach (for Compositor/export)\n * new Image((await fetch('<img url>')).body);\n *\n * @example\n * new Image(\n * await renderTxt2ImgBitmap(\n * 'Watermark',\n * `font-size:40px; color: white; text-shadow: 2px 2px 6px red;`,\n * )\n * )\n *\n */\nexport class Image extends BaseClip implements IClip {\n readonly type = \"Image\";\n ready: IClip[\"ready\"];\n\n private _meta = {\n // microseconds\n duration: 0,\n width: 0,\n height: 0,\n };\n\n /**\n * ⚠️ Static images have duration of Infinity\n *\n * When wrapping with Sprite, you need to set its duration to a finite number\n *\n */\n get meta() {\n return { ...this._meta };\n }\n\n private img: ImageBitmap | null = null;\n\n // Optimized: Store PixiJS Texture for direct use in Studio\n // This avoids ImageBitmap → Canvas → Texture conversion\n private pixiTexture: Texture | null = null;\n\n private frames: VideoFrame[] = [];\n\n /**\n * Unique identifier for this clip instance\n */\n id: string = `clip_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\n /**\n * Array of effects to be applied to this clip\n * Each effect specifies key, startTime, duration, and optional targets\n */\n effects: Array<{\n id: string;\n key: string;\n startTime: number;\n duration: number;\n }> = [];\n\n getVisibleHandles(): Array<\"tl\" | \"tr\" | \"bl\" | \"br\" | \"ml\" | \"mr\" | \"mt\" | \"mb\" | \"rot\"> {\n return [\"tl\", \"tr\", \"bl\", \"br\", \"rot\"];\n }\n\n /**\n * Load an image clip from a URL using PixiJS Assets\n * This is optimized for Studio as it uses Texture directly\n *\n * @param url Image URL\n * @param src Optional source identifier for serialization\n * @returns Promise that resolves to an Image instance\n *\n * @example\n * const imgClip = await Image.fromUrl('path/to/image.png');\n */\n static async fromUrl(url: string, src?: string): Promise<Image> {\n let texture: Texture | null = null;\n let imageBitmap: ImageBitmap | undefined;\n\n // Optimized handling for blob URLs to avoid PixiJS warnings about unknown extensions\n if (url.startsWith(\"blob:\")) {\n try {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to fetch image: ${response.status} ${response.statusText}`);\n }\n const blob = await response.blob();\n imageBitmap = await createImageBitmap(blob);\n // Create texture from bitmap for Studio optimization\n try {\n texture = Texture.from(imageBitmap);\n } catch (e) {\n Log.warn(\"Failed to create Pixi texture from bitmap:\", e);\n }\n } catch (err) {\n Log.error(`Failed to load blob image from ${url}`, err);\n throw err;\n }\n } else {\n imageBitmap = await ResourceManager.getImageBitmap(url);\n }\n\n if (!imageBitmap) {\n throw new Error(`Failed to load image from ${url}`);\n }\n\n const clip = new Image(imageBitmap, src || url);\n // Store the Texture for optimized preview rendering\n if (texture) {\n clip.pixiTexture = texture;\n }\n\n return clip;\n }\n\n /**\n * Get the PixiJS Texture (if available)\n * This is used for optimized rendering in Studio\n */\n getTexture(): Texture | null {\n return this.pixiTexture;\n }\n\n /**\n * Static images can be initialized using stream or ImageBitmap\n *\n * Animated images need to use VideoFrame[] or provide image type\n */\n constructor(\n dataSource:\n | ReadableStream\n | ImageBitmap\n | VideoFrame[]\n | { type: `image/${AnimateImgType}`; stream: ReadableStream },\n src?: string,\n ) {\n super();\n // Always set src, defaulting to empty string if not provided\n this.src = src !== undefined ? src : \"\";\n const initWithImgBitmap = (imgBitmap: ImageBitmap) => {\n this.img = imgBitmap;\n this._meta.width = imgBitmap.width;\n this._meta.height = imgBitmap.height;\n this._meta.duration = Infinity;\n const meta = { ...this._meta };\n // Update rect and duration from meta (BaseClip pattern)\n // Only set duration from meta if it hasn't been explicitly set (still 0)\n // and if meta.duration is not Infinity (to allow user to set finite duration)\n this.width = this.width === 0 ? meta.width : this.width;\n this.height = this.height === 0 ? meta.height : this.height;\n if (this.duration === 0 && meta.duration !== Infinity) {\n this.duration = meta.duration;\n // Update display.to when duration changes\n this.display.to = this.display.from + this.duration;\n }\n return meta;\n };\n\n if (dataSource instanceof ReadableStream) {\n this.ready = new Response(dataSource)\n .blob()\n .then((data) => createImageBitmap(data))\n .then(initWithImgBitmap);\n } else if (dataSource instanceof ImageBitmap) {\n this.ready = Promise.resolve(initWithImgBitmap(dataSource));\n } else if (Array.isArray(dataSource) && dataSource.every((it) => it instanceof VideoFrame)) {\n this.frames = dataSource;\n const frame = this.frames[0];\n if (frame == null) throw Error(\"The frame count must be greater than 0\");\n this._meta = {\n width: frame.displayWidth,\n height: frame.displayHeight,\n duration: this.frames.reduce((acc, cur) => acc + (cur.duration ?? 0), 0),\n };\n const meta = { ...this._meta, duration: Infinity };\n // Update rect and duration from meta (BaseClip pattern)\n // Only set duration from meta if it hasn't been explicitly set (still 0)\n // and if meta.duration is not Infinity (to allow user to set finite duration)\n this.width = this.width === 0 ? meta.width : this.width;\n this.height = this.height === 0 ? meta.height : this.height;\n if (this.duration === 0 && meta.duration !== Infinity) {\n this.duration = meta.duration;\n // Update display.to when duration changes\n this.display.to = this.display.from + this.duration;\n }\n this.ready = Promise.resolve(meta);\n } else if (\"type\" in dataSource) {\n this.ready = this.initAnimateImg(dataSource.stream, dataSource.type).then(() => {\n const meta = {\n width: this._meta.width,\n height: this._meta.height,\n duration: Infinity,\n };\n // Update rect and time from meta (BaseClip pattern)\n // Only set duration from meta if it hasn't been explicitly set (still 0)\n // and if meta.duration is not Infinity (to allow user to set finite duration)\n this.width = this.width === 0 ? meta.width : this.width;\n this.height = this.height === 0 ? meta.height : this.height;\n if (this.duration === 0 && meta.duration !== Infinity) {\n this.duration = meta.duration;\n // Update display.to when duration changes\n this.display.to = this.display.from + this.duration;\n }\n return meta;\n });\n } else {\n throw Error(\"Illegal arguments\");\n }\n }\n\n private async initAnimateImg(stream: ReadableStream, type: `image/${AnimateImgType}`) {\n this.frames = await decodeImg(stream, type);\n const firstVf = this.frames[0];\n if (firstVf == null) throw Error(\"No frame available in gif\");\n\n this._meta = {\n duration: this.frames.reduce((acc, cur) => acc + (cur.duration ?? 0), 0),\n width: firstVf.codedWidth,\n height: firstVf.codedHeight,\n };\n Log.info(\"Image ready:\", this._meta);\n }\n\n tickInterceptor: <T extends Awaited<ReturnType<Image[\"tick\"]>>>(\n time: number,\n tickRet: T,\n ) => Promise<T> = async (_, tickRet) => tickRet;\n\n async tick(time: number): Promise<{\n video: ImageBitmap | VideoFrame;\n state: \"success\";\n }> {\n if (this.img != null) {\n return await this.tickInterceptor(time, {\n video: await createImageBitmap(this.img),\n state: \"success\",\n });\n }\n const targetTime = time % this._meta.duration;\n return await this.tickInterceptor(time, {\n video: (\n this.frames.find(\n (f) => targetTime >= f.timestamp && targetTime <= f.timestamp + (f.duration ?? 0),\n ) ?? this.frames[0]\n ).clone(),\n state: \"success\",\n });\n }\n\n async split(time: number) {\n await this.ready;\n if (this.img != null) {\n return [\n new Image(await createImageBitmap(this.img), this.src),\n new Image(await createImageBitmap(this.img), this.src),\n ] as [this, this];\n }\n let hitIdx = -1;\n for (let i = 0; i < this.frames.length; i++) {\n const vf = this.frames[i];\n if (time > vf.timestamp) continue;\n hitIdx = i;\n break;\n }\n if (hitIdx === -1) throw Error(\"Not found frame by time\");\n const preSlice = this.frames.slice(0, hitIdx).map((vf) => new VideoFrame(vf));\n const postSlice = this.frames.slice(hitIdx).map(\n (vf) =>\n new VideoFrame(vf, {\n timestamp: vf.timestamp - time,\n }),\n );\n return [new Image(preSlice, this.src), new Image(postSlice, this.src)] as [this, this];\n }\n\n async clone() {\n await this.ready;\n const data =\n this.img == null ? this.frames.map((vf) => vf.clone()) : await createImageBitmap(this.img);\n const newClip = new Image(data, this.src) as this;\n newClip.tickInterceptor = this.tickInterceptor;\n // Copy sprite state (animations, opacity, rect, etc.) to the cloned clip\n this.copyStateTo(newClip);\n // Copy id and effects\n newClip.id = this.id;\n newClip.effects = [...this.effects];\n newClip.transition = this.transition;\n return newClip;\n }\n\n // Effects\n addEffect(effect: { id: string; key: string; startTime: number; duration: number }) {\n this.effects.push(effect);\n }\n\n editEffect(\n effectId: string,\n newEffectData: Partial<{\n key: string;\n startTime: number;\n duration: number;\n }>,\n ) {\n const effect = this.effects.find((e) => e.id === effectId);\n if (effect) {\n Object.assign(effect, newEffectData);\n }\n }\n\n removeEffect(effectId: string) {\n const effectIndex = this.effects.findIndex((e) => e.id === effectId);\n if (effectIndex !== -1) {\n this.effects.splice(effectIndex, 1);\n }\n }\n\n destroy(): void {\n Log.info(\"Image destroy\");\n this.img?.close();\n this.frames.forEach((f) => f.close());\n // Note: We don't destroy the Texture here as it's managed by Assets cache\n // If you need to explicitly unload, use Assets.unload()\n this.pixiTexture = null;\n super.destroy();\n }\n\n toJSON(main: boolean = false): ImageJSON {\n const base = super.toJSON(main);\n return {\n ...base,\n type: \"Image\",\n id: this.id,\n effects: this.effects,\n } as ImageJSON;\n }\n\n /**\n * Create an Image instance from a JSON object (fabric.js pattern)\n * @param json The JSON object representing the clip\n * @returns Promise that resolves to an Image instance\n */\n static async fromObject(json: ClipJSON): Promise<Image> {\n if (json.type !== \"Image\") {\n throw new Error(`Expected Image, got ${json.type}`);\n }\n if (!json.src || json.src.trim() === \"\") {\n throw new Error(\n \"Image requires a valid source URL. Generated clips (like text-to-image) cannot be loaded from JSON without their source data.\",\n );\n }\n\n let clip: Image;\n try {\n const bitmap = await ResourceManager.getImageBitmap(json.src);\n clip = new Image(bitmap, json.src);\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"could not be decoded\")) {\n throw new Error(\n `Failed to decode image from ${json.src}. The image may be decoded, in an unsupported format, or there may be CORS issues.`,\n );\n }\n throw error;\n }\n\n BaseClip.deserializeBaseProperties(clip, json);\n\n if (json.effects) {\n clip.effects = json.effects;\n }\n\n return clip;\n }\n}\n","import {\n mp4box,\n AudioTrackOpts,\n ESDSBoxParser,\n MP4ArrayBuffer,\n MP4File,\n MP4Info,\n MP4Sample,\n TrakBoxParser,\n VideoTrackOpts,\n} from \"wrapbox\";\nimport { file } from \"opfs-tools\";\n\ninterface ExtractedConfig {\n videoTrackConf?: VideoTrackOpts;\n videoDecoderConf?: VideoDecoderConfig;\n audioTrackConf?: AudioTrackOpts;\n audioDecoderConf?: AudioDecoderConfig;\n}\n\n/**\n * Extracts video and audio configurations from an MP4 file.\n */\nexport function extractFileConfig(file: MP4File, info: MP4Info): ExtractedConfig {\n const result: ExtractedConfig = {};\n\n const vTrack = info.videoTracks[0];\n if (vTrack != null) {\n const videoDesc = parseVideoCodecDesc(file.getTrackById(vTrack.id))?.buffer;\n const codecInfo = getCodecInfo(vTrack.codec);\n\n if (codecInfo) {\n result.videoTrackConf = {\n timescale: vTrack.timescale,\n duration: vTrack.duration,\n width: vTrack.video.width,\n height: vTrack.video.height,\n brands: info.brands,\n type: codecInfo.type,\n [codecInfo.descKey]: videoDesc,\n } as VideoTrackOpts;\n }\n\n result.videoDecoderConf = {\n codec: vTrack.codec,\n codedHeight: vTrack.video.height,\n codedWidth: vTrack.video.width,\n description: videoDesc as ArrayBuffer,\n };\n }\n\n const aTrack = info.audioTracks[0];\n if (aTrack != null) {\n const esdsBox = getESDSBoxFromMP4File(file);\n const audioInfo = esdsBox ? parseAudioInfoFromESDSBox(esdsBox) : {};\n\n result.audioTrackConf = {\n timescale: aTrack.timescale,\n samplerate: audioInfo.sampleRate ?? aTrack.audio.sample_rate,\n channel_count: audioInfo.numberOfChannels ?? aTrack.audio.channel_count,\n hdlr: \"soun\",\n type: aTrack.codec.startsWith(\"mp4a\") ? \"mp4a\" : aTrack.codec,\n description: esdsBox,\n };\n\n // For Opus tracks there is no ESDS box, so use the track codec directly.\n // For mp4a tracks, prefer the track-level codec string (e.g. mp4a.40.29) over the\n // ESDS-derived value because the parser does not handle object-type escape codes.\n const resolvedCodec = aTrack.codec.startsWith(\"mp4a\")\n ? aTrack.codec\n : (audioInfo.codec ??\n (aTrack.codec === \"Opus\" || aTrack.codec === \"opus\" ? \"opus\" : aTrack.codec));\n\n result.audioDecoderConf = {\n codec: resolvedCodec,\n numberOfChannels: audioInfo.numberOfChannels ?? aTrack.audio.channel_count,\n sampleRate: audioInfo.sampleRate ?? aTrack.audio.sample_rate,\n ...(audioInfo.description ? { description: audioInfo.description } : {}),\n };\n }\n\n return result;\n}\n\nfunction getCodecInfo(codec: string): { descKey: string; type: string } | null {\n if (codec.startsWith(\"avc1\")) return { descKey: \"avcDecoderConfigRecord\", type: \"avc1\" };\n if (codec.startsWith(\"hvc1\")) return { descKey: \"hevcDecoderConfigRecord\", type: \"hvc1\" };\n return null;\n}\n\n/**\n * Parses video codec description (avcC, hvcC, etc.) from a track.\n */\nfunction parseVideoCodecDesc(track: TrakBoxParser): Uint8Array | undefined {\n for (const entry of track.mdia.minf.stbl.stsd.entries) {\n const box = entry.avcC ?? entry.hvcC ?? entry.av1C ?? entry.vpcC;\n if (box != null) {\n const stream = new mp4box.DataStream(undefined, 0, undefined);\n box.write(stream);\n return new Uint8Array(stream.buffer.slice(8)); // Skip box header\n }\n }\n return undefined;\n}\n\nfunction getESDSBoxFromMP4File(file: MP4File, codec = \"mp4a\"): ESDSBoxParser | undefined {\n const entry = file.moov?.traks\n .flatMap((t: any) => t.mdia.minf.stbl.stsd.entries)\n .find((e: any) => e.type === codec);\n // Return the nested ESDS box, not the sample entry itself\n return (entry?.esds ?? entry) as ESDSBoxParser | undefined;\n}\n\n/**\n * Parses audio configuration from ESDS Box.\n * ref: https://wiki.multimedia.cx/index.php/MPEG-4_Audio#Audio_Specific_Config\n */\nfunction parseAudioInfoFromESDSBox(esds: ESDSBoxParser): {\n codec?: string;\n sampleRate?: number;\n numberOfChannels?: number;\n description?: Uint8Array;\n} {\n const decConfDesc = esds.esd?.descs?.[0];\n if (!decConfDesc) return {};\n\n let codec = `mp4a.${decConfDesc.oti.toString(16)}`;\n const decSpecInfo = decConfDesc.descs?.[0];\n\n if (!decSpecInfo) {\n if (codec.endsWith(\".40\")) codec += \".2\";\n return { codec };\n }\n\n const data = decSpecInfo.data;\n if (!data) return { codec };\n const audioObjectType = (data[0] & 0xf8) >> 3;\n codec += `.${audioObjectType}`;\n\n // Bit parsing for sample rate and channels\n const sampleRateIdx = ((data[0] & 0x07) << 1) | (data[1] >> 7);\n const numberOfChannels = (data[1] & 0x78) >> 3;\n\n const SAMPLE_RATES = [\n 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350,\n ] as const;\n\n return {\n codec,\n sampleRate: SAMPLE_RATES[sampleRateIdx],\n numberOfChannels,\n description: data,\n };\n}\n\n/**\n * Quick parse mp4 file, prioritizing header parsing to save memory.\n */\nexport async function quickParseMP4File(\n reader: Awaited<ReturnType<ReturnType<typeof file>[\"createReader\"]>>,\n onReady: (data: { mp4boxFile: MP4File; info: MP4Info }) => void,\n onSamples: (id: number, sampleType: \"video\" | \"audio\", samples: MP4Sample[]) => void,\n) {\n const mp4boxFile = mp4box.createFile(false) as unknown as MP4File;\n\n mp4boxFile.onReady = (info: MP4Info) => {\n onReady({ mp4boxFile, info });\n\n [info.videoTracks[0], info.audioTracks[0]].forEach((track) => {\n if (track) {\n const type = (track as any).video ? \"video\" : \"audio\";\n mp4boxFile.setExtractionOptions(track.id, type, { nbSamples: 100 });\n }\n });\n\n mp4boxFile.start();\n };\n\n mp4boxFile.onSamples = onSamples;\n\n let cursor = 0;\n const CHUNK_SIZE = 30 * 1024 * 1024; // 30MB\n\n while (true) {\n const data = (await reader.read(CHUNK_SIZE, {\n at: cursor,\n })) as MP4ArrayBuffer;\n if (data.byteLength === 0) break;\n\n data.fileStart = cursor;\n const nextPos = mp4boxFile.appendBuffer(data);\n if (nextPos == null) break;\n cursor = nextPos;\n }\n\n mp4boxFile.stop();\n}\n\n/**\n * Parses transformation matrix to extract scale, rotation, and translation.\n */\nexport function parseMatrix(matrix?: Int32Array) {\n if (matrix?.length !== 9) return {};\n\n const m = new Int32Array(matrix.buffer);\n const fixed = (val: number) => val / 65536.0;\n\n const a = fixed(m[0]);\n const b = fixed(m[1]);\n const c = fixed(m[3]);\n const d = fixed(m[4]);\n const tx = fixed(m[6]);\n const ty = fixed(m[7]);\n const w = m[8] / (1 << 30);\n\n return {\n scaleX: Math.sqrt(a * a + c * c),\n scaleY: Math.sqrt(b * b + d * d),\n rotationRad: Math.atan2(c, a),\n rotationDeg: (Math.atan2(c, a) * 180) / Math.PI,\n translateX: tx,\n translateY: ty,\n perspective: w,\n };\n}\n\n/**\n * Creates a function to rotate VideoFrames using Canvas.\n */\nexport function createVFRotater(width: number, height: number, rotationDeg: number) {\n const normRotation = (Math.round(rotationDeg / 90) * 90 + 360) % 360;\n if (normRotation === 0) return (vf: VideoFrame | null) => vf;\n\n const isPortrait = normRotation === 90 || normRotation === 270;\n const rotatedWidth = isPortrait ? height : width;\n const rotatedHeight = isPortrait ? width : height;\n\n const canvas = new OffscreenCanvas(rotatedWidth, rotatedHeight);\n const ctx = canvas.getContext(\"2d\")!;\n\n ctx.translate(rotatedWidth / 2, rotatedHeight / 2);\n ctx.rotate((-normRotation * Math.PI) / 180);\n ctx.translate(-width / 2, -height / 2);\n\n return (vf: VideoFrame | null) => {\n if (!vf) return null;\n\n ctx.drawImage(vf, 0, 0);\n const newVF = new VideoFrame(canvas, {\n timestamp: vf.timestamp,\n duration: vf.duration ?? undefined,\n });\n vf.close();\n return newVF;\n };\n}\n","import type { MP4Info, MP4Sample } from \"wrapbox\";\nimport { file, tmpfile, write } from \"opfs-tools\";\nimport { Log } from \"../utils/log\";\nimport {\n createVFRotater,\n extractFileConfig,\n parseMatrix,\n quickParseMP4File,\n} from \"../mp4-utils/mp4box-utils\";\nimport { audioResample, extractPCM4AudioData, sleep, getEaseFactor } from \"../utils\";\nimport { BaseClip } from \"./base-clip\";\nimport { DEFAULT_AUDIO_CONF, type IClip, type IPlaybackCapable } from \"./iclip\";\nimport { type VideoJSON } from \"../json-serialization\";\nimport { ResourceManager } from \"../studio/resource-manager\";\n\nlet CLIP_ID = 0;\n\ntype OPFSToolFile = ReturnType<typeof file>;\nfunction isOTFile(obj: any): obj is OPFSToolFile {\n return obj.kind === \"file\" && obj.createReader instanceof Function;\n}\n\n// Internally used for creating Video instances\ntype MPClipCloneArgs = Awaited<ReturnType<typeof mp4FileToSamples>> & {\n localFile: OPFSToolFile;\n};\n\ninterface MP4DecoderConf {\n video: VideoDecoderConfig | null;\n audio: AudioDecoderConfig | null;\n}\n\nexport interface IMP4ClipOpts {\n audio?: boolean | { volume: number };\n /**\n * Unsafe, may be deprecated at any time\n */\n __unsafe_hardwareAcceleration__?: HardwarePreference;\n}\n\ntype ExtMP4Sample = Omit<MP4Sample, \"data\"> & {\n is_idr: boolean;\n deleted?: boolean;\n data: null | Uint8Array;\n};\n\ntype LocalFileReader = Awaited<ReturnType<OPFSToolFile[\"createReader\"]>>;\n/**\n * Video clip, parses MP4 files, uses {@link Video.tick} to decode image frames at specified time on demand\n *\n * Can be used to implement video frame extraction, thumbnail generation, video editing and other functions\n *\n * @example\n * // Load video clip asynchronously\n * const videoClip = await Video.fromUrl('clip.mp4', {\n * x: 0,\n * y: 0,\n * width: 1920,\n * height: 1080,\n * });\n *\n * // Set timeline position\n * videoClip.set({\n * display: {\n * from: 150, // frames\n * to: 450, // frames (10 seconds at 30fps)\n * },\n * });\n *\n */\nexport class Video extends BaseClip implements IPlaybackCapable {\n readonly type = \"Video\";\n private insId = CLIP_ID++;\n\n private logger = Log.create(`Video id:${this.insId},`);\n\n ready: IClip[\"ready\"];\n\n private _meta = {\n // microseconds\n duration: 0,\n width: 0,\n height: 0,\n audioSampleRate: 0,\n audioChanCount: 0,\n };\n\n get meta() {\n return { ...this._meta };\n }\n\n private localFile: OPFSToolFile;\n\n /** Store binary data of video header (box: ftyp, moov) */\n private headerBoxPos: Array<{ start: number; size: number }> = [];\n /**\n * Provide binary data of video header (box: ftyp, moov)\n * Use any mp4 demuxer to parse and get detailed video information\n * Unit tests include sample code using mp4box.js\n */\n async getFileHeaderBinData() {\n await this.ready;\n const oFile = await this.localFile.getOriginFile();\n if (oFile == null) throw Error(\"Video localFile is not origin file\");\n\n return await new Blob(\n this.headerBoxPos.map(({ start, size }) => oFile.slice(start, start + size)),\n ).arrayBuffer();\n }\n\n /** Store video transform and rotation info, currently only restores rotation */\n private parsedMatrix = {\n perspective: 1,\n rotationRad: 0,\n rotationDeg: 0,\n scaleX: 1,\n scaleY: 1,\n translateX: 0,\n translateY: 0,\n };\n private vfRotater: (vf: VideoFrame | null) => VideoFrame | null = (vf) => vf;\n\n private videoSamples: ExtMP4Sample[] = [];\n\n private audioSamples: ExtMP4Sample[] = [];\n\n private videoFrameFinder: VideoFrameFinder | null = null;\n private audioFrameFinder: AudioFrameFinder | null = null;\n\n protected override onEffectiveVolumeChange(): void {\n this.audioFrameFinder?.setVolume(this.effectiveVolume);\n }\n\n private decoderConf: {\n video: VideoDecoderConfig | null;\n audio: AudioDecoderConfig | null;\n } = {\n video: null,\n audio: null,\n };\n\n private opts: IMP4ClipOpts = { audio: true };\n\n /**\n * Whether to include audio track (hybrid JSON structure)\n */\n audio: boolean = true;\n\n /**\n * Unique identifier for this clip instance\n */\n id: string = `clip_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\n /**\n * Array of effects to be applied to this clip\n * Each effect specifies key, startTime, duration, and optional targets\n */\n effects: Array<{\n id: string;\n key: string;\n startTime: number;\n duration: number;\n }> = [];\n\n getVisibleHandles(): Array<\"tl\" | \"tr\" | \"bl\" | \"br\" | \"ml\" | \"mr\" | \"mt\" | \"mb\" | \"rot\"> {\n return [\"tl\", \"tr\", \"bl\", \"br\", \"rot\"];\n }\n\n /**\n * Load a video clip from a URL\n * @param url Video URL\n * @param opts Position and size options\n * @returns Promise that resolves to a video clip\n *\n * @example\n * const videoClip = await Video.fromUrl('clip.mp4', {\n * x: 0,\n * y: 0,\n * width: 1920,\n * height: 1080,\n * });\n */\n static async fromUrl(\n url: string,\n opts: {\n x?: number;\n y?: number;\n width?: number;\n height?: number;\n } = {},\n ): Promise<Video> {\n const stream = await ResourceManager.getReadableStream(url);\n const clip = new Video(stream, {}, url);\n await clip.ready;\n\n // Set position and size\n if (opts.x !== undefined) clip.left = opts.x;\n if (opts.y !== undefined) clip.top = opts.y;\n if (opts.width !== undefined) clip.width = opts.width;\n if (opts.height !== undefined) clip.height = opts.height;\n\n return clip;\n }\n\n constructor(\n source: OPFSToolFile | ReadableStream<Uint8Array> | MPClipCloneArgs,\n opts: IMP4ClipOpts = {},\n src?: string,\n ) {\n super();\n // Always set src, defaulting to empty string if not provided\n this.src = src !== undefined ? src : \"\";\n if (\n !(source instanceof ReadableStream) &&\n !isOTFile(source) &&\n !Array.isArray(source.videoSamples)\n ) {\n throw Error(\"Illegal argument\");\n }\n\n this.opts = { audio: true, ...opts };\n this.audio = typeof this.opts.audio === \"boolean\" ? this.opts.audio : true;\n this.volume =\n typeof opts.audio === \"object\" && \"volume\" in opts.audio\n ? opts.audio.volume\n : ((opts as any).volume ?? 1);\n\n const initByStream = async (s: ReadableStream) => {\n await write(this.localFile, s);\n return this.localFile;\n };\n\n this.localFile = isOTFile(source)\n ? source\n : \"localFile\" in source\n ? source.localFile // from clone\n : tmpfile();\n\n // Override the ready promise from BaseClip with our initialization\n this.ready = (\n source instanceof ReadableStream\n ? initByStream(source).then((otFile) => mp4FileToSamples(otFile, this.opts))\n : isOTFile(source)\n ? mp4FileToSamples(source, this.opts)\n : Promise.resolve(source)\n ).then(async ({ videoSamples, audioSamples, decoderConf, headerBoxPos, parsedMatrix }) => {\n this.videoSamples = videoSamples;\n this.audioSamples = audioSamples;\n this.decoderConf = decoderConf;\n this.headerBoxPos = headerBoxPos;\n this.parsedMatrix = parsedMatrix;\n\n const { videoFrameFinder, audioFrameFinder } = genDecoder(\n {\n video:\n decoderConf.video == null\n ? null\n : {\n ...decoderConf.video,\n hardwareAcceleration: this.opts.__unsafe_hardwareAcceleration__,\n },\n audio: decoderConf.audio,\n },\n await this.localFile.createReader(),\n videoSamples,\n audioSamples,\n this.opts.audio !== false ? this.volume : 0,\n );\n this.videoFrameFinder = videoFrameFinder;\n this.audioFrameFinder = audioFrameFinder;\n // Decoded at the real volume so unmuting later still has audio; apply the mute afterwards\n if (this.effectiveVolume !== this.volume) this.audioFrameFinder?.setVolume(this.effectiveVolume);\n\n const { codedWidth, codedHeight } = decoderConf.video ?? {};\n if (codedWidth && codedHeight) {\n this.vfRotater = createVFRotater(codedWidth, codedHeight, parsedMatrix.rotationDeg);\n }\n\n this._meta = genMeta(decoderConf, videoSamples, audioSamples, parsedMatrix.rotationDeg);\n\n this.logger.info(\"Video meta:\", this._meta);\n const meta = { ...this._meta };\n // Update rect and duration from meta (BaseClip pattern)\n this.width = this.width === 0 ? meta.width : this.width;\n this.height = this.height === 0 ? meta.height : this.height;\n\n // Update trim.to if not set or exceeds meta.duration\n this.trim.to = this.trim.to === 0 ? meta.duration : Math.min(this.trim.to, meta.duration);\n\n // Ensure trim.from is also valid\n this.trim.from = Math.min(this.trim.from, this.trim.to);\n\n const effectiveDuration = (this.trim.to - this.trim.from) / this.playbackRate;\n this.duration = this.duration === 0 ? effectiveDuration : this.duration;\n\n // Display check: if duration was 0 or incorrect from placeholder, sync it\n if (Math.abs(this.duration - effectiveDuration) > 1) {\n this.duration = effectiveDuration;\n }\n\n // Update display.to when duration changes\n this.display.to = this.display.from + this.duration;\n\n // Listen for volume changes to update audio finder\n this.on(\"propsChange\", (props) => {\n if ((props.volume !== undefined || props.muted !== undefined) && this.audioFrameFinder) {\n this.audioFrameFinder.setVolume(this.effectiveVolume);\n }\n });\n\n return meta;\n });\n }\n\n /**\n * Intercept data returned by {@link Video.tick} method for secondary processing of image and audio data\n * @param time Time when tick was called\n * @param tickRet Data returned by tick\n *\n * */\n tickInterceptor: <T extends Awaited<ReturnType<Video[\"tick\"]>>>(\n time: number,\n tickRet: T,\n ) => Promise<T> = async (_, tickRet) => tickRet;\n\n /**\n * Get image frame and audio data at specified time\n * @param time Time in microseconds\n */\n async tick(time: number): Promise<{\n video?: VideoFrame;\n audio: Float32Array[];\n state: \"success\" | \"done\";\n }> {\n const trimmedTime = time + this.trim.from;\n if (trimmedTime > this.trim.to || trimmedTime > this._meta.duration) {\n return await this.tickInterceptor(time, {\n audio: (await this.audioFrameFinder?.find(trimmedTime)) ?? [],\n state: \"done\",\n });\n }\n\n const [audio, video] = await Promise.all([\n this.audioFrameFinder?.find(trimmedTime) ?? [],\n this.videoFrameFinder?.find(trimmedTime).then(this.vfRotater),\n ]);\n\n if (video == null) {\n return await this.tickInterceptor(time, {\n audio,\n state: \"success\",\n });\n }\n\n return await this.tickInterceptor(time, {\n video,\n audio,\n state: \"success\",\n });\n }\n // Effects\n addEffect(effect: { id: string; key: string; startTime: number; duration: number }) {\n this.effects.push(effect);\n }\n\n editEffect(\n effectId: string,\n newEffectData: Partial<{\n key: string;\n startTime: number;\n duration: number;\n }>,\n ) {\n const effect = this.effects.find((e) => e.id === effectId);\n if (effect) {\n Object.assign(effect, newEffectData);\n }\n }\n\n removeEffect(effectId: string) {\n const effectIndex = this.effects.findIndex((e) => e.id === effectId);\n if (effectIndex !== -1) {\n this.effects.splice(effectIndex, 1);\n }\n }\n\n /**\n * Split is handled by core state, not implemented here\n */\n async split(_time: number): Promise<[this, this]> {\n throw new Error(\"Video.split is not implemented - use core state instead\");\n }\n\n async clone() {\n await this.ready;\n const clip = new Video(\n {\n localFile: this.localFile,\n videoSamples: [...this.videoSamples],\n audioSamples: [...this.audioSamples],\n decoderConf: this.decoderConf,\n headerBoxPos: this.headerBoxPos,\n parsedMatrix: this.parsedMatrix,\n },\n this.opts,\n this.src,\n );\n await clip.ready;\n clip.tickInterceptor = this.tickInterceptor;\n // Copy sprite state (animations, opacity, rect, etc.) to the cloned clip\n this.copyStateTo(clip);\n // Copy id and effects\n clip.id = this.id;\n clip.effects = [...this.effects];\n return clip as this;\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n this.logger.info(\"Video destroy\");\n super.destroy();\n\n this.videoFrameFinder?.destroy();\n this.audioFrameFinder?.destroy();\n }\n\n toJSON(main: boolean = false): VideoJSON {\n const base = super.toJSON(main);\n return {\n ...base,\n type: \"Video\",\n audio: this.audio,\n volume: this.volume,\n id: this.id,\n effects: this.effects,\n } as VideoJSON;\n }\n\n /**\n * Create a Video instance from a JSON object (fabric.js pattern)\n * @param json The JSON object representing the clip\n * @returns Promise that resolves to a Video instance\n */\n static async fromObject(json: VideoJSON): Promise<Video> {\n if (json.type !== \"Video\") {\n throw new Error(`Expected Video, got ${json.type}`);\n }\n\n // Support both new flat structure and old options structure\n const options =\n json.audio !== undefined\n ? { audio: json.audio, volume: json.volume }\n : { volume: json.volume };\n\n const stream = await ResourceManager.getReadableStream(json.src!);\n const clip = new Video(stream, options as any, json.src);\n\n BaseClip.deserializeBaseProperties(clip, json);\n\n // Apply specific video properties\n if (json.effects) {\n clip.effects = json.effects;\n }\n if (json.volume !== undefined) {\n clip.volume = json.volume;\n }\n\n return clip;\n }\n\n /**\n * Create HTMLVideoElement for playback\n */\n async createPlaybackElement(): Promise<{\n element: HTMLVideoElement;\n objectUrl?: string;\n }> {\n await this.ready;\n\n const mp4ClipAny = this as any;\n const localFile = mp4ClipAny.localFile;\n\n if (!localFile || typeof localFile.getOriginFile !== \"function\") {\n throw new Error(\"Video does not have a local file for playback\");\n }\n\n const originFile = await localFile.getOriginFile();\n if (!originFile) {\n throw new Error(\"Failed to get origin file from VideoClip\");\n }\n\n const objectUrl = URL.createObjectURL(originFile);\n const video = document.createElement(\"video\");\n\n video.crossOrigin = \"anonymous\";\n video.muted = true;\n video.autoplay = false;\n video.playsInline = true;\n video.preload = \"auto\";\n video.loop = false;\n video.src = objectUrl;\n\n // Wait for video to be ready\n await new Promise<void>((resolve, reject) => {\n const onLoadedData = () => {\n video.removeEventListener(\"loadeddata\", onLoadedData);\n video.removeEventListener(\"error\", onError);\n video.pause();\n video.currentTime = 0;\n resolve();\n };\n const onError = () => {\n video.removeEventListener(\"loadeddata\", onLoadedData);\n video.removeEventListener(\"error\", onError);\n reject(new Error(\"Failed to load video\"));\n };\n video.addEventListener(\"loadeddata\", onLoadedData, { once: true });\n video.addEventListener(\"error\", onError, { once: true });\n video.load();\n });\n\n return { element: video, objectUrl };\n }\n\n async play(element: HTMLVideoElement | HTMLAudioElement, timeSeconds: number): Promise<void> {\n const video = element as HTMLVideoElement;\n const trimmedTime = timeSeconds + this.trim.from / 1e6;\n // Set time if needed\n if (Math.abs(video.currentTime - trimmedTime) > 0.1) {\n video.currentTime = trimmedTime;\n }\n\n video.muted = false;\n\n if (video.paused) {\n try {\n await video.play();\n } catch (err) {\n // Retry once on failure\n try {\n await video.play();\n } catch (retryErr) {\n console.warn(\"Failed to play video:\", retryErr);\n }\n }\n }\n }\n\n pause(element: HTMLVideoElement | HTMLAudioElement): void {\n const video = element as HTMLVideoElement;\n video.pause();\n video.muted = true;\n }\n\n async seek(element: HTMLVideoElement | HTMLAudioElement, timeSeconds: number): Promise<void> {\n const video = element as HTMLVideoElement;\n const trimmedTime = timeSeconds + this.trim.from / 1e6;\n video.pause();\n video.currentTime = trimmedTime;\n // Fire-and-forget: return immediately so the caller can render with\n // whatever frame is currently available (real-time scrubbing).\n // Register a one-shot seeked listener that re-renders once the browser\n // has decoded the target frame, giving eventual correctness.\n video.addEventListener(\n \"seeked\",\n () => {\n (video as any).__pendingRender?.();\n },\n { once: true },\n );\n }\n\n syncPlayback(\n element: HTMLVideoElement | HTMLAudioElement,\n isPlaying: boolean,\n timeSeconds: number,\n ): void {\n const video = element as HTMLVideoElement;\n const clipDuration =\n this.duration && this.duration !== Infinity\n ? this.duration / 1e6\n : (this.display.to - this.display.from) / 1e6;\n const isWithinClip = timeSeconds >= 0 && timeSeconds < clipDuration;\n\n const trimmedTime = timeSeconds + this.trim.from / 1e6;\n // Sync volume with fade applied for HTML Video element preview\n const clipDurationMs = clipDuration * 1000;\n const timeMs = timeSeconds * 1000;\n let fadeMultiplier = 1.0;\n if (\n this.timing.fadeIn &&\n this.timing.fadeIn.duration > 0 &&\n timeMs < this.timing.fadeIn.duration\n ) {\n fadeMultiplier *= getEaseFactor(\n timeMs / this.timing.fadeIn.duration,\n this.timing.fadeIn.curve,\n );\n }\n if (this.timing.fadeOut && this.timing.fadeOut.duration > 0) {\n const fadeOutStartMs = clipDurationMs - this.timing.fadeOut.duration;\n if (timeMs >= fadeOutStartMs) {\n const t = 1.0 - (timeMs - fadeOutStartMs) / this.timing.fadeOut.duration;\n fadeMultiplier *= getEaseFactor(t, this.timing.fadeOut.curve);\n }\n }\n video.volume = Math.max(0, Math.min(1, this.effectiveVolume * fadeMultiplier));\n\n if (isPlaying && isWithinClip) {\n // Should be playing\n if (video.paused) {\n this.play(video, timeSeconds).catch(console.warn);\n } else {\n // Already playing - minimal checks\n if (video.muted) {\n video.muted = false;\n }\n // Restart if ended\n if (video.ended || video.currentTime >= this.trim.to / 1e6) {\n video.currentTime = trimmedTime;\n video.play().catch(console.warn);\n }\n }\n } else {\n // Should be paused\n if (!video.paused) {\n video.pause();\n }\n video.muted = true;\n\n // Update time when paused\n if (isWithinClip && Math.abs(video.currentTime - trimmedTime) > 0.1) {\n video.currentTime = trimmedTime;\n }\n }\n }\n\n cleanupPlayback(element: HTMLVideoElement | HTMLAudioElement, objectUrl?: string): void {\n const video = element as HTMLVideoElement;\n video.pause();\n video.removeAttribute(\"src\");\n video.load();\n\n if (objectUrl) {\n URL.revokeObjectURL(objectUrl);\n }\n }\n\n /**\n * Scale clip to fit within the scene dimensions while maintaining aspect ratio\n * Similar to fabric.js scaleToFit\n * @param sceneWidth Scene width\n * @param sceneHeight Scene height\n */\n async scaleToFit(sceneWidth: number, sceneHeight: number): Promise<void> {\n await this.ready;\n const { width, height } = this.meta;\n if (width === 0 || height === 0) return;\n\n const scale = Math.min(sceneWidth / width, sceneHeight / height);\n this.width = width * scale;\n this.height = height * scale;\n }\n\n /**\n * Scale clip to fill the scene dimensions while maintaining aspect ratio\n * May crop parts of the clip. Similar to fabric.js scaleToFill\n * @param sceneWidth Scene width\n * @param sceneHeight Scene height\n */\n async scaleToFill(sceneWidth: number, sceneHeight: number): Promise<void> {\n await this.ready;\n const { width, height } = this.meta;\n if (width === 0 || height === 0) return;\n\n const scale = Math.max(sceneWidth / width, sceneHeight / height);\n this.width = width * scale;\n this.height = height * scale;\n }\n\n /**\n * Center the clip within the scene dimensions\n * Similar to fabric.js center\n * @param sceneWidth Scene width\n * @param sceneHeight Scene height\n */\n centerInScene(sceneWidth: number, sceneHeight: number): void {\n this.left = (sceneWidth - this.width) / 2;\n this.top = (sceneHeight - this.height) / 2;\n }\n}\n\nfunction genMeta(\n decoderConf: MP4DecoderConf,\n videoSamples: ExtMP4Sample[],\n audioSamples: ExtMP4Sample[],\n rotationDeg: number,\n) {\n const meta = {\n duration: 0,\n width: 0,\n height: 0,\n audioSampleRate: 0,\n audioChanCount: 0,\n };\n if (decoderConf.video != null && videoSamples.length > 0) {\n meta.width = decoderConf.video.codedWidth ?? 0;\n meta.height = decoderConf.video.codedHeight ?? 0;\n // 90, 270 degrees, need to swap width and height\n const normalizedRotation = (Math.round(rotationDeg / 90) * 90 + 360) % 360;\n if (normalizedRotation === 90 || normalizedRotation === 270) {\n [meta.width, meta.height] = [meta.height, meta.width];\n }\n }\n if (decoderConf.audio != null && audioSamples.length > 0) {\n meta.audioSampleRate = DEFAULT_AUDIO_CONF.sampleRate;\n meta.audioChanCount = DEFAULT_AUDIO_CONF.channelCount;\n }\n\n let vDuration = 0;\n let aDuration = 0;\n if (videoSamples.length > 0) {\n for (let i = videoSamples.length - 1; i >= 0; i--) {\n const s = videoSamples[i];\n if (s.deleted) continue;\n vDuration = s.cts + s.duration;\n break;\n }\n }\n if (audioSamples.length > 0) {\n const lastSampele = audioSamples.at(-1)!;\n aDuration = lastSampele.cts + lastSampele.duration;\n }\n meta.duration = Math.max(vDuration, aDuration);\n\n return meta;\n}\n\nfunction genDecoder(\n decoderConf: MP4DecoderConf,\n localFileReader: LocalFileReader,\n videoSamples: ExtMP4Sample[],\n audioSamples: ExtMP4Sample[],\n volume: number,\n) {\n return {\n audioFrameFinder:\n volume === 0 || decoderConf.audio == null || audioSamples.length === 0\n ? null\n : new AudioFrameFinder(localFileReader, audioSamples, decoderConf.audio, {\n volume,\n targetSampleRate: DEFAULT_AUDIO_CONF.sampleRate,\n }),\n videoFrameFinder:\n decoderConf.video == null || videoSamples.length === 0\n ? null\n : new VideoFrameFinder(localFileReader, videoSamples, decoderConf.video),\n };\n}\n\nasync function mp4FileToSamples(otFile: OPFSToolFile, opts: IMP4ClipOpts = {}) {\n let mp4Info: MP4Info | null = null;\n const decoderConf: MP4DecoderConf = { video: null, audio: null };\n let videoSamples: ExtMP4Sample[] = [];\n let audioSamples: ExtMP4Sample[] = [];\n let headerBoxPos: Array<{ start: number; size: number }> = [];\n const parsedMatrix = {\n perspective: 1,\n rotationRad: 0,\n rotationDeg: 0,\n scaleX: 1,\n scaleY: 1,\n translateX: 0,\n translateY: 0,\n };\n\n let videoDeltaTS = -1;\n let audioDeltaTS = -1;\n const reader = await otFile.createReader();\n await quickParseMP4File(\n reader,\n async (data) => {\n mp4Info = data.info;\n const ftyp = data.mp4boxFile.ftyp!;\n headerBoxPos.push({ start: ftyp.start, size: ftyp.size });\n const moov = data.mp4boxFile.moov!;\n headerBoxPos.push({ start: moov.start, size: moov.size });\n\n Object.assign(parsedMatrix, parseMatrix(mp4Info.videoTracks[0]?.matrix));\n\n let { videoDecoderConf: vc, audioDecoderConf: ac } = extractFileConfig(\n data.mp4boxFile,\n data.info,\n );\n decoderConf.video = vc ?? null;\n decoderConf.audio = ac ?? null;\n if (vc == null && ac == null) {\n Log.error(\"Video no video and audio track\");\n }\n if (ac != null) {\n const { supported } = await AudioDecoder.isConfigSupported(ac);\n if (!supported) {\n Log.error(`Video audio codec is not supported: ${ac.codec}`);\n }\n }\n if (vc != null) {\n const { supported } = await VideoDecoder.isConfigSupported(vc);\n if (!supported) {\n Log.error(`Video video codec is not supported: ${vc.codec}`);\n }\n }\n Log.info(\n \"mp4BoxFile moov ready\",\n {\n ...data.info,\n tracks: null,\n videoTracks: null,\n audioTracks: null,\n },\n decoderConf,\n );\n },\n (_, type, samples) => {\n if (type === \"video\") {\n if (videoDeltaTS === -1) videoDeltaTS = samples[0].dts;\n for (const s of samples) {\n videoSamples.push(normalizeTimescale(s, videoDeltaTS, \"video\"));\n }\n } else if (type === \"audio\" && opts.audio) {\n if (audioDeltaTS === -1) audioDeltaTS = samples[0].dts;\n for (const s of samples) {\n audioSamples.push(normalizeTimescale(s, audioDeltaTS, \"audio\"));\n }\n }\n },\n );\n await reader.close();\n\n const lastSampele = videoSamples.at(-1) ?? audioSamples.at(-1);\n if (mp4Info == null) {\n throw Error(\"Video stream is done, but not emit ready\");\n } else if (lastSampele == null) {\n throw Error(\"Video stream not contain any sample\");\n }\n // Fix first black frame\n fixFirstBlackFrame(videoSamples);\n Log.info(\"mp4 stream parsed\");\n return {\n videoSamples,\n audioSamples,\n decoderConf,\n headerBoxPos,\n parsedMatrix,\n };\n}\n\nfunction normalizeTimescale(s: MP4Sample, delta = 0, sampleType: \"video\" | \"audio\") {\n // todo: perf discard redundant fields, small objects perform better\n let offset = s.offset;\n // When IDR frame contains non-image data (like SEI) before it, decoding may fail\n const idrOffset =\n sampleType === \"video\" && s.is_sync ? idrNALUOffset(s.data, s.description.type) : -1;\n\n let size = s.size;\n if (idrOffset > 0) {\n // Skip non-image data by controlling offset and size fields\n offset += idrOffset;\n size -= idrOffset;\n }\n\n return {\n ...s,\n is_idr: idrOffset >= 0,\n offset,\n size,\n cts: ((s.cts - delta) / s.timescale) * 1e6,\n dts: ((s.dts - delta) / s.timescale) * 1e6,\n duration: (s.duration / s.timescale) * 1e6,\n timescale: 1e6,\n // Audio data volume is controllable, save directly in memory\n data: sampleType === \"video\" ? null : s.data,\n };\n}\n\nclass VideoFrameFinder {\n private decoder: VideoDecoder | null = null;\n constructor(\n public localFileReader: LocalFileReader,\n public samples: ExtMP4Sample[],\n public conf: VideoDecoderConfig,\n ) {}\n\n private timestamp = 0;\n private curAborter = { abort: false, st: performance.now() };\n find = async (time: number): Promise<VideoFrame | null> => {\n if (\n this.decoder == null ||\n this.decoder.state === \"closed\" ||\n time < this.timestamp ||\n time - this.timestamp > 3e6\n ) {\n this.reset(time);\n }\n\n this.curAborter.abort = true;\n this.timestamp = time;\n\n this.curAborter = { abort: false, st: performance.now() };\n const vf = await this.parseFrame(time, this.decoder, this.curAborter);\n this.sleepCnt = 0;\n return vf;\n };\n\n // Fix VideoFrame duration is null\n private lastVfDur = 0;\n\n private downgradeSoftDecode = false;\n private videoDecCursorIdx = 0;\n private videoFrames: VideoFrame[] = [];\n private outputFrameCnt = 0;\n private inputChunkCnt = 0;\n private sleepCnt = 0;\n private predecodeErr = false;\n private _firstPresentableTs: number | null = null;\n\n /**\n * Earliest presentation timestamp among the samples of the first decodable GOP (the first IDR\n * sample up to the next one). Frames before it can't be produced, so it is held instead.\n */\n private firstPresentableTs(): number {\n if (this._firstPresentableTs != null) return this._firstPresentableTs;\n let start = this.samples.findIndex((s) => s.is_idr && !s.deleted);\n if (start < 0) start = 0;\n let min = Infinity;\n for (let i = start; i < this.samples.length; i++) {\n const s = this.samples[i];\n if (i > start && s.is_idr) break;\n if (!s.deleted && s.cts < min) min = s.cts;\n }\n this._firstPresentableTs = Number.isFinite(min) ? min : 0;\n return this._firstPresentableTs;\n }\n\n private parseFrame = async (\n time: number,\n dec: VideoDecoder | null,\n aborter: { abort: boolean; st: number },\n ): Promise<VideoFrame | null> => {\n if (dec == null || dec.state === \"closed\" || aborter.abort) return null;\n\n if (this.videoFrames.length > 0) {\n const vf = this.videoFrames[0];\n if (time < vf.timestamp) {\n // Before the stream's first presentable frame (encoder delay, B-frame reordering, a cut\n // stream or a skipped non-IDR first GOP can push it to ~0.5s): hold that first frame instead\n // of returning nothing, which rendered black until its PTS. Return a copy so callers can\n // close/consume it without invalidating the queue.\n if (time <= 0 || vf.timestamp <= this.firstPresentableTs()) {\n return new VideoFrame(vf);\n }\n return null;\n }\n // Pop first frame\n this.videoFrames.shift();\n // First frame expired, find next frame\n if (time > vf.timestamp + (vf.duration ?? 0)) {\n vf.close();\n return await this.parseFrame(time, dec, aborter);\n }\n\n if (!this.predecodeErr && this.videoFrames.length < 10) {\n // Pre-decode to avoid waiting\n this.startDecode(dec).catch((err) => {\n this.predecodeErr = true;\n this.reset(time);\n throw err;\n });\n }\n // Matches expectation\n return vf;\n }\n\n // Missing frame data\n if (this.decoding || (this.outputFrameCnt < this.inputChunkCnt && dec.decodeQueueSize > 0)) {\n if (performance.now() - aborter.st > 6e3) {\n throw Error(`Video.tick video timeout, ${JSON.stringify(this.getState())}`);\n }\n // Decoding, wait, then retry\n this.sleepCnt += 1;\n await sleep(15);\n } else if (this.videoDecCursorIdx >= this.samples.length) {\n // Decode completed\n return null;\n } else {\n try {\n await this.startDecode(dec);\n } catch (err) {\n this.reset(time);\n throw err;\n }\n }\n return await this.parseFrame(time, dec, aborter);\n };\n\n private decoding = false;\n private startDecode = async (dec: VideoDecoder) => {\n if (this.decoding || dec.decodeQueueSize > 600) return;\n\n // Start decode task, then retry\n let endIdx = this.videoDecCursorIdx + 1;\n if (endIdx > this.samples.length) return;\n\n this.decoding = true;\n // Frames in this GOP time range that have time matches and are not deleted\n let hasValidFrame = false;\n for (; endIdx < this.samples.length; endIdx++) {\n const s = this.samples[endIdx];\n if (!hasValidFrame && !s.deleted) {\n hasValidFrame = true;\n }\n // Find a GOP, so end at next IDR frame\n if (s.is_idr) break;\n }\n\n if (hasValidFrame) {\n const samples = this.samples.slice(this.videoDecCursorIdx, endIdx);\n if (samples[0]?.is_idr !== true) {\n Log.warn(\"First sample not idr frame\");\n } else {\n const readStartTime = performance.now();\n const chunks = await videosamples2Chunks(samples, this.localFileReader);\n\n const readCost = performance.now() - readStartTime;\n if (readCost > 1000) {\n const first = samples[0];\n const last = samples.at(-1)!;\n const rangSize = last.offset + last.size - first.offset;\n Log.warn(\n `Read video samples time cost: ${Math.round(readCost)}ms, file chunk size: ${rangSize}`,\n );\n }\n // Wait for the previous asynchronous operation to complete, at which point the task may have already been terminated\n if (dec.state === \"closed\") return;\n\n this.lastVfDur = chunks[0]?.duration ?? 0;\n decodeGoP(dec, chunks, {\n onDecodingError: (err) => {\n if (this.downgradeSoftDecode) {\n throw err;\n } else if (this.outputFrameCnt === 0) {\n this.downgradeSoftDecode = true;\n Log.warn(\"Downgrade to software decode\");\n this.reset();\n }\n },\n });\n\n this.inputChunkCnt += chunks.length;\n }\n }\n this.videoDecCursorIdx = endIdx;\n this.decoding = false;\n };\n\n private reset = (time?: number) => {\n this.decoding = false;\n this.videoFrames.forEach((f) => f.close());\n this.videoFrames = [];\n if (time == null || time === 0) {\n this.videoDecCursorIdx = 0;\n } else {\n let keyIdx = 0;\n for (let i = 0; i < this.samples.length; i++) {\n const s = this.samples[i];\n if (s.is_idr) keyIdx = i;\n if (s.cts < time) continue;\n this.videoDecCursorIdx = keyIdx;\n break;\n }\n }\n this.inputChunkCnt = 0;\n this.outputFrameCnt = 0;\n if (this.decoder?.state !== \"closed\") this.decoder?.close();\n const encoderConf = {\n ...this.conf,\n ...(this.downgradeSoftDecode ? { hardwareAcceleration: \"prefer-software\" } : {}),\n } as VideoDecoderConfig;\n this.decoder = new VideoDecoder({\n output: (vf) => {\n this.outputFrameCnt += 1;\n if (vf.timestamp === -1) {\n vf.close();\n return;\n }\n let rsVf = vf;\n if (vf.duration == null) {\n rsVf = new VideoFrame(vf, {\n duration: this.lastVfDur,\n });\n vf.close();\n }\n this.videoFrames.push(rsVf);\n },\n error: (err) => {\n if (err.message.includes(\"Codec reclaimed due to inactivity\")) {\n // todo: Should decoder that was auto-closed due to inactivity be auto-restarted?\n this.decoder = null;\n Log.warn(err.message);\n return;\n }\n\n const errMsg = `VideoFinder VideoDecoder err: ${\n err.message\n }, config: ${JSON.stringify(encoderConf)}, state: ${JSON.stringify(this.getState())}`;\n Log.error(errMsg);\n throw Error(errMsg);\n },\n });\n this.decoder.configure(encoderConf);\n };\n\n private getState = () => ({\n time: this.timestamp,\n decState: this.decoder?.state,\n decQSize: this.decoder?.decodeQueueSize,\n decCursorIdx: this.videoDecCursorIdx,\n sampleLen: this.samples.length,\n inputCnt: this.inputChunkCnt,\n outputCnt: this.outputFrameCnt,\n cacheFrameLen: this.videoFrames.length,\n softDecode: this.downgradeSoftDecode,\n clipIdCnt: CLIP_ID,\n sleepCnt: this.sleepCnt,\n memInfo: memoryUsageInfo(),\n });\n\n destroy = async () => {\n this.curAborter.abort = true;\n\n // Close video frames first\n this.videoFrames.forEach((f) => f.close());\n this.videoFrames = [];\n\n // Properly close the decoder\n if (this.decoder && this.decoder.state !== \"closed\") {\n try {\n this.decoder.close();\n } catch {\n // Ignore close errors - decoder may already be closed\n }\n }\n this.decoder = null;\n\n this.localFileReader.close();\n };\n}\n\nfunction findIndexOfSamples(time: number, samples: ExtMP4Sample[]) {\n for (let i = 0; i < samples.length; i++) {\n const s = samples[i];\n if (time >= s.cts && time < s.cts + s.duration) {\n return i;\n }\n if (s.cts > time) break;\n }\n return 0;\n}\n\nclass AudioFrameFinder {\n private volume = 1;\n private sampleRate: number;\n constructor(\n public localFileReader: LocalFileReader,\n public samples: ExtMP4Sample[],\n public conf: AudioDecoderConfig,\n opts: { volume: number; targetSampleRate: number },\n ) {\n this.volume = opts.volume;\n this.sampleRate = opts.targetSampleRate;\n }\n\n setVolume(volume: number) {\n this.volume = volume;\n this.reset();\n }\n\n private decoder: ReturnType<typeof createAudioChunksDecoder> | null = null;\n private curAborter = { abort: false, st: performance.now() };\n find = async (time: number): Promise<Float32Array[]> => {\n const needResetTime = time <= this.timestamp || time - this.timestamp > 0.1e6;\n if (this.decoder == null || this.decoder.state === \"closed\" || needResetTime) {\n this.reset();\n }\n\n if (needResetTime) {\n // Audio data difference before/after cannot exceed 100ms (empirical value), otherwise treat as seek operation, reset decoder\n // Seek operation, reset time\n this.timestamp = time;\n this.decCursorIdx = findIndexOfSamples(time, this.samples);\n }\n\n this.curAborter.abort = true;\n const deltaTime = time - this.timestamp;\n this.timestamp = time;\n\n this.curAborter = { abort: false, st: performance.now() };\n\n const pcmData = await this.parseFrame(\n Math.ceil(deltaTime * (this.sampleRate / 1e6)),\n this.decoder,\n this.curAborter,\n );\n this.sleepCnt = 0;\n\n return pcmData;\n };\n\n private timestamp = 0;\n private decCursorIdx = 0;\n private pcmData: {\n frameCnt: number;\n data: [Float32Array, Float32Array][];\n } = {\n frameCnt: 0,\n data: [],\n };\n private sleepCnt = 0;\n private parseFrame = async (\n emitFrameCnt: number,\n dec: ReturnType<typeof createAudioChunksDecoder> | null = null,\n aborter: { abort: boolean; st: number },\n ): Promise<Float32Array[]> => {\n if (dec == null || aborter.abort || dec.state === \"closed\" || emitFrameCnt === 0) {\n return [];\n }\n\n // Data satisfies requirement\n const remainFrameCnt = this.pcmData.frameCnt - emitFrameCnt;\n if (remainFrameCnt > 0) {\n // Remaining audio data less than 100ms, pre-decode\n if (remainFrameCnt < DEFAULT_AUDIO_CONF.sampleRate / 10) {\n this.startDecode(dec);\n }\n return emitAudioFrames(this.pcmData, emitFrameCnt);\n }\n\n if (dec.decoding) {\n // Slow machines/headless workers can take well over 3s to decode a chunk; aborting the whole\n // export there was worse than emitting the audio decoded so far.\n if (performance.now() - aborter.st > 60e3) {\n console.warn(`[Video.tick] Audio decode wait exceeded 60s, using the PCM decoded so far`, this.getState());\n return this.pcmData.frameCnt > 0 ? emitAudioFrames(this.pcmData, this.pcmData.frameCnt) : [];\n }\n // Decoding, wait\n this.sleepCnt += 1;\n await sleep(15);\n } else if (this.decCursorIdx >= this.samples.length - 1) {\n // Last fragment, return remaining data\n return emitAudioFrames(this.pcmData, this.pcmData.frameCnt);\n } else {\n this.startDecode(dec);\n }\n return this.parseFrame(emitFrameCnt, dec, aborter);\n };\n\n private startDecode = (dec: ReturnType<typeof createAudioChunksDecoder>) => {\n const onceDecodeCnt = 10;\n if (dec.decodeQueueSize > onceDecodeCnt) return;\n // Start decode task\n const samples = [];\n let i = this.decCursorIdx;\n while (i < this.samples.length) {\n const s = this.samples[i];\n i += 1;\n if (s.deleted) continue;\n samples.push(s);\n if (samples.length >= onceDecodeCnt) break;\n }\n this.decCursorIdx = i;\n\n dec.decode(\n samples.map(\n (s) =>\n new EncodedAudioChunk({\n type: \"key\",\n timestamp: s.cts,\n duration: s.duration,\n data: s.data!,\n }),\n ),\n );\n };\n\n private reset = () => {\n this.timestamp = 0;\n this.decCursorIdx = 0;\n this.pcmData = {\n frameCnt: 0,\n data: [],\n };\n this.decoder?.close();\n this.decoder = createAudioChunksDecoder(\n this.conf,\n {\n resampleRate: DEFAULT_AUDIO_CONF.sampleRate,\n volume: this.volume,\n },\n (pcmArr) => {\n this.pcmData.data.push(pcmArr as [Float32Array, Float32Array]);\n this.pcmData.frameCnt += pcmArr[0].length;\n },\n );\n };\n\n private getState = () => ({\n time: this.timestamp,\n decState: this.decoder?.state,\n decQSize: this.decoder?.decodeQueueSize,\n decCursorIdx: this.decCursorIdx,\n sampleLen: this.samples.length,\n pcmLen: this.pcmData.frameCnt,\n clipIdCnt: CLIP_ID,\n sleepCnt: this.sleepCnt,\n memInfo: memoryUsageInfo(),\n });\n\n destroy = () => {\n this.decoder = null;\n this.curAborter.abort = true;\n this.pcmData = {\n frameCnt: 0,\n data: [],\n };\n this.localFileReader.close();\n };\n}\n\nfunction createAudioChunksDecoder(\n decoderConf: AudioDecoderConfig,\n opts: { resampleRate: number; volume: number },\n outputCb: (pcm: Float32Array[]) => void,\n) {\n let inputCnt = 0;\n let outputCnt = 0;\n const outputHandler = (pcmArr: Float32Array[]) => {\n outputCnt += 1;\n if (pcmArr.length === 0) return;\n\n if (opts.volume !== 1) {\n for (const pcm of pcmArr) for (let i = 0; i < pcm.length; i++) pcm[i] *= opts.volume;\n }\n\n // Ensure stereo\n if (pcmArr.length === 1) pcmArr = [pcmArr[0], pcmArr[0]];\n\n outputCb(pcmArr);\n };\n const resampleQ = createPromiseQueue<Float32Array[]>(outputHandler);\n\n const needResample = opts.resampleRate !== decoderConf.sampleRate;\n let adec = new AudioDecoder({\n output: (ad) => {\n const pcm = extractPCM4AudioData(ad);\n if (needResample) {\n resampleQ(() =>\n audioResample(pcm, ad.sampleRate, {\n rate: opts.resampleRate,\n chanCount: ad.numberOfChannels,\n }),\n );\n } else {\n outputHandler(pcm);\n }\n ad.close();\n },\n error: (err) => {\n if (err.message.includes(\"Codec reclaimed due to inactivity\")) {\n return;\n }\n handleDecodeError(\"Video AudioDecoder err\", err as Error);\n },\n });\n adec.configure(decoderConf);\n\n function handleDecodeError(prefixStr: string, err: Error) {\n const errMsg = `${prefixStr}: ${(err as Error).message}, state: ${JSON.stringify({\n qSize: adec.decodeQueueSize,\n state: adec.state,\n inputCnt,\n outputCnt,\n decoderConf,\n opts,\n })}`;\n Log.error(errMsg);\n throw Error(errMsg);\n }\n\n return {\n decode(chunks: EncodedAudioChunk[]) {\n inputCnt += chunks.length;\n try {\n for (const chunk of chunks) adec.decode(chunk);\n } catch (err) {\n handleDecodeError(\"decode audio chunk error\", err as Error);\n }\n },\n close() {\n if (adec.state !== \"closed\") adec.close();\n },\n get decoding() {\n return inputCnt > outputCnt && adec.decodeQueueSize > 0;\n },\n get state() {\n return adec.state;\n },\n get decodeQueueSize() {\n return adec.decodeQueueSize;\n },\n };\n}\n\n// Parallel execution, but emit results in order\nfunction createPromiseQueue<T extends any>(onResult: (data: T) => void) {\n const rsCache: T[] = [];\n let waitingIdx = 0;\n\n function updateRs(rs: T, emitIdx: number) {\n rsCache[emitIdx] = rs;\n emitRs();\n }\n\n function emitRs() {\n const rs = rsCache[waitingIdx];\n if (rs == null) return;\n onResult(rs);\n\n waitingIdx += 1;\n emitRs();\n }\n\n let addIdx = 0;\n return (task: () => Promise<T>) => {\n const emitIdx = addIdx;\n addIdx += 1;\n task()\n .then((rs) => updateRs(rs, emitIdx))\n .catch((err) => updateRs(err, emitIdx));\n };\n}\n\nfunction emitAudioFrames(\n pcmData: { frameCnt: number; data: [Float32Array, Float32Array][] },\n emitCnt: number,\n) {\n // todo: perf reuse memory space\n const audio = [new Float32Array(emitCnt), new Float32Array(emitCnt)];\n let offset = 0;\n let i = 0;\n for (; i < pcmData.data.length; ) {\n const [chan0, chan1] = pcmData.data[i];\n if (offset + chan0.length > emitCnt) {\n const gapCnt = emitCnt - offset;\n audio[0].set(chan0.subarray(0, gapCnt), offset);\n audio[1].set(chan1.subarray(0, gapCnt), offset);\n pcmData.data[i][0] = chan0.subarray(gapCnt, chan0.length);\n pcmData.data[i][1] = chan1.subarray(gapCnt, chan1.length);\n break;\n } else {\n audio[0].set(chan0, offset);\n audio[1].set(chan1, offset);\n offset += chan0.length;\n i++;\n }\n }\n pcmData.data = pcmData.data.slice(i);\n pcmData.frameCnt -= emitCnt;\n return audio;\n}\n\nasync function videosamples2Chunks(\n samples: ExtMP4Sample[],\n reader: Awaited<ReturnType<OPFSToolFile[\"createReader\"]>>,\n): Promise<EncodedVideoChunk[]> {\n const first = samples[0];\n const last = samples.at(-1);\n if (last == null) return [];\n\n const rangSize = last.offset + last.size - first.offset;\n if (rangSize < 30e6) {\n // Single read data < 30M, read all at once to reduce IO frequency\n const data = new Uint8Array(await reader.read(rangSize, { at: first.offset }));\n return samples.map((s) => {\n const offset = s.offset - first.offset;\n return new EncodedVideoChunk({\n type: s.is_sync ? \"key\" : \"delta\",\n timestamp: s.cts,\n duration: s.duration,\n data: data.subarray(offset, offset + s.size),\n });\n });\n }\n\n return await Promise.all(\n samples.map(async (s) => {\n return new EncodedVideoChunk({\n type: s.is_sync ? \"key\" : \"delta\",\n timestamp: s.cts,\n duration: s.duration,\n data: await reader.read(s.size, {\n at: s.offset,\n }),\n });\n }),\n );\n}\n\n// Support decoding errors\nfunction decodeGoP(\n dec: VideoDecoder,\n chunks: EncodedVideoChunk[],\n opts: {\n onDecodingError?: (err: Error) => void;\n },\n) {\n if (dec.state !== \"configured\") return;\n for (let i = 0; i < chunks.length; i++) dec.decode(chunks[i]);\n\n // todo: The next frame after flush must be an IDR frame. Decide whether to call flush based on context?\n // flush may not be resolved on some Windows devices, so do not await flush\n dec.flush().catch((err) => {\n if (!(err instanceof Error)) throw err;\n if (err.message.includes(\"Decoding error\") && opts.onDecodingError != null) {\n opts.onDecodingError(err);\n return;\n }\n // reset interrupts the decoder, expected to throw AbortedError\n if (!err.message.includes(\"Aborted due to close\")) {\n throw err;\n }\n });\n}\n\nfunction idrNALUOffset(u8Arr: Uint8Array, type: MP4Sample[\"description\"][\"type\"]) {\n if (type !== \"avc1\" && type !== \"hvc1\") return 0;\n\n const dv = new DataView(u8Arr.buffer);\n for (let i = 0; i < u8Arr.byteLength - 4; ) {\n if (type === \"avc1\") {\n const nalUnitType = dv.getUint8(i + 4) & 0x1f;\n // 5: IDR frame, 7: SPS, 8: PPS\n if (nalUnitType === 5 || nalUnitType === 7 || nalUnitType === 8) return i;\n } else if (type === \"hvc1\") {\n const nalUnitType = (dv.getUint8(i + 4) >> 1) & 0x3f;\n // 19-20: IDR frame, 32-34: VPS SPS PPS\n if (\n nalUnitType === 19 ||\n nalUnitType === 20 ||\n nalUnitType === 32 ||\n nalUnitType === 33 ||\n nalUnitType === 34\n )\n return i;\n }\n // Jump to next NALU to continue checking\n i += dv.getUint32(i) + 4;\n }\n return -1;\n}\n\n/**\n * Fix black first-frame caused by a non-zero CTS (composition time) offset.\n *\n * Some encoders produce an initial keyframe with CTS > 0, which means the\n * decoder shows nothing (black) until that timestamp. This function finds\n * the first keyframe and shifts its CTS to 0 (absorbing the gap into its\n * duration) so playback starts immediately with a visible frame.\n *\n * Only applied when the offset is < 200 ms (empirical threshold).\n */\nconst MAX_BLACK_FRAME_OFFSET_US = 200_000; // 200 ms in microseconds\n\nfunction fixFirstBlackFrame(samples: ExtMP4Sample[]) {\n let firstKeyframe: ExtMP4Sample | null = null;\n let keyframeCount = 0;\n\n for (const sample of samples) {\n if (sample.deleted) continue;\n if (sample.is_sync) keyframeCount++;\n if (keyframeCount >= 2) break; // Only inspect up to the first GOP\n\n if (sample.is_sync && (firstKeyframe == null || sample.cts < firstKeyframe.cts)) {\n firstKeyframe = sample;\n }\n }\n\n if (firstKeyframe != null && firstKeyframe.cts < MAX_BLACK_FRAME_OFFSET_US) {\n firstKeyframe.duration += firstKeyframe.cts;\n firstKeyframe.cts = 0;\n }\n}\n\nfunction memoryUsageInfo() {\n try {\n // @ts-ignore\n const mem = performance.memory;\n return {\n jsHeapSizeLimit: mem.jsHeapSizeLimit,\n totalJSHeapSize: mem.totalJSHeapSize,\n usedJSHeapSize: mem.usedJSHeapSize,\n percentUsed: (mem.usedJSHeapSize / mem.jsHeapSizeLimit).toFixed(3),\n percentTotal: (mem.totalJSHeapSize / mem.jsHeapSizeLimit).toFixed(3),\n };\n } catch (err) {\n return {};\n }\n}\n","import { type Application, type Container, SplitBitmapText, Color } from \"pixi.js\";\nimport { BaseClip } from \"./base-clip\";\nimport type { IClip } from \"./iclip\";\nimport type { TextJSON, TextStyleJSON } from \"../json-serialization\";\nimport type { BaseSpriteEvents } from \"../sprite/base-sprite\";\nimport { BaseTextClip, type IBaseTextOpts } from \"./base-text-clip\";\n\nexport interface ITextOpts extends IBaseTextOpts {\n /**\n * Text decoration ('none', 'underline', 'line-through', 'overline')\n * @default 'none'\n */\n textDecoration?: \"none\" | \"underline\" | \"line-through\" | \"overline\";\n /**\n * Words per line mode ('single' or 'multiple')\n * @default 'multiple'\n */\n wordsPerLine?: \"single\" | \"multiple\";\n}\n\nexport interface ITextEvents extends BaseSpriteEvents {\n propsChange: Partial<\n {\n left: number;\n top: number;\n width: number;\n height: number;\n angle: number;\n zIndex: number;\n opacity: number;\n volume: number;\n text: string;\n style: any;\n } & ITextOpts\n >;\n}\n\n/**\n * Text clip using PixiJS Text for rendering\n *\n * @example\n * const textClip = new Text('Hello World', {\n * fontSize: 48,\n * fill: '#ffffff',\n * stroke: '#000000',\n * strokeWidth: 2,\n * dropShadow: {\n * color: '#000000',\n * alpha: 0.5,\n * blur: 4,\n * distance: 2,\n * },\n * });\n * textClip.duration = 5e6; // 5 seconds\n */\nexport class Text extends BaseTextClip<ITextEvents> {\n readonly type = \"Text\";\n declare ready: IClip[\"ready\"];\n\n // Override width/height to trigger refreshText when resized by transformer\n // Use getters from BaseSprite but override setters\n override get width(): number {\n return (this as any)._width;\n }\n\n override set width(v: number) {\n if (Math.abs(this.width - v) < 0.1) return;\n (this as any)._width = v;\n this._targetWidth = v;\n this.refreshText().then(() => {\n // When height is auto (not explicitly set), emit height change after text reflows\n if (!this._explicitHeight) {\n this.emit(\"propsChange\", { width: v, height: this.height });\n } else {\n this.emit(\"propsChange\", { width: v });\n }\n });\n }\n\n override get height(): number {\n return (this as any)._height;\n }\n\n /**\n * Flag to track if height was explicitly set by user (vs auto-calculated from content)\n */\n private _explicitHeight = false;\n\n /**\n * Get whether height was explicitly set by user\n */\n get isExplicitHeight(): boolean {\n return this._explicitHeight;\n }\n\n /**\n * Reset height to auto-fit mode (height will adjust to content)\n */\n resetHeightToAuto(): void {\n this._explicitHeight = false;\n (this as any)._height = 0;\n this.refreshText().then(() => {\n this.emit(\"propsChange\", { height: this.height });\n });\n }\n\n override set height(v: number) {\n if (Math.abs(this.height - v) < 0.1) return;\n // Store the requested value temporarily\n const requestedHeight = v;\n (this as any)._height = v;\n this.refreshText().then(() => {\n // After refresh, determine if this should be treated as explicit height\n // contentHeight = the natural height text wants at current width\n const contentHeight = this.meta.height;\n // Only auto-mark as explicit if user is forcing a smaller height than content requires\n // (diff < -5px). Otherwise preserve existing explicit mode or stay in auto mode.\n // This prevents transformer resize from accidentally marking height as explicit\n // when text reflows due to width changes.\n const diff = requestedHeight - contentHeight;\n const isForcingSmaller = diff < -5;\n // Mark as explicit if: value > 0 AND (forcing smaller OR already explicit)\n this._explicitHeight = requestedHeight > 0 && (isForcingSmaller || this._explicitHeight);\n // Emit the actual calculated height (may differ from input v if content is taller)\n this.emit(\"propsChange\", { height: this.height });\n });\n }\n\n /**\n * Text content (hybrid JSON structure)\n */\n get text(): string {\n return this._text;\n }\n\n set text(v: string) {\n if (this._text === v) return;\n this._text = v;\n // Only refresh if already initialized\n if (this.originalOpts && this.textStyle) {\n this.refreshText().then(() => {\n this.emit(\"propsChange\", { text: v });\n });\n }\n }\n\n /**\n * Text styling (hybrid JSON structure)\n * Provides direct access to styling properties\n */\n /**\n * Text styling (hybrid JSON structure)\n * Provides direct access to styling properties\n */\n override get style(): any {\n return {\n fontSize: this.originalOpts.fontSize,\n fontFamily: this.originalOpts.fontFamily,\n fontUrl: this.originalOpts.fontUrl,\n fontWeight: this.originalOpts.fontWeight,\n fontStyle: this.originalOpts.fontStyle,\n color: this.originalOpts.color,\n align: this.originalOpts.align,\n stroke: this.originalOpts.stroke\n ? typeof this.originalOpts.stroke === \"object\"\n ? {\n color: this.originalOpts.stroke.color,\n width: this.originalOpts.stroke.width,\n join: this.originalOpts.stroke.join,\n cap: this.originalOpts.stroke.cap,\n miterLimit: this.originalOpts.stroke.miterLimit,\n }\n : {\n color: this.originalOpts.stroke,\n width: this.originalOpts.strokeWidth ?? 0,\n }\n : undefined,\n shadow: this.originalOpts.shadow\n ? {\n color: this.originalOpts.shadow.color ?? \"#000000\",\n alpha: this.originalOpts.shadow.alpha ?? 0.5,\n blur: this.originalOpts.shadow.blur ?? 4,\n offsetX: this.originalOpts.shadow.offsetX ?? 0,\n offsetY: this.originalOpts.shadow.offsetY ?? 0,\n }\n : undefined,\n wordWrap: this.originalOpts.wordWrap,\n wordWrapWidth: this.originalOpts.wordWrapWidth,\n lineHeight: this.originalOpts.lineHeight,\n letterSpacing: this.originalOpts.letterSpacing,\n textCase: this.originalOpts.textCase,\n textDecoration: this.originalOpts.textDecoration,\n background: this.originalOpts.background,\n };\n }\n\n override set style(opts: Partial<ITextOpts>) {\n this.updateStyle(opts);\n }\n\n /**\n * Text alignment proxy for compatibility with UI\n */\n get textAlign(): \"left\" | \"center\" | \"right\" {\n return this.originalOpts.align || (this.originalOpts as any).textAlign || \"left\";\n }\n\n set textAlign(v: \"left\" | \"center\" | \"right\") {\n this.updateStyle({ align: v });\n }\n\n /**\n * Vertical alignment or decoration proxy\n */\n get verticalAlign(): string {\n return (this.originalOpts as any).verticalAlign || this.originalOpts.textDecoration || \"top\";\n }\n\n set verticalAlign(v: string) {\n if ([\"underline\", \"overline\", \"strikethrough\", \"line-through\"].includes(v)) {\n this.updateStyle({\n textDecoration: v === \"strikethrough\" ? \"line-through\" : (v as any),\n } as any);\n // Also store as verticalAlign for UI state persistence\n (this.originalOpts as any).verticalAlign = v;\n } else {\n this.updateStyle({ verticalAlign: v } as any);\n }\n }\n\n /**\n * Text case proxy\n */\n get textCase(): string {\n return this.originalOpts.textCase || \"none\";\n }\n\n set textCase(v: \"none\" | \"uppercase\" | \"lowercase\" | \"title\") {\n this.updateStyle({ textCase: v });\n }\n\n /**\n * Decoration proxies for UI compatibility (booleans)\n */\n get underline(): boolean {\n return this.originalOpts.textDecoration === \"underline\";\n }\n\n set underline(v: boolean) {\n this.updateStyle({ textDecoration: v ? \"underline\" : \"none\" });\n }\n\n get overline(): boolean {\n return this.originalOpts.textDecoration === \"overline\";\n }\n\n set overline(v: boolean) {\n this.updateStyle({ textDecoration: v ? \"overline\" : \"none\" });\n }\n\n get linethrough(): boolean {\n return this.originalOpts.textDecoration === \"line-through\";\n }\n\n set linethrough(v: boolean) {\n this.updateStyle({ textDecoration: v ? \"line-through\" : \"none\" });\n }\n\n // The resize target set by the width setter. Kept separate from _width (which\n // _doRefreshText overwrites with the measured containerWidth at the end of each run).\n protected _targetWidth = 0;\n\n // Cached measurements for fast real-time layout updates (fabric.js-style optimization)\n private _wordCache: Array<{\n text: string;\n width: number;\n height: number;\n textObj: SplitBitmapText | null;\n }> = [];\n private _measuredTextHeight = 0;\n private _lineHeightMultiplier = 1;\n private _fontSize = 40;\n private _textOnlyContainer: Container | null = null;\n\n declare public originalOpts: ITextOpts;\n\n constructor(text: string, opts: ITextOpts = {}, renderer?: Application[\"renderer\"]) {\n super();\n this.originalOpts = { ...opts } as ITextOpts;\n this._text = text;\n if (renderer) this.setRenderer(renderer);\n this._buildTextStyles();\n this.ready = (async () => {\n await this.refreshText();\n return { ...this.meta };\n })();\n }\n\n override _onAfterRefresh(\n words: string[],\n textOnlyContainer: Container,\n spaceWidth: number,\n measuredTextHeight: number,\n lineHeightMultiplier: number,\n fontSize: number,\n ): void {\n this._populateWordCache(\n words,\n textOnlyContainer,\n spaceWidth,\n measuredTextHeight,\n lineHeightMultiplier,\n fontSize,\n );\n }\n\n async clone() {\n await this.ready;\n const style = this.textStyle;\n const originalOpts = this.originalOpts || {};\n\n const colorToNumber = (color: any): number | undefined => {\n if (color === undefined || color === null) return undefined;\n if (typeof color === \"number\") return color;\n if (color instanceof Color) return color.toNumber();\n return undefined;\n };\n\n const { stroke, strokeWidth } = this._cloneStrokeOpts(colorToNumber);\n\n const opts: ITextOpts = {\n fontSize: originalOpts.fontSize ?? style.fontSize,\n fontFamily:\n originalOpts.fontFamily ??\n (Array.isArray(style.fontFamily)\n ? style.fontFamily[0]\n : typeof style.fontFamily === \"string\"\n ? style.fontFamily\n : \"Roboto\"),\n fontUrl: originalOpts.fontUrl,\n fontWeight: originalOpts.fontWeight ?? style.fontWeight,\n fontStyle: originalOpts.fontStyle ?? style.fontStyle,\n align:\n originalOpts.align ??\n (style.align === \"justify\" ? \"left\" : (style.align as \"left\" | \"center\" | \"right\")),\n textCase: originalOpts.textCase,\n textDecoration: originalOpts.textDecoration,\n color: this._cloneColorOpts(colorToNumber),\n stroke,\n strokeWidth,\n shadow: this._cloneShadowOpts(colorToNumber),\n };\n\n if (originalOpts.wordWrap !== undefined) {\n opts.wordWrap = originalOpts.wordWrap;\n opts.wordWrapWidth = originalOpts.wordWrapWidth;\n } else if (style.wordWrap) {\n opts.wordWrap = style.wordWrap;\n opts.wordWrapWidth = style.wordWrapWidth;\n }\n\n if (originalOpts.background !== undefined) opts.background = originalOpts.background;\n\n if (originalOpts.lineHeight !== undefined) {\n opts.lineHeight = originalOpts.lineHeight;\n } else if (style.lineHeight !== undefined) {\n const fontSize = opts.fontSize ?? style.fontSize ?? 40;\n opts.lineHeight = style.lineHeight / fontSize;\n }\n if (originalOpts.letterSpacing !== undefined) {\n opts.letterSpacing = originalOpts.letterSpacing;\n } else if (style.letterSpacing !== undefined) {\n opts.letterSpacing = style.letterSpacing;\n }\n\n const newClip = new Text(this.text, opts) as this;\n await newClip.ready;\n this.copyStateTo(newClip);\n newClip.id = this.id;\n newClip.effects = [...this.effects];\n return newClip;\n }\n\n /**\n * Update text styling options and refresh the texture\n */\n async updateStyle(opts: Partial<ITextOpts>): Promise<void> {\n const processedOpts = this._normalizeStyleOpts(opts);\n this.originalOpts = { ...this.originalOpts, ...processedOpts } as ITextOpts;\n this._buildTextStyles();\n await this.refreshText();\n this.emit(\"propsChange\", opts);\n }\n\n private _populateWordCache(\n words: string[],\n textOnlyContainer: import(\"pixi.js\").Container,\n spaceWidth: number,\n measuredTextHeight: number,\n lineHeightMultiplier: number,\n fontSize: number,\n ): void {\n this._wordCache = this.wordTexts.map((textObj, i) => ({\n text: words[i],\n width: Math.ceil(textObj.getLocalBounds().width || textObj.width),\n height: Math.ceil(textObj.getLocalBounds().height || textObj.height),\n textObj,\n }));\n this._spaceWidth = spaceWidth;\n this._measuredTextHeight = measuredTextHeight;\n this._lineHeightMultiplier = lineHeightMultiplier;\n this._fontSize = fontSize;\n this._textOnlyContainer = textOnlyContainer;\n }\n\n /**\n * Fast layout update for real-time transform operations.\n * Re-calculates word wrapping and repositions existing text objects without\n * re-creating them. Much faster than full refreshText() for resize operations.\n *\n * @param targetWidth - The new target width for wrapping\n * @returns Object with new width and height\n */\n updateLayoutForWidth(targetWidth: number): { width: number; height: number } {\n if (!this._wordCache.length || !this._textOnlyContainer || !this.pixiTextContainer) {\n // Fall back to full refresh if cache not populated\n this._targetWidth = targetWidth;\n void this.refreshText();\n return { width: this.width, height: this.height };\n }\n\n const bgPadX = this.originalOpts.background?.paddingX ?? 8;\n const bgPadY = this.originalOpts.background?.paddingY ?? 4;\n const lineHeightMultiplier = this._lineHeightMultiplier;\n const fontSize = this._fontSize;\n const lineHeight = fontSize * lineHeightMultiplier;\n const measuredTextHeight = this._measuredTextHeight;\n const spaceWidth = this._spaceWidth;\n\n // Calculate wrap width (inner text area)\n const wrapWidth = Math.max(1, targetWidth - bgPadX * 2);\n\n // Fast line breaking using cached word widths\n const lines: Array<{ wordIndices: number[]; width: number; height: number }> = [];\n let currentLine: number[] = [];\n let currentLineWidth = 0;\n let currentLineHeight = 0;\n\n for (let i = 0; i < this._wordCache.length; i++) {\n const word = this._wordCache[i];\n const wordWidth = word.width;\n const wordHeight = word.height;\n\n const projectedWidth = currentLineWidth + (currentLineWidth > 0 ? spaceWidth : 0) + wordWidth;\n if (projectedWidth <= wrapWidth || currentLine.length === 0) {\n currentLine.push(i);\n currentLineWidth = projectedWidth;\n currentLineHeight = Math.max(currentLineHeight, wordHeight);\n } else {\n if (currentLine.length > 0) {\n lines.push({\n wordIndices: currentLine,\n width: currentLineWidth,\n height: Math.max(currentLineHeight, lineHeight),\n });\n }\n currentLine = [i];\n currentLineWidth = wordWidth;\n currentLineHeight = wordHeight;\n }\n }\n\n if (currentLine.length > 0) {\n lines.push({\n wordIndices: currentLine,\n width: currentLineWidth,\n height: Math.max(currentLineHeight, lineHeight),\n });\n }\n\n // Calculate total height\n const bgLineHeight = measuredTextHeight + bgPadY * 2;\n lines.forEach((line) => {\n line.height = Math.max(line.height, bgLineHeight);\n });\n\n let maxLineWidth = 0;\n let totalHeight = 0;\n lines.forEach((line) => {\n maxLineWidth = Math.max(maxLineWidth, line.width);\n totalHeight += line.height;\n });\n\n // Container dimensions\n const contentWidth = maxLineWidth + bgPadX * 2;\n const contentHeight = totalHeight;\n const containerWidth = Math.max(contentWidth, targetWidth);\n const containerHeight = contentHeight; // Always auto-height during transform\n\n // Position words within container\n const finalAlign = this.textAlign;\n const finalVAlign = (this.originalOpts as any).verticalAlign || \"top\";\n\n let startY = 0;\n if (finalVAlign === \"center\") {\n startY = (containerHeight - contentHeight) / 2;\n } else if (finalVAlign === \"bottom\") {\n startY = containerHeight - contentHeight;\n }\n\n let currentY = startY;\n lines.forEach((line) => {\n let currentX = 0;\n if (finalAlign === \"center\") {\n currentX = (containerWidth - line.width) / 2;\n } else if (finalAlign === \"right\") {\n currentX = containerWidth - line.width - bgPadX * 2;\n } else {\n currentX = bgPadX;\n }\n\n line.wordIndices.forEach((wordIndex, wordIdxInLine) => {\n const word = this._wordCache[wordIndex];\n if (word.textObj) {\n word.textObj.x = Math.round(currentX);\n word.textObj.y = Math.round(currentY + (line.height - measuredTextHeight) / 2 - 9);\n }\n currentX += word.width + (wordIdxInLine < line.wordIndices.length - 1 ? spaceWidth : 0);\n });\n\n currentY += line.height;\n });\n\n // Update clip dimensions\n this._meta.width = containerWidth;\n this._meta.height = containerHeight;\n (this as any)._width = containerWidth;\n (this as any)._height = containerHeight;\n this._targetWidth = containerWidth;\n\n // Update render texture if dimensions changed significantly\n const newPaddedWidth = containerWidth + (this.renderTexturePadding ?? 0) * 2;\n const newPaddedHeight = containerHeight + (this.renderTexturePadding ?? 0) * 2;\n if (\n this.renderTexture &&\n (Math.abs(this.renderTexture.width - newPaddedWidth) > 10 ||\n Math.abs(this.renderTexture.height - newPaddedHeight) > 10)\n ) {\n // Re-render to update texture dimensions\n void this.getTexture();\n }\n\n return { width: containerWidth, height: containerHeight };\n }\n\n toJSON(main: boolean = false): TextJSON {\n const base = super.toJSON(main);\n\n // Build style object from originalOpts\n const style: TextStyleJSON = {};\n if (this.originalOpts.fontSize !== undefined) style.fontSize = this.originalOpts.fontSize;\n if (this.originalOpts.fontFamily !== undefined) style.fontFamily = this.originalOpts.fontFamily;\n if (this.originalOpts.fontUrl !== undefined) style.fontUrl = this.originalOpts.fontUrl;\n if (this.originalOpts.fontWeight !== undefined)\n style.fontWeight = this.originalOpts.fontWeight as any;\n if (this.originalOpts.fontStyle !== undefined) style.fontStyle = this.originalOpts.fontStyle;\n if (this.originalOpts.color !== undefined) style.color = this.originalOpts.color as any;\n if (this.originalOpts.align !== undefined) style.align = this.originalOpts.align;\n if (this.originalOpts.wordWrap !== undefined) style.wordWrap = this.originalOpts.wordWrap;\n if (this.originalOpts.wordWrapWidth !== undefined)\n style.wordWrapWidth = this.originalOpts.wordWrapWidth;\n if (this.originalOpts.lineHeight !== undefined) style.lineHeight = this.originalOpts.lineHeight;\n if (this.originalOpts.letterSpacing !== undefined)\n style.letterSpacing = this.originalOpts.letterSpacing;\n\n // Background options\n if (this.originalOpts.background !== undefined) style.background = this.originalOpts.background;\n\n // Handle stroke\n if (this.originalOpts.stroke) {\n if (typeof this.originalOpts.stroke === \"object\") {\n style.stroke = {\n color: this.originalOpts.stroke.color as any,\n width: this.originalOpts.stroke.width,\n join: this.originalOpts.stroke.join,\n cap: (this.originalOpts.stroke as any).cap, // cap might be missing from ITextOpts definition but present in object\n miterLimit: (this.originalOpts.stroke as any).miterLimit,\n };\n } else {\n style.stroke = {\n color: this.originalOpts.stroke as any,\n width: this.originalOpts.strokeWidth ?? 0,\n };\n }\n }\n\n if (this.originalOpts.shadow) {\n style.shadow = {\n color: (this.originalOpts.shadow.color ?? \"#000000\") as string,\n alpha: this.originalOpts.shadow.alpha ?? 0.5,\n blur: this.originalOpts.shadow.blur ?? 4,\n offsetX: this.originalOpts.shadow.offsetX ?? 0,\n offsetY: this.originalOpts.shadow.offsetY ?? 0,\n };\n }\n\n return {\n ...base,\n type: \"Text\",\n text: this.text,\n style,\n id: this.id,\n effects: this.effects,\n } as TextJSON;\n }\n\n /**\n * Create a Text instance from a JSON object (fabric.js pattern)\n * @param json The JSON object representing the clip\n * @returns Promise that resolves to a Text instance\n */\n static async fromObject(json: TextJSON): Promise<Text> {\n if (json.type !== \"Text\") {\n throw new Error(`Expected Text, got ${json.type}`);\n }\n\n // Support new structure (text + style) and old structure (options)\n const text = json.text || \"\";\n const style = json.style || {};\n\n // Build options object from style\n const textClipOpts: ITextOpts = {};\n if (style.fontSize !== undefined) textClipOpts.fontSize = style.fontSize;\n if (style.fontFamily !== undefined) textClipOpts.fontFamily = style.fontFamily;\n if (style.fontUrl !== undefined) textClipOpts.fontUrl = style.fontUrl;\n if (style.fontWeight !== undefined) textClipOpts.fontWeight = style.fontWeight as any;\n if (style.fontStyle !== undefined) textClipOpts.fontStyle = style.fontStyle;\n if (style.color !== undefined) textClipOpts.color = style.color;\n if (style.align !== undefined) textClipOpts.align = style.align;\n if (style.wordWrap !== undefined) textClipOpts.wordWrap = style.wordWrap;\n if (style.wordWrapWidth !== undefined) textClipOpts.wordWrapWidth = style.wordWrapWidth;\n if (style.lineHeight !== undefined) textClipOpts.lineHeight = style.lineHeight;\n if (style.letterSpacing !== undefined) textClipOpts.letterSpacing = style.letterSpacing;\n\n // Background options\n if (style.background !== undefined) textClipOpts.background = style.background;\n\n // Handle stroke\n if (style.stroke) {\n if (style.stroke.join || style.stroke.cap || style.stroke.miterLimit !== undefined) {\n textClipOpts.stroke = {\n color: style.stroke.color,\n width: style.stroke.width,\n join: style.stroke.join,\n cap: style.stroke.cap,\n miterLimit: style.stroke.miterLimit,\n };\n } else {\n textClipOpts.stroke = style.stroke.color;\n textClipOpts.strokeWidth = style.stroke.width;\n }\n }\n\n if (style.shadow) {\n textClipOpts.shadow = {\n color: style.shadow.color,\n alpha: style.shadow.alpha,\n blur: style.shadow.blur,\n offsetX: style.shadow.offsetX ?? 0,\n offsetY: style.shadow.offsetY ?? 0,\n };\n }\n\n const clip = new Text(text, textClipOpts);\n\n BaseClip.deserializeBaseProperties(clip, json);\n\n // Apply text-specific effects if present\n if ((json as any).effects) {\n clip.effects = (json as any).effects;\n }\n\n await clip.ready;\n return clip;\n }\n\n /**\n * Override handle visibility for text clips\n * Text clips should only show: mr (mid-right), mb (mid-bottom), br (bottom-right), and rot (rotation)\n * This allows resizing width and height independently while preventing corner handles that might distort text\n */\n override getVisibleHandles(): Array<\n \"tl\" | \"tr\" | \"bl\" | \"br\" | \"ml\" | \"mr\" | \"mt\" | \"mb\" | \"rot\"\n > {\n return [\"mr\", \"mb\", \"br\", \"rot\"];\n }\n}\n","export function camelToWords(text: string) {\n return text.replace(/([a-z])([A-Z])/g, \"$1 $2\").replace(/^./, (str) => str.toUpperCase());\n}\n","import { BaseClip } from \"./base-clip\";\nimport { type IClip } from \"./iclip\";\nimport { type EffectKey } from \"../effect/glsl/gl-effect\";\nimport { camelToWords } from \"../utils/effect\";\n\n// Since Effect is an adjustment layer, it doesn't render visual content directly.\n// We can use a minimal dummy implementation for BaseClip abstract methods.\n\nexport class Effect extends BaseClip {\n readonly type = \"Effect\";\n ready: IClip[\"ready\"];\n\n private _meta = {\n duration: 5e6, // Default 5 seconds\n width: 0,\n height: 0,\n };\n\n get meta() {\n return { ...this._meta };\n }\n\n /**\n * Unique identifier for this clip instance\n */\n id: string = `clip_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\n /**\n * The effect key\n */\n effectKey: EffectKey;\n\n /**\n * Effect parameters / values\n */\n values: Record<string, any> = {};\n\n constructor(effectKey: EffectKey) {\n super();\n this.effectKey = effectKey;\n this.name = camelToWords(effectKey);\n\n // Ready immediately\n this.ready = Promise.resolve(this._meta);\n this.duration = this._meta.duration;\n }\n\n async clone() {\n const newClip = new Effect(this.effectKey);\n this.copyStateTo(newClip);\n newClip.values = { ...this.values };\n return newClip as this;\n }\n\n // Effect is invisible, so it returns empty/dummy data\n async tick(_time: number): Promise<{\n video: ImageBitmap | undefined;\n state: \"success\";\n }> {\n return {\n video: undefined,\n state: \"success\",\n };\n }\n\n async split(_time: number): Promise<[this, this]> {\n const clone1 = await this.clone();\n const clone2 = await this.clone();\n return [clone1, clone2];\n }\n\n toJSON(_main: boolean = false): any {\n return {\n id: this.id,\n type: \"Effect\",\n name: this.name,\n timing: {\n display: {\n from: this.timing.display.from,\n to: this.timing.display.to,\n },\n trim: {\n from: this.timing.trim.from,\n to: this.timing.trim.to,\n },\n duration: this.timing.duration,\n playbackRate: this.timing.playbackRate,\n },\n effectKey: this.effectKey,\n values: this.values,\n };\n }\n\n /**\n * Create an Effect instance from a JSON object\n */\n static async fromObject(json: any): Promise<Effect> {\n if (json.type !== \"Effect\") {\n throw new Error(`Expected Effect, got ${json.type}`);\n }\n\n const key = json.effectKey;\n if (!key) {\n throw new Error(`Missing effectKey in Effect JSON`);\n }\n\n const clip = new Effect(key);\n clip.values = json.values || {};\n\n BaseClip.deserializeBaseProperties(clip, json);\n\n await clip.ready;\n return clip;\n }\n}\n","import { BaseClip } from \"./base-clip\";\nimport type { IClipMeta } from \"./iclip\";\n\nexport class Placeholder extends BaseClip {\n type: string = \"Placeholder\";\n\n meta: IClipMeta = {\n width: 0,\n height: 0,\n duration: 0,\n };\n\n constructor(src: string, meta: Partial<IClipMeta> = {}, type: string = \"Placeholder\") {\n super();\n this.type = type;\n this.src = src;\n this.meta = {\n width: meta.width || 1280,\n height: meta.height || 720,\n duration: meta.duration || 5000000,\n };\n\n this.width = this.meta.width;\n this.height = this.meta.height;\n this.duration = this.meta.duration;\n this.trim.to = this.duration;\n this.display.to = this.display.from + this.duration;\n\n this.ready = Promise.resolve(this.meta);\n }\n\n private canvas: HTMLCanvasElement | null = null;\n private ctx: CanvasRenderingContext2D | null = null;\n private animationRafId: number | null = null;\n private renderPending = false;\n\n async tick(_time: number): Promise<{\n video: ImageBitmap | VideoFrame | null;\n audio: Float32Array[];\n state: \"done\" | \"success\";\n }> {\n if (!this.canvas) {\n this.canvas = document.createElement(\"canvas\");\n this.canvas.width = this.meta.width;\n this.canvas.height = this.meta.height;\n this.ctx = this.canvas.getContext(\"2d\");\n }\n\n const { canvas, ctx } = this;\n if (ctx) {\n const { width, height } = canvas;\n if (width > 0 && height > 0) {\n // 1. Clear and Draw Background\n ctx.fillStyle = \"#1e1e1e\";\n ctx.fillRect(0, 0, width, height);\n\n // 2. Draw Spinner\n const centerX = width / 2;\n const centerY = height / 2;\n const radius = 100;\n const thickness = radius / 4;\n\n // Rotation based on real-time (performance.now())\n // ensures it spins even if the engine's time is 0\n const rotation = (performance.now() / 2000) * Math.PI * 2;\n\n ctx.save();\n\n // Create a gradient for the spinner tail effect\n const gradient = ctx.createConicGradient(rotation, centerX, centerY);\n gradient.addColorStop(0, \"#ffffff\"); // Head\n gradient.addColorStop(0.2, \"#ffffff\");\n gradient.addColorStop(0.5, \"rgba(255, 255, 255, 0.4)\");\n gradient.addColorStop(0.8, \"rgba(255, 255, 255, 0.1)\"); // Tail\n gradient.addColorStop(1, \"rgba(255, 255, 255, 0)\");\n\n ctx.strokeStyle = gradient;\n ctx.lineWidth = thickness;\n ctx.lineCap = \"round\";\n\n ctx.beginPath();\n // Draw 270 degrees of the ring starting from the current rotation\n ctx.arc(centerX, centerY, radius, rotation, rotation + Math.PI * 1.5);\n ctx.stroke();\n\n ctx.restore();\n\n // 4. Add a subtle border\n ctx.strokeStyle = \"#333333\";\n ctx.lineWidth = 10;\n ctx.strokeRect(0, 0, width, height);\n }\n }\n\n // Schedule next render via rAF with back-pressure guard.\n // renderPending prevents flooding: we only emit request-render\n // once per completed render cycle (tick clears the flag below).\n this.renderPending = false; // Current tick() is completing — allow next request\n if (this.animationRafId === null) {\n const scheduleNext = () => {\n if (this.destroyed) {\n this.animationRafId = null;\n return;\n }\n if (!this.renderPending) {\n this.renderPending = true;\n this.emit(\"request-render\" as any);\n }\n this.animationRafId = requestAnimationFrame(scheduleNext);\n };\n this.animationRafId = requestAnimationFrame(scheduleNext);\n }\n\n const frame = canvas.width > 0 && canvas.height > 0 ? await createImageBitmap(canvas) : null;\n\n return {\n video: frame,\n state: \"success\",\n audio: [],\n };\n }\n\n async clone() {\n const clip = new Placeholder(this.src, this.meta);\n this.copyStateTo(clip);\n clip.id = this.id;\n return clip as this;\n }\n\n async split(time: number): Promise<[this, this]> {\n const pre = await this.clone();\n const post = await this.clone();\n\n pre.trim.to = time + this.trim.from;\n post.trim.from = time + this.trim.from;\n\n pre.duration = pre.trim.to - pre.trim.from;\n post.duration = post.trim.to - post.trim.from;\n\n pre.display.to = pre.display.from + pre.duration;\n post.display.from = pre.display.to;\n post.display.to = post.display.from + post.duration;\n\n return [pre, post];\n }\n\n /**\n * Create a Placeholder instance from a JSON object\n */\n static async fromObject(json: any): Promise<Placeholder> {\n if (json.type !== \"Placeholder\") {\n throw new Error(`Expected Placeholder, got ${json.type}`);\n }\n\n const timing = json.timing || {\n display: json.display || { from: 0, to: 0 },\n trim: json.trim || { from: 0, to: 0 },\n duration: json.duration ?? 0,\n playbackRate: json.playbackRate ?? 1,\n };\n\n const width = json.transform?.width ?? json.width ?? 0;\n const height = json.transform?.height ?? json.height ?? 0;\n\n const clip = new Placeholder(json.src, {\n width,\n height,\n duration: timing.duration,\n });\n\n BaseClip.deserializeBaseProperties(clip, json);\n\n await clip.ready;\n return clip;\n }\n}\n","import { BaseClip } from \"./base-clip\";\nimport { type IClip } from \"./iclip\";\nimport { type TransitionKey } from \"../transition/glsl/gl-transition\";\n\nexport class Transition extends BaseClip {\n readonly type = \"Transition\";\n ready: IClip[\"ready\"];\n\n private _meta = {\n duration: 2e6, // Default 2 seconds\n width: 0,\n height: 0,\n };\n\n get meta() {\n return { ...this._meta };\n }\n\n /**\n * Unique identifier for this clip instance\n */\n id: string = `clip_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\n /**\n * The transition key\n */\n transitionKey: TransitionKey;\n\n /**\n * ID of the clip from which the transition starts\n */\n fromClipId: string | null = null;\n\n /**\n * ID of the clip to which the transition ends\n */\n toClipId: string | null = null;\n\n /**\n * Custom shader parameter values (uniform name -> value)\n */\n values: Record<string, any> = {};\n\n constructor(transitionKey: TransitionKey) {\n super();\n this.transitionKey = transitionKey;\n\n // Ready immediately\n this.ready = Promise.resolve(this._meta);\n this.duration = this._meta.duration;\n }\n\n async clone() {\n const newClip = new Transition(this.transitionKey);\n this.copyStateTo(newClip);\n newClip.fromClipId = this.fromClipId;\n newClip.toClipId = this.toClipId;\n newClip.values = JSON.parse(JSON.stringify(this.values));\n return newClip as this;\n }\n\n // Transition is invisible (it's applied via renderer logic), so it returns empty/dummy data\n async tick(_time: number): Promise<{\n video: ImageBitmap | undefined;\n state: \"success\";\n }> {\n return {\n video: undefined,\n state: \"success\",\n };\n }\n\n async split(_time: number): Promise<[this, this]> {\n const clone1 = await this.clone();\n const clone2 = await this.clone();\n return [clone1, clone2];\n }\n\n toJSON(_main: boolean = false): any {\n return {\n id: this.id,\n type: \"Transition\",\n name: this.name,\n timing: {\n display: {\n from: this.timing.display.from,\n to: this.timing.display.to,\n },\n trim: {\n from: this.timing.trim.from,\n to: this.timing.trim.to,\n },\n duration: this.timing.duration,\n playbackRate: this.timing.playbackRate,\n },\n transitionKey: this.transitionKey,\n fromClipId: this.fromClipId,\n toClipId: this.toClipId,\n ...(Object.keys(this.values).length > 0 && { values: this.values }),\n };\n }\n\n /**\n * Create a Transition instance from a JSON object\n */\n static async fromObject(json: any): Promise<Transition> {\n if (json.type !== \"Transition\") {\n throw new Error(`Expected Transition, got ${json.type}`);\n }\n\n const key = json.transitionKey;\n if (!key) {\n throw new Error(`Missing transitionKey in Transition JSON`);\n }\n\n const clip = new Transition(key);\n clip.fromClipId = json.fromClipId || null;\n clip.toClipId = json.toClipId || null;\n clip.values = json.values || {};\n\n BaseClip.deserializeBaseProperties(clip, json);\n\n await clip.ready;\n return clip;\n }\n}\n","import { Graphics, RenderTexture, type Application } from \"pixi.js\";\nimport { BaseClip } from \"./base-clip\";\nimport { nanoid } from \"nanoid\";\nimport type { ShapeType, IShapeStyle } from \"@agrhub/core\";\nimport type { IClipMeta } from \"./iclip\";\n\nexport interface ShapeClipOptions {\n shapeType: ShapeType;\n width?: number;\n height?: number;\n fill?: string;\n fillOpacity?: number;\n stroke?: {\n color: string;\n width: number;\n };\n borderRadius?: number;\n renderer?: Application[\"renderer\"];\n}\n\n/**\n * ShapeClip renders rectangle shapes using Pixi.js Graphics\n */\nexport class ShapeClip extends BaseClip {\n readonly type = \"Shape\";\n\n public shapeType: ShapeType;\n public graphics: Graphics;\n private _meta: IClipMeta;\n private renderTexture: RenderTexture | null = null;\n private externalRenderer: Application[\"renderer\"] | null = null;\n\n constructor(options: ShapeClipOptions) {\n super();\n this.shapeType = options.shapeType;\n this.id = nanoid();\n this.name = `${options.shapeType} Shape`;\n this.src = `shape://${options.shapeType}`;\n\n // Store external renderer if provided\n this.externalRenderer = options.renderer ?? null;\n\n // Set dimensions\n this.width = options.width ?? 200;\n this.height = options.height ?? 200;\n\n // Initialize graphics\n this.graphics = new Graphics();\n\n // Set meta\n this._meta = {\n width: this.width,\n height: this.height,\n duration: 0, // Shapes have no duration by default\n };\n\n // Set style from options\n this.style = {\n fill: options.fill ?? \"#3b82f6\",\n fillOpacity: options.fillOpacity ?? 1,\n stroke: options.stroke ?? { color: \"#1e40af\", width: 2 },\n borderRadius: options.borderRadius ?? 0,\n };\n\n // Set ready promise - doesn't need renderer yet\n this.ready = Promise.resolve(this._meta);\n }\n\n private async getRenderer(): Promise<Application[\"renderer\"]> {\n if (this.externalRenderer != null) return this.externalRenderer;\n throw new Error(\n \"ShapeClip: No renderer available. Provide a renderer via options.renderer or setRenderer().\",\n );\n }\n\n /**\n * Set an external renderer (e.g., from Studio)\n */\n setRenderer(renderer: Application[\"renderer\"]): void {\n this.externalRenderer = renderer;\n }\n\n /**\n * Get or create the render texture for this shape\n */\n private async getRenderTexture(): Promise<RenderTexture> {\n if (this.renderTexture == null) {\n this.renderTexture = RenderTexture.create({\n width: Math.ceil(this.width),\n height: Math.ceil(this.height),\n });\n }\n // Resize if dimensions changed\n if (\n this.renderTexture.width !== Math.ceil(this.width) ||\n this.renderTexture.height !== Math.ceil(this.height)\n ) {\n this.renderTexture.resize(Math.ceil(this.width), Math.ceil(this.height));\n }\n return this.renderTexture;\n }\n\n get meta(): IClipMeta {\n return this._meta;\n }\n\n private drawShape(): void {\n const style = this.style as IShapeStyle;\n\n this.graphics.clear();\n\n // Draw rectangle (only shape type supported)\n this.drawRectangle(style);\n\n // Fill and stroke the path (Pixi v8: fill/stroke after drawing)\n if (style.fill) {\n const fillColor = this.hexToNumber(style.fill);\n this.graphics.fill({\n color: fillColor,\n alpha: style.fillOpacity ?? 1,\n });\n }\n\n if (style.stroke) {\n const strokeColor = this.hexToNumber(style.stroke.color);\n this.graphics.stroke({\n color: strokeColor,\n width: style.stroke.width,\n alpha: 1,\n });\n }\n }\n\n private drawRectangle(style: IShapeStyle): void {\n const borderRadius = style.borderRadius ?? 0;\n if (borderRadius > 0) {\n this.graphics.roundRect(\n -this.width / 2,\n -this.height / 2,\n this.width,\n this.height,\n borderRadius,\n );\n } else {\n this.graphics.rect(-this.width / 2, -this.height / 2, this.width, this.height);\n }\n }\n\n private hexToNumber(hex: string): number {\n const hexStr = hex.startsWith(\"#\") ? hex.slice(1) : hex;\n return parseInt(hexStr, 16);\n }\n\n async tick(_time: number): Promise<{\n video: ImageBitmap;\n state: \"success\";\n }> {\n await this.ready;\n\n // Get or create render texture (requires renderer to be set)\n const renderTexture = await this.getRenderTexture();\n\n // Ensure shape is drawn (drawShape clears and redraws)\n this.drawShape();\n\n // Render graphics to render texture\n const renderer = await this.getRenderer();\n\n // Position graphics to center in the render texture\n this.graphics.x = this.width / 2;\n this.graphics.y = this.height / 2;\n\n renderer.render({\n container: this.graphics,\n target: renderTexture,\n });\n\n // Extract ImageBitmap from render texture\n const source = renderTexture.source?.resource?.source;\n let imageBitmap: ImageBitmap;\n if (source instanceof HTMLCanvasElement || source instanceof OffscreenCanvas) {\n imageBitmap = await createImageBitmap(source);\n } else {\n // Fallback: extract canvas\n const extract = renderer.extract;\n const extractedCanvas = extract.canvas(renderTexture);\n if (\n extractedCanvas instanceof HTMLCanvasElement ||\n extractedCanvas instanceof OffscreenCanvas\n ) {\n imageBitmap = await createImageBitmap(extractedCanvas);\n } else {\n throw new Error(\"Unable to extract canvas from render texture\");\n }\n }\n\n return { video: imageBitmap, state: \"success\" };\n }\n\n async clone(): Promise<this> {\n const cloned = new ShapeClip({\n shapeType: this.shapeType,\n width: this.width,\n height: this.height,\n fill: (this.style as any).fill,\n fillOpacity: (this.style as any).fillOpacity,\n stroke: (this.style as any).stroke,\n borderRadius: (this.style as any).borderRadius,\n }) as this;\n\n // Copy transform properties\n cloned.left = this.left;\n cloned.top = this.top;\n cloned.angle = this.angle;\n cloned.opacity = this.opacity;\n cloned.zIndex = this.zIndex;\n\n // Copy timing properties (needed for compositor export)\n cloned.display = { ...this.display };\n cloned.duration = this.duration;\n cloned.timing = { ...this.timing };\n\n return cloned;\n }\n\n async split(_time: number): Promise<[this, this]> {\n // For shapes, splitting creates two identical shapes\n const first = await this.clone();\n const second = await this.clone();\n\n return [first, second];\n }\n\n toJSON(main: boolean = false): any {\n const baseJSON = super.toJSON(main);\n return {\n ...baseJSON,\n shapeType: this.shapeType,\n };\n }\n\n // Override style setter to redraw shape when style changes\n set style(style: any) {\n super.style = style;\n if (this.graphics) {\n this.drawShape();\n }\n }\n\n get style(): any {\n return super.style;\n }\n\n // Override dimension setters to redraw shape and resize texture\n set width(width: number) {\n super.width = width;\n if (this.graphics) {\n this.drawShape();\n }\n if (this.renderTexture) {\n this.renderTexture.resize(Math.ceil(this.width), Math.ceil(this.height));\n }\n }\n\n get width(): number {\n return super.width;\n }\n\n set height(height: number) {\n super.height = height;\n if (this.graphics) {\n this.drawShape();\n }\n if (this.renderTexture) {\n this.renderTexture.resize(Math.ceil(this.width), Math.ceil(this.height));\n }\n }\n\n get height(): number {\n return super.height;\n }\n\n /**\n * Create ShapeClip from JSON object\n */\n static async fromObject(json: any): Promise<ShapeClip> {\n const shape = new ShapeClip({\n shapeType: json.shapeType,\n width: json.transform?.width,\n height: json.transform?.height,\n fill: json.style?.fill,\n fillOpacity: json.style?.fillOpacity,\n stroke: json.style?.stroke,\n borderRadius: json.style?.borderRadius,\n });\n\n BaseClip.deserializeBaseProperties(shape, json);\n\n return shape;\n }\n}\n","import {\n BlurFilter,\n Container,\n FillGradient,\n Graphics,\n RenderTexture,\n Sprite,\n Texture,\n TilingSprite,\n type Application,\n} from \"pixi.js\";\nimport { nanoid } from \"nanoid\";\nimport { BaseClip } from \"./base-clip\";\nimport type { IClipMeta } from \"./iclip\";\nimport { parseColor } from \"../utils/color\";\n\nexport interface BackdropClipOptions {\n backdropType: \"solid\" | \"gradient\" | \"meshGradient\" | \"noise\" | \"floatingBlobs\";\n width?: number;\n height?: number;\n colors?: string[];\n gradientType?: \"linear\" | \"radial\";\n speed?: number;\n scale?: number;\n density?: number;\n renderer?: Application[\"renderer\"];\n}\n\ninterface FloatingCircle {\n graphics: Graphics;\n baseX: number;\n baseY: number;\n phase: number;\n speedX: number;\n speedY: number;\n radius: number;\n}\n\nconst DEFAULT_COLORS = [\"#6A5AF9\", \"#B14EFF\", \"#FF7A7A\"];\n\n/**\n * Backdrop: procedural, endlessly playing background (solid, gradient, animated mesh gradient,\n * floating blobs, film noise) rendered with Pixi into a texture.\n */\nexport class Backdrop extends BaseClip {\n readonly type = \"Backdrop\";\n\n public backdropType: BackdropClipOptions[\"backdropType\"];\n public container: Container;\n private _meta: IClipMeta;\n private renderTexture: RenderTexture | null = null;\n private externalRenderer: Application[\"renderer\"] | null = null;\n\n // Cached elements for animations\n private bgGraphics: Graphics | null = null;\n private meshContainer: Container | null = null;\n private meshCircles: FloatingCircle[] = [];\n private blobsContainer: Container | null = null;\n private blobCircles: FloatingCircle[] = [];\n private noiseSprite: TilingSprite | null = null;\n private noiseTexture: Texture | null = null;\n\n constructor(options: BackdropClipOptions) {\n super();\n this.backdropType = options.backdropType;\n this.id = nanoid();\n this.name = `${options.backdropType} Backdrop`;\n this.src = `backdrop://${options.backdropType}`;\n this.externalRenderer = options.renderer ?? null;\n this.width = options.width ?? 1280;\n this.height = options.height ?? 720;\n this.container = new Container();\n this.container.label = \"BackdropContainer\";\n this._meta = {\n width: this.width,\n height: this.height,\n duration: Infinity, // backdrops can play indefinitely\n };\n this.style = {\n backdropType: options.backdropType,\n colors: options.colors ?? DEFAULT_COLORS,\n gradientType: options.gradientType ?? \"linear\",\n speed: options.speed ?? 1,\n scale: options.scale ?? 1,\n density: options.density ?? 8,\n };\n this.ready = Promise.resolve(this._meta);\n this.rebuildBackdrop();\n }\n\n setRenderer(renderer: Application[\"renderer\"]): void {\n this.externalRenderer = renderer;\n }\n\n private async getRenderer(): Promise<Application[\"renderer\"]> {\n if (this.externalRenderer != null) return this.externalRenderer;\n throw new Error(\"BackdropClip: No renderer available. Provide a renderer via options.renderer or setRenderer().\");\n }\n\n private async getRenderTexture(): Promise<RenderTexture> {\n const w = Math.max(1, Math.ceil(this.width));\n const h = Math.max(1, Math.ceil(this.height));\n if (this.renderTexture == null) this.renderTexture = RenderTexture.create({ width: w, height: h });\n if (this.renderTexture.width !== w || this.renderTexture.height !== h) this.renderTexture.resize(w, h);\n return this.renderTexture;\n }\n\n get meta(): IClipMeta {\n return this._meta;\n }\n\n /**\n * Rebuilds the static structure of the backdrop based on current styles.\n */\n private rebuildBackdrop(): void {\n this.container.removeChildren();\n this.bgGraphics = null;\n this.meshContainer = null;\n this.meshCircles = [];\n this.blobsContainer = null;\n this.blobCircles = [];\n this.noiseSprite = null;\n\n const style = this.style;\n const type = style.backdropType || this.backdropType;\n this.backdropType = type;\n const cssColors: string[] = style.colors || [\"#6A5AF9\"];\n const colors = cssColors.map((c) => parseColor(c) ?? 0xffffff);\n const fillBase = () => {\n this.bgGraphics = new Graphics();\n this.bgGraphics.rect(0, 0, this.width, this.height).fill({ color: colors[0] });\n this.container.addChild(this.bgGraphics);\n };\n\n if (type === \"solid\") {\n fillBase();\n } else if (type === \"gradient\") {\n if ((style.gradientType ?? \"linear\") === \"radial\") {\n const canvas = document.createElement(\"canvas\");\n canvas.width = Math.max(1, Math.ceil(this.width));\n canvas.height = Math.max(1, Math.ceil(this.height));\n const ctx = canvas.getContext(\"2d\")!;\n const cx = this.width / 2, cy = this.height / 2;\n const radius = Math.min(this.width, this.height) / 2;\n const gradient = ctx.createRadialGradient(cx, cy, 0, cx, cy, radius);\n cssColors.forEach((c, i) => gradient.addColorStop(i / Math.max(1, cssColors.length - 1), c));\n ctx.fillStyle = gradient;\n ctx.fillRect(0, 0, this.width, this.height);\n this.container.addChild(new Sprite(Texture.from(canvas)));\n } else {\n this.bgGraphics = new Graphics();\n const gradient = new FillGradient(0, 0, this.width, this.height);\n colors.forEach((c, i) => gradient.addColorStop(i / Math.max(1, colors.length - 1), c));\n this.bgGraphics.rect(0, 0, this.width, this.height).fill(gradient);\n this.container.addChild(this.bgGraphics);\n }\n } else if (type === \"meshGradient\") {\n fillBase();\n this.meshContainer = new Container();\n this.meshContainer.label = \"MeshContainer\";\n const count = Math.max(3, colors.length);\n const blur = Math.max(this.width, this.height) * 0.35;\n this.meshContainer.filters = [new BlurFilter({ strength: blur })];\n for (let i = 0; i < count; i++) {\n const g = new Graphics();\n const radius = Math.max(this.width, this.height) * (0.35 + Math.random() * 0.15);\n g.circle(0, 0, radius).fill({ color: colors[i % colors.length], alpha: 0.8 });\n const circle: FloatingCircle = {\n graphics: g,\n baseX: this.width * (0.2 + Math.random() * 0.6),\n baseY: this.height * (0.2 + Math.random() * 0.6),\n phase: Math.random() * Math.PI * 2,\n speedX: 0.3 + Math.random() * 0.4,\n speedY: 0.3 + Math.random() * 0.4,\n radius,\n };\n g.x = circle.baseX;\n g.y = circle.baseY;\n this.meshContainer.addChild(g);\n this.meshCircles.push(circle);\n }\n this.container.addChild(this.meshContainer);\n } else if (type === \"floatingBlobs\") {\n fillBase();\n this.blobsContainer = new Container();\n this.blobsContainer.label = \"BlobsContainer\";\n const count = Math.max(4, style.density ?? 8);\n const blobColors = colors.slice(1).length > 0 ? colors.slice(1) : colors;\n const blur = Math.max(this.width, this.height) * 0.08;\n this.blobsContainer.filters = [new BlurFilter({ strength: blur })];\n for (let i = 0; i < count; i++) {\n const g = new Graphics();\n const radius = Math.max(this.width, this.height) * (0.1 + Math.random() * 0.12);\n g.circle(0, 0, radius).fill({ color: blobColors[i % blobColors.length], alpha: 0.6 });\n const blob: FloatingCircle = {\n graphics: g,\n baseX: this.width * Math.random(),\n baseY: this.height * Math.random(),\n phase: Math.random() * Math.PI * 2,\n speedX: 0.2 + Math.random() * 0.3,\n speedY: 0.2 + Math.random() * 0.3,\n radius,\n };\n g.x = blob.baseX;\n g.y = blob.baseY;\n this.blobsContainer.addChild(g);\n this.blobCircles.push(blob);\n }\n this.container.addChild(this.blobsContainer);\n } else if (type === \"noise\") {\n fillBase();\n if (!this.noiseTexture) {\n const canvas = document.createElement(\"canvas\");\n canvas.width = 256;\n canvas.height = 256;\n const ctx = canvas.getContext(\"2d\")!;\n const image = ctx.createImageData(256, 256);\n const data = image.data;\n for (let i = 0; i < data.length; i += 4) {\n const v = Math.floor(Math.random() * 255);\n data[i] = v;\n data[i + 1] = v;\n data[i + 2] = v;\n data[i + 3] = 18;\n }\n ctx.putImageData(image, 0, 0);\n this.noiseTexture = Texture.from(canvas);\n }\n this.noiseSprite = new TilingSprite({ texture: this.noiseTexture, width: this.width, height: this.height });\n this.noiseSprite.tileScale.set(style.scale ?? 1);\n this.container.addChild(this.noiseSprite);\n }\n }\n\n async tick(time: number): Promise<{ video: ImageBitmap; state: \"success\" }> {\n await this.ready;\n const target = await this.getRenderTexture();\n const renderer = await this.getRenderer();\n const t = (time / 1e6) * (this.style.speed ?? 1);\n\n if (this.backdropType === \"meshGradient\" && this.meshCircles.length > 0) {\n const scale = this.style.scale ?? 1;\n for (const c of this.meshCircles) {\n const ax = t * c.speedX + c.phase;\n const ay = t * c.speedY + c.phase * 1.5;\n c.graphics.x = c.baseX + Math.cos(ax) * (this.width * 0.25 * scale);\n c.graphics.y = c.baseY + Math.sin(ay) * (this.height * 0.25 * scale);\n }\n }\n if (this.backdropType === \"floatingBlobs\" && this.blobCircles.length > 0) {\n const scale = this.style.scale ?? 1;\n for (const c of this.blobCircles) {\n const ax = t * c.speedX + c.phase;\n const ay = t * c.speedY + c.phase * 1.3;\n c.graphics.x = (c.baseX + Math.sin(ax) * (this.width * 0.35 * scale) + this.width) % this.width;\n c.graphics.y = (c.baseY + Math.cos(ay) * (this.height * 0.35 * scale) + this.height) % this.height;\n }\n }\n if (this.backdropType === \"noise\" && this.noiseSprite) {\n this.noiseSprite.tilePosition.x = Math.random() * 256;\n this.noiseSprite.tilePosition.y = Math.random() * 256;\n }\n\n renderer.render({ container: this.container, target });\n\n const source = (target as any).source?.resource?.source;\n let video: ImageBitmap;\n if (source instanceof HTMLCanvasElement || source instanceof OffscreenCanvas) {\n video = await createImageBitmap(source);\n } else {\n const canvas = renderer.extract.canvas(target);\n if (canvas instanceof HTMLCanvasElement || canvas instanceof OffscreenCanvas) {\n video = await createImageBitmap(canvas);\n } else {\n throw new Error(\"Unable to extract canvas from render texture\");\n }\n }\n return { video, state: \"success\" };\n }\n\n async clone(): Promise<this> {\n const copy = new Backdrop({\n backdropType: this.backdropType,\n width: this.width,\n height: this.height,\n colors: this.style.colors,\n gradientType: this.style.gradientType,\n speed: this.style.speed,\n scale: this.style.scale,\n density: this.style.density,\n });\n copy.left = this.left;\n copy.top = this.top;\n copy.angle = this.angle;\n copy.opacity = this.opacity;\n copy.zIndex = this.zIndex;\n copy.display = { ...this.display };\n copy.duration = this.duration;\n (copy as any).timing = { ...(this as any).timing };\n return copy as this;\n }\n\n async split(_time: number): Promise<[this, this]> {\n return [await this.clone(), await this.clone()];\n }\n\n toJSON(main: boolean = false): any {\n return { ...super.toJSON(main), backdropType: this.backdropType };\n }\n\n set style(style: any) {\n super.style = style;\n if (this.container) this.rebuildBackdrop();\n }\n\n get style(): any {\n return super.style;\n }\n\n set width(width: number) {\n super.width = width;\n if (this.container) this.rebuildBackdrop();\n this.renderTexture?.resize(Math.max(1, Math.ceil(this.width)), Math.max(1, Math.ceil(this.height)));\n }\n\n get width(): number {\n return super.width;\n }\n\n set height(height: number) {\n super.height = height;\n if (this.container) this.rebuildBackdrop();\n this.renderTexture?.resize(Math.max(1, Math.ceil(this.width)), Math.max(1, Math.ceil(this.height)));\n }\n\n get height(): number {\n return super.height;\n }\n\n static async fromObject(json: any): Promise<Backdrop> {\n const clip = new Backdrop({\n backdropType: json.backdropType,\n width: json.transform?.width,\n height: json.transform?.height,\n colors: json.style?.colors,\n gradientType: json.style?.gradientType,\n speed: json.style?.speed,\n scale: json.style?.scale,\n density: json.style?.density,\n });\n BaseClip.deserializeBaseProperties(clip, json);\n return clip;\n }\n}\n","import type { IClip } from \"./iclip\";\nimport { Video } from \"./video-clip\";\nimport { Audio } from \"./audio-clip\";\nimport { Image } from \"./image-clip\";\nimport { Text } from \"./text-clip\";\nimport { Caption } from \"./caption-clip\";\nimport { Effect } from \"./effect-clip\";\nimport { Transition } from \"./transition-clip\";\nimport { Placeholder } from \"./placeholder-clip\";\nimport { ShapeClip } from \"./shape-clip\";\nimport { Backdrop } from \"./backdrop-clip\";\n\nexport interface TrackCaptionConfig {\n style?: Record<string, any>;\n colors?: {\n active?: {\n color?: string;\n background?: string;\n border?: { color?: string; width?: number };\n } | null;\n future?: { color?: string; border?: { color?: string; width?: number } } | null;\n keyword?: { color?: string; preserveAfterSpoken?: boolean } | null;\n };\n positioning?: { videoWidth?: number; videoHeight?: number; bottomOffset?: number };\n wordsPerLine?: \"single\" | \"multiple\";\n}\n\nexport interface ClipContext {\n captionConfig?: TrackCaptionConfig;\n}\n\nexport type ClipClass = {\n fromObject(json: any, context?: ClipContext): Promise<IClip>;\n};\n\n/**\n * Registry mapping clip type strings to their class constructors.\n * Supports default core clips and dynamic registration of custom clip types.\n */\nexport class ClipRegistry {\n private static registry = new Map<string, ClipClass>();\n\n /**\n * Register a clip class under a type name.\n */\n static register(type: string, klass: ClipClass) {\n this.registry.set(type, klass);\n }\n\n /**\n * Retrieve the registered clip class for a type.\n */\n static get(type: string): ClipClass | undefined {\n return this.registry.get(type);\n }\n\n /**\n * Get all registered clip types.\n */\n static getRegisteredTypes(): string[] {\n return Array.from(this.registry.keys());\n }\n}\n\n// Automatically register all core clip types\nClipRegistry.register(\"Video\", Video);\nClipRegistry.register(\"Audio\", Audio);\nClipRegistry.register(\"Image\", Image);\nClipRegistry.register(\"Text\", Text);\nClipRegistry.register(\"Caption\", Caption);\nClipRegistry.register(\"Effect\", Effect);\nClipRegistry.register(\"Transition\", Transition);\nClipRegistry.register(\"Placeholder\", Placeholder);\nClipRegistry.register(\"Shape\", ShapeClip);\nClipRegistry.register(\"Backdrop\", Backdrop);\n","export function autoReadStream<ST extends ReadableStream>(\n stream: ST,\n cbs: {\n onChunk: ST extends ReadableStream<infer DT> ? (chunk: DT) => Promise<void> : never;\n onDone: () => void;\n },\n) {\n let stoped = false;\n async function run() {\n const reader = stream.getReader();\n\n while (!stoped) {\n const { value, done } = await reader.read();\n if (done) {\n cbs.onDone();\n return;\n }\n await cbs.onChunk(value);\n }\n\n reader.releaseLock();\n await stream.cancel();\n }\n\n run().catch(console.error);\n\n return () => {\n stoped = true;\n };\n}\n","import { MP4ArrayBuffer, MP4File, MP4Info, MP4Sample, mp4box } from \"wrapbox\";\n\nexport type TransformChunk =\n | { chunkType: \"ready\"; data: { info: MP4Info; file: MP4File } }\n | {\n chunkType: \"samples\";\n data: { id: number; type: \"video\" | \"audio\"; samples: MP4Sample[] };\n };\n\n/**\n * Transforms a raw byte stream into an MP4Sample stream using mp4box.js.\n */\nexport class SampleTransform {\n public readonly readable: ReadableStream<TransformChunk>;\n public readonly writable: WritableStream<Uint8Array>;\n\n private inputBufOffset = 0;\n private isStreamCancelled = false;\n\n constructor() {\n const file = mp4box.createFile() as unknown as MP4File;\n\n this.readable = new ReadableStream<TransformChunk>(\n {\n start: (controller) => this.initMP4Box(file, controller),\n cancel: () => {\n this.isStreamCancelled = true;\n file.stop();\n },\n },\n { highWaterMark: 50 }, // Each chunk typically contains 100 samples\n );\n\n this.writable = new WritableStream<Uint8Array>({\n write: async (chunk) => {\n if (this.isStreamCancelled) {\n throw new Error(\"Stream cancelled\");\n }\n\n const buffer = chunk.buffer as MP4ArrayBuffer;\n buffer.fileStart = this.inputBufOffset;\n this.inputBufOffset += buffer.byteLength;\n file.appendBuffer(buffer);\n },\n close: () => {\n file.flush();\n file.stop();\n // Invoke onFlush if defined to signal completion\n (file as any).onFlush?.();\n },\n abort: (reason) => {\n Log.error(\"SampleTransform writable aborted:\", reason);\n file.stop();\n },\n });\n }\n\n private initMP4Box(file: MP4File, controller: ReadableStreamDefaultController<TransformChunk>) {\n file.onReady = (info: MP4Info) => {\n // Set extraction options for video and audio tracks\n [info.videoTracks[0], info.audioTracks[0]].forEach((track) => {\n if (track) {\n file.setExtractionOptions(track.id, (track as any).video ? \"video\" : \"audio\", {\n nbSamples: 100,\n });\n }\n });\n\n controller.enqueue({ chunkType: \"ready\", data: { info, file } });\n file.start();\n };\n\n const releasedSamplesCount: Record<number, number> = {};\n\n file.onSamples = (id: number, type: \"video\" | \"audio\", samples: MP4Sample[]) => {\n // Create independent copies of samples to ensure safe transfer\n const samplesCopy = samples.map((s) => ({ ...s }));\n\n controller.enqueue({\n chunkType: \"samples\",\n data: { id, type, samples: samplesCopy },\n });\n\n // Release processed samples to free memory\n releasedSamplesCount[id] = (releasedSamplesCount[id] ?? 0) + samples.length;\n file.releaseUsedSamples(id, releasedSamplesCount[id]);\n };\n\n (file as any).onFlush = () => {\n controller.close();\n };\n\n file.onError = (err) => {\n controller.error(new Error(`mp4box error: ${err}`));\n };\n }\n}\n\n// Internal Log placeholder since it might not be imported\nconst Log = {\n error: (...args: any[]) => console.error(\"[SampleTransform]\", ...args),\n};\n","import { mp4box, MP4File, MP4Sample, SampleOpts, TrakBoxParser } from \"wrapbox\";\nimport { tmpfile, write } from \"opfs-tools\";\nimport { DEFAULT_AUDIO_CONF } from \"../clips\";\nimport { autoReadStream } from \"../utils/stream-utils\";\nimport { Log } from \"../utils/log\";\nimport {\n concatPCMFragments,\n extractPCM4AudioBuffer,\n extractPCM4AudioData,\n mixinPCM,\n ringSliceFloat32Array,\n} from \"../utils\";\nimport { extractFileConfig } from \"./mp4box-utils\";\nimport { SampleTransform } from \"./sample-transform\";\n\nfunction fixMP4BoxFileDuration(\n inMP4File: MP4File,\n): () => Promise<ReadableStream<Uint8Array> | null> {\n let sentBoxIdx = 0;\n const boxes = inMP4File.boxes;\n const tracks: Array<{ track: TrakBoxParser; id: number }> = [];\n let totalDuration = 0;\n\n async function write2TmpFile() {\n const buf = box2Buf(boxes, sentBoxIdx);\n sentBoxIdx = boxes.length;\n // Release references to avoid memory leaks\n // todo: use unsafeReleaseMP4BoxFile\n tracks.forEach(({ track, id }) => {\n const s = track.samples.at(-1);\n if (s != null) totalDuration = Math.max(totalDuration, s.cts + s.duration);\n\n inMP4File.releaseUsedSamples(id, track.samples.length);\n track.samples = [];\n });\n inMP4File.mdats = [];\n inMP4File.moofs = [];\n if (buf != null) await tmpFileWriter?.write(buf);\n }\n\n let moovPrevBoxes: typeof boxes = [];\n function moovBoxReady() {\n if (moovPrevBoxes.length > 0) return true;\n\n const moovIdx = boxes.findIndex((box: any) => box.type === \"moov\");\n if (moovIdx === -1) return false;\n\n moovPrevBoxes = boxes.slice(0, moovIdx + 1);\n sentBoxIdx = moovIdx + 1;\n\n if (tracks.length === 0) {\n for (let i = 1; true; i += 1) {\n const track = inMP4File.getTrackById(i);\n if (track == null) break;\n tracks.push({ track, id: i });\n }\n }\n\n return true;\n }\n\n let timerId = 0;\n // Write boxes other than moov to temp file first, then concatenate temp file after updating duration\n const postFile = tmpfile();\n let tmpFileWriter: Awaited<ReturnType<ReturnType<typeof tmpfile>[\"createWriter\"]>> | null = null;\n\n const initPromise = (async () => {\n tmpFileWriter = await postFile.createWriter();\n\n timerId = self.setInterval(() => {\n if (!moovBoxReady()) return;\n write2TmpFile();\n }, 100);\n })();\n\n let stopped = false;\n return async () => {\n if (stopped) throw Error(\"File exported\");\n stopped = true;\n\n await initPromise;\n clearInterval(timerId);\n\n if (!moovBoxReady() || tmpFileWriter == null) return null;\n inMP4File.flush();\n await write2TmpFile();\n await tmpFileWriter?.close();\n\n const moov = moovPrevBoxes.find((box: any) => box.type === \"moov\") as any;\n if (moov == null) return null;\n\n moov.mvhd.duration = totalDuration;\n\n const resultFile = tmpfile();\n const buf = box2Buf(moovPrevBoxes, 0)!;\n await write(resultFile, buf.slice());\n await write(resultFile, postFile, { overwrite: false });\n\n return await resultFile.stream();\n };\n\n function box2Buf(source: typeof boxes, startIdx: number): Uint8Array<ArrayBuffer> | null {\n if (startIdx >= source.length) return null;\n\n const ds = new mp4box.DataStream();\n\n for (let i = startIdx; i < source.length; i++) {\n if (source[i] === null) continue;\n source[i].write(ds);\n delete source[i];\n }\n return new Uint8Array(ds.buffer).slice() as Uint8Array<ArrayBuffer>;\n }\n}\n\n/**\n * Convert EncodedAudioChunk | EncodedVideoChunk to parameters required by MP4 addSample\n */\nfunction chunk2MP4SampleOpts(chunk: EncodedAudioChunk | EncodedVideoChunk): SampleOpts & {\n data: ArrayBuffer;\n} {\n const buf = new ArrayBuffer(chunk.byteLength);\n chunk.copyTo(buf);\n const dts = chunk.timestamp;\n return {\n duration: chunk.duration ?? 0,\n dts,\n cts: dts,\n is_sync: chunk.type === \"key\",\n data: buf,\n };\n}\n\n/**\n * Quick concatenate multiple MP4 file streams, requires all MP4s to have consistent properties,\n * properties include (but not limited to): audio/video codec format, resolution, sample rate\n *\n * @param streams An array of readable streams containing Uint8Array.\n * @returns Returns a Promise that resolves to a readable stream containing merged MP4 data.\n * @throws Will throw error if unable to generate file from streams.\n *\n * @example\n * const streams = [stream1, stream2, stream3];\n * const resultStream = await fastConcatMP4(streams);\n */\nexport async function fastConcatMP4(\n streams: ReadableStream<Uint8Array>[],\n): Promise<ReadableStream<Uint8Array>> {\n const outfile = mp4box.createFile() as unknown as MP4File;\n\n const dumpFile = fixMP4BoxFileDuration(outfile);\n await concatStreamsToMP4BoxFile(streams, outfile);\n const outStream = await dumpFile();\n if (outStream == null) throw Error(\"Can not generate file from streams\");\n return outStream;\n}\n\nasync function concatStreamsToMP4BoxFile(streams: ReadableStream<Uint8Array>[], outfile: MP4File) {\n let vTrackId = 0;\n let vDTS = 0;\n let vCTS = 0;\n let aTrackId = 0;\n let aDTS = 0;\n let aCTS = 0;\n // ts bug, cannot correctly identify type\n let lastVSamp: any = null;\n let lastASamp: any = null;\n for (const stream of streams) {\n // Reset first sample timestamps for each stream to enable normalization\n let firstVDTS: number | null = null;\n let firstVCTS: number | null = null;\n let firstADTS: number | null = null;\n let firstACTS: number | null = null;\n\n await new Promise<void>(async (resolve) => {\n autoReadStream(stream.pipeThrough(new SampleTransform()), {\n onDone: resolve,\n onChunk: async ({ chunkType, data }) => {\n if (chunkType === \"ready\") {\n const { videoTrackConf, audioTrackConf } = extractFileConfig(data.file, data.info);\n if (vTrackId === 0 && videoTrackConf != null) {\n vTrackId = outfile.addTrack(videoTrackConf);\n }\n if (aTrackId === 0 && audioTrackConf != null) {\n aTrackId = outfile.addTrack(audioTrackConf);\n }\n } else if (chunkType === \"samples\") {\n const { type, samples } = data;\n const trackId = type === \"video\" ? vTrackId : aTrackId;\n const offsetDTS = type === \"video\" ? vDTS : aDTS;\n const offsetCTS = type === \"video\" ? vCTS : aCTS;\n\n samples.forEach((s) => {\n let normalizedDTS: number;\n let normalizedCTS: number;\n\n if (type === \"video\") {\n // Capture first sample timestamps for normalization\n if (firstVDTS === null) {\n firstVDTS = s.dts;\n firstVCTS = s.cts;\n }\n // Normalize to start from 0, then add offset\n normalizedDTS = s.dts - firstVDTS!;\n normalizedCTS = s.cts - (firstVCTS ?? 0);\n } else {\n // Same for audio\n if (firstADTS === null) {\n firstADTS = s.dts;\n firstACTS = s.cts;\n }\n normalizedDTS = s.dts - firstADTS!;\n normalizedCTS = s.cts - (firstACTS ?? 0);\n }\n\n outfile.addSample(trackId, new Uint8Array(s.data), {\n duration: s.duration,\n dts: normalizedDTS + offsetDTS,\n cts: normalizedCTS + offsetCTS,\n is_sync: s.is_sync,\n });\n });\n\n const lastSamp = samples.at(-1);\n if (lastSamp == null) return;\n if (type === \"video\") {\n lastVSamp = lastSamp;\n } else if (type === \"audio\") {\n lastASamp = lastSamp;\n }\n }\n },\n });\n });\n // Calculate offsets based on normalized timestamps\n if (lastVSamp != null && firstVDTS !== null && firstVCTS !== null) {\n // Duration of this normalized stream\n const normalizedVDTS = lastVSamp.dts - firstVDTS + lastVSamp.duration;\n const normalizedVCTS = lastVSamp.cts - firstVCTS + lastVSamp.duration;\n vDTS += normalizedVDTS;\n vCTS += normalizedVCTS;\n }\n // Coerce audio timing to match video timing by converting video timescale to audio timescale\n if (lastASamp != null && lastVSamp != null) {\n const videoToAudioRatio = lastASamp.timescale / lastVSamp.timescale;\n aDTS = Math.round(vDTS * videoToAudioRatio);\n aCTS = Math.round(vCTS * videoToAudioRatio);\n }\n }\n}\n\n/**\n * Set correct duration value for fMP4 files generated\n */\nexport async function fixFMP4Duration(\n stream: ReadableStream<Uint8Array>,\n): Promise<ReadableStream<Uint8Array>> {\n return await fastConcatMP4([stream]);\n}\n\n/**\n * Create MP4 audio sample decoder.\n * @param decoderConfig - Audio decoder configuration parameter {@link AudioDecoderConfig}.\n * @returns Returns an object containing `decode` and `close` methods.\n * - `decode` method is used to decode MP4 audio samples, returns array of decoded audio data.\n * - `close` method is used to close audio decoder.\n */\nfunction createMP4AudioSampleDecoder(decoderConfig: Parameters<AudioDecoder[\"configure\"]>[0]) {\n let cacheAD: AudioData[] = [];\n const adDecoder = new AudioDecoder({\n output: (ad) => {\n cacheAD.push(ad);\n },\n error: Log.error,\n });\n adDecoder.configure(decoderConfig);\n\n return {\n decode: async (ss: MP4Sample[]) => {\n ss.forEach((s) => {\n adDecoder.decode(\n new EncodedAudioChunk({\n type: s.is_sync ? \"key\" : \"delta\",\n timestamp: (1e6 * s.cts) / s.timescale,\n duration: (1e6 * s.duration) / s.timescale,\n data: s.data,\n }),\n );\n });\n\n await adDecoder.flush();\n\n const result = cacheAD;\n cacheAD = [];\n\n return result;\n },\n close: () => {\n adDecoder.close();\n },\n };\n}\n\n// Audio encoding and decoding APIs have significant differences,\n// because calling AudioEncoder.flush mid-encoding causes audio stuttering\nfunction createMP4AudioSampleEncoder(\n encoderConfig: Parameters<AudioEncoder[\"configure\"]>[0],\n onOutput: (s: ReturnType<typeof chunk2MP4SampleOpts>) => void,\n) {\n const encoderConf = {\n codec: encoderConfig.codec,\n sampleRate: encoderConfig.sampleRate,\n numberOfChannels: encoderConfig.numberOfChannels,\n } as const;\n\n const adEncoder = new AudioEncoder({\n output: (chunk) => {\n onOutput(chunk2MP4SampleOpts(chunk));\n },\n error: (err) => {\n Log.error(\"AudioEncoder error:\", err, \", config:\", encoderConf);\n },\n });\n\n adEncoder.configure(encoderConf);\n\n // Keep one audio data for final audio fade out\n let lastData: { data: Float32Array; ts: number } | null = null;\n\n function createAudioData(data: Float32Array, timestamp: number) {\n return new AudioData({\n timestamp: timestamp,\n numberOfChannels: encoderConfig.numberOfChannels,\n numberOfFrames: data.length / encoderConfig.numberOfChannels,\n sampleRate: encoderConfig.sampleRate,\n format: \"f32-planar\",\n data: new Float32Array(data),\n });\n }\n return {\n encode: async (data: Float32Array, timestamp: number) => {\n if (lastData != null) {\n adEncoder.encode(createAudioData(lastData.data, lastData.ts));\n }\n lastData = { data, ts: timestamp };\n },\n stop: async () => {\n if (lastData != null) {\n // Side effect modifies data\n audioFade(lastData.data, encoderConfig.numberOfChannels, encoderConfig.sampleRate);\n adEncoder.encode(createAudioData(lastData.data, lastData.ts));\n lastData = null;\n }\n await adEncoder.flush();\n adEncoder.close();\n },\n };\n}\n\n/**\n * Audio linear fade out to avoid POP sound\n * Side effect adjusts volume value\n */\nfunction audioFade(pcmData: Float32Array, chanCnt: number, sampleRate: number) {\n const dataLen = pcmData.length - 1;\n // Avoid exceeding boundaries, maximum 500ms fade out time\n const fadeLen = Math.min(sampleRate / 2, dataLen);\n for (let i = 0; i < fadeLen; i++) {\n for (let j = 1; j <= chanCnt; j++) {\n // From tail, adjust each channel volume value\n pcmData[Math.floor(dataLen / j) - i] *= i / fadeLen;\n }\n }\n}\n\n/**\n * Video dubbing; mix MP4 with audio file, only re-encode audio, video track unchanged\n * @param mp4Stream - MP4 stream\n * @param audio - Audio information\n * @param audio.stream - Audio data stream\n * @param audio.volume - Audio volume\n * @param audio.loop - When audio duration is less than video, whether to loop audio stream\n * @returns Output mixed audio stream\n */\nexport function mixinMP4AndAudio(\n mp4Stream: ReadableStream<Uint8Array>,\n audio: {\n stream: ReadableStream<Uint8Array>;\n volume: number;\n loop: boolean;\n },\n) {\n Log.info(\"mixinMP4AndAudio, opts:\", {\n volume: audio.volume,\n loop: audio.loop,\n });\n\n const outfile = mp4box.createFile() as unknown as MP4File;\n\n let outStream: ReadableStream<Uint8Array>;\n let timerId = 0;\n let sendedBoxIdx = 0;\n const boxes = outfile.boxes;\n let firstMoofReady = false;\n\n const deltaBuf = (): Uint8Array | null => {\n if (!firstMoofReady) {\n if (boxes.find((box: any) => box.type === \"moof\") != null) {\n firstMoofReady = true;\n } else {\n return null;\n }\n }\n if (sendedBoxIdx >= boxes.length) return null;\n\n const ds = new mp4box.DataStream();\n\n let i = sendedBoxIdx;\n try {\n for (; i < boxes.length; ) {\n boxes[i].write(ds);\n delete boxes[i];\n i += 1;\n }\n } catch (err) {\n throw err;\n }\n\n if (outfile.moov != null) {\n for (var j = 0; j < outfile.moov.traks.length; j++) {\n outfile.moov.traks[j].samples = [];\n }\n outfile.mdats = [];\n outfile.moofs = [];\n }\n\n sendedBoxIdx = boxes.length;\n return new Uint8Array(ds.buffer);\n };\n\n let stoped = false;\n let canceled = false;\n let exit: ((err?: Error) => void) | null = null;\n outStream = new ReadableStream({\n start(ctrl) {\n timerId = self.setInterval(() => {\n const d = deltaBuf();\n if (d != null && !canceled) ctrl.enqueue(d);\n }, 500);\n\n exit = (err) => {\n clearInterval(timerId);\n outfile.flush();\n if (err != null) {\n ctrl.error(err);\n return;\n }\n\n const d = deltaBuf();\n if (d != null && !canceled) ctrl.enqueue(d);\n\n if (!canceled) ctrl.close();\n };\n },\n cancel() {\n canceled = true;\n clearInterval(timerId);\n },\n });\n\n const stopOut = (err?: Error) => {\n if (stoped) return;\n stoped = true;\n exit?.(err);\n };\n\n let audioSampleDecoder: ReturnType<typeof createMP4AudioSampleDecoder> | null = null;\n\n let audioSampleEncoder: ReturnType<typeof createMP4AudioSampleEncoder> | null = null;\n\n let inputAudioPCM: Float32Array[] = [];\n\n let vTrackId = 0;\n let aTrackId = 0;\n let audioOffset = 0;\n let mp4HasAudio = true;\n let sampleRate = DEFAULT_AUDIO_CONF.sampleRate as number;\n autoReadStream(mp4Stream.pipeThrough(new SampleTransform()), {\n onDone: async () => {\n await audioSampleEncoder?.stop();\n audioSampleDecoder?.close();\n stopOut();\n },\n onChunk: async ({ chunkType, data }) => {\n if (chunkType === \"ready\") {\n const { videoTrackConf, audioTrackConf, audioDecoderConf } = extractFileConfig(\n data.file,\n data.info,\n );\n if (vTrackId === 0 && videoTrackConf != null) {\n vTrackId = outfile.addTrack(videoTrackConf as any);\n }\n\n const safeAudioTrackConf = audioTrackConf ?? {\n timescale: 1e6,\n samplerate: sampleRate,\n channel_count: DEFAULT_AUDIO_CONF.channelCount,\n hdlr: \"soun\",\n name: \"SoundHandler\",\n type: \"mp4a\",\n };\n if (aTrackId === 0) {\n aTrackId = outfile.addTrack(safeAudioTrackConf as any);\n sampleRate = audioTrackConf?.samplerate ?? sampleRate;\n mp4HasAudio = audioTrackConf == null ? false : true;\n }\n const audioCtx = new AudioContext({ sampleRate });\n inputAudioPCM = extractPCM4AudioBuffer(\n await audioCtx.decodeAudioData(await new Response(audio.stream).arrayBuffer()),\n );\n\n if (audioDecoderConf != null) {\n audioSampleDecoder = createMP4AudioSampleDecoder(audioDecoderConf);\n }\n audioSampleEncoder = createMP4AudioSampleEncoder(\n audioDecoderConf ?? {\n codec:\n safeAudioTrackConf.type === \"mp4a\"\n ? DEFAULT_AUDIO_CONF.codec\n : safeAudioTrackConf.type,\n numberOfChannels: safeAudioTrackConf.channel_count,\n sampleRate: safeAudioTrackConf.samplerate,\n },\n (s) => outfile.addSample(aTrackId, new Uint8Array(s.data), s),\n );\n } else if (chunkType === \"samples\") {\n const { id, type, samples } = data;\n if (type === \"video\") {\n samples.forEach((s) => outfile.addSample(id, new Uint8Array(s.data), s));\n\n if (!mp4HasAudio) await addInputAudio2Track(samples);\n return;\n }\n\n if (type === \"audio\") await mixinAudioSampleAndInputPCM(samples);\n }\n },\n });\n\n function getInputAudioSlice(len: number) {\n const result = inputAudioPCM.map((chanBuf) =>\n audio.loop\n ? ringSliceFloat32Array(chanBuf, audioOffset, audioOffset + len)\n : chanBuf.slice(audioOffset, audioOffset + len),\n );\n audioOffset += len;\n\n if (audio.volume !== 1) {\n for (const buf of result) for (let i = 0; i < buf.length; i++) buf[i] *= audio.volume;\n }\n\n return result;\n }\n\n async function addInputAudio2Track(videoSamples: MP4Sample[]) {\n const firstSamp = videoSamples[0];\n const lastSamp = videoSamples[videoSamples.length - 1];\n const pcmLength = Math.floor(\n ((lastSamp.cts + lastSamp.duration - firstSamp.cts) / firstSamp.timescale) * sampleRate,\n );\n const audioDataBuf = mixinPCM([getInputAudioSlice(pcmLength)]);\n if (audioDataBuf.length === 0) return;\n audioSampleEncoder?.encode(audioDataBuf, (firstSamp.cts / firstSamp.timescale) * 1e6);\n }\n\n async function mixinAudioSampleAndInputPCM(samples: MP4Sample[]) {\n if (audioSampleDecoder == null) return;\n\n // 1. First decode MP4 audio\n // [[chan0, chan1], [chan0, chan1]...]\n const pcmFragments = (await audioSampleDecoder.decode(samples)).map(extractPCM4AudioData);\n // [chan0, chan1]\n const mp4AudioPCM = concatPCMFragments(pcmFragments);\n const inputAudioPCM = getInputAudioSlice(mp4AudioPCM[0].length);\n const firstSamp = samples[0];\n\n // 3. Re-encode audio\n audioSampleEncoder?.encode(\n // 2. Mix input audio\n mixinPCM([mp4AudioPCM, inputAudioPCM]),\n (firstSamp.cts / firstSamp.timescale) * 1e6,\n );\n }\n\n return outStream;\n}\n","import {\n ClipRegistry,\n type IClip,\n type ITransitionInfo,\n type ClipContext,\n type IChromaKeyOpts,\n} from \"./clips\";\nimport type { ColorAdjustment } from \"./utils/color-adjustment\";\nimport type { ShapeType } from \"@agrhub/core\";\n\nexport interface ClipTimingJSON {\n display: {\n from: number;\n to: number;\n };\n trim?: {\n from: number;\n to: number;\n };\n duration: number;\n playbackRate: number;\n fadeIn?: {\n duration: number; // ms\n curve?: \"linear\" | \"ease-in\" | \"ease-out\" | \"ease-in-out\";\n };\n fadeOut?: {\n duration: number; // ms\n curve?: \"linear\" | \"ease-in\" | \"ease-out\" | \"ease-in-out\";\n };\n}\n\nexport interface ClipTransformJSON {\n x: number;\n y: number;\n width: number;\n height: number;\n angle: number;\n opacity: number;\n zIndex: number;\n flip?: { x: boolean; y: boolean } | null;\n}\n\n// Base interface for all clips\ninterface BaseClipJSON {\n id?: string;\n name?: string;\n metadata?: Record<string, any>;\n effects?: Array<{\n id: string;\n key: string;\n startTime: number;\n duration: number;\n targets?: number[];\n }>;\n src?: string;\n\n // New nested timing schema\n timing?: ClipTimingJSON;\n\n // New nested transform schema\n transform?: ClipTransformJSON;\n\n // Legacy fields made optional for backward compatibility during deserialization\n display?: {\n from: number;\n to: number;\n };\n playbackRate?: number;\n duration?: number;\n trim?: {\n from: number;\n to: number;\n };\n transition?: ITransitionInfo;\n style?: any;\n locked?: boolean;\n muted?: boolean;\n colorAdjustment?: ColorAdjustment;\n chromaKey?: IChromaKeyOpts;\n\n animation?: {\n keyFrames: Record<\n string,\n Partial<{\n x: number;\n y: number;\n w: number;\n h: number;\n angle: number;\n opacity: number;\n }>\n >;\n options: {\n duration: number;\n delay?: number;\n iterCount?: number;\n };\n };\n animations?: Array<{\n type: string;\n options: any;\n params?: any;\n }>;\n main?: boolean; // For Compositor only\n}\n\n// Visual style (Image, Video, Audio)\nexport interface ClipVisualStyleJSON {\n borderRadius?: number;\n stroke?: { color: string; width: number };\n shadow?: {\n color?: string;\n alpha?: number;\n blur?: number;\n offsetX?: number;\n offsetY?: number;\n };\n}\n\n// Video clip specific\nexport interface VideoJSON extends BaseClipJSON {\n type: \"Video\";\n audio?: boolean;\n volume?: number;\n style?: ClipVisualStyleJSON;\n}\n\n// Audio clip specific\nexport interface AudioJSON extends BaseClipJSON {\n type: \"Audio\";\n loop?: boolean;\n volume?: number;\n style?: ClipVisualStyleJSON;\n}\n\n// Image clip specific\nexport interface ImageJSON extends BaseClipJSON {\n type: \"Image\";\n style?: ClipVisualStyleJSON;\n}\n\n// Text style interface\nexport interface TextStyleJSON {\n fontSize?: number;\n fontFamily?: string;\n fontWeight?: string | number;\n fontStyle?: string;\n color?:\n | string\n | number\n | {\n type: \"gradient\";\n x0: number;\n y0: number;\n x1: number;\n y1: number;\n colors: Array<{ ratio: number; color: string | number }>;\n };\n align?: \"left\" | \"center\" | \"right\";\n fontUrl?: string; // Font URL for custom fonts\n stroke?: {\n color: string | number;\n width: number;\n join?: \"miter\" | \"round\" | \"bevel\";\n cap?: \"butt\" | \"round\" | \"square\";\n miterLimit?: number;\n };\n shadow?: {\n color?: string | number;\n alpha?: number;\n blur?: number;\n offsetX?: number;\n offsetY?: number;\n };\n wordWrap?: boolean;\n wordWrapWidth?: number;\n lineHeight?: number;\n letterSpacing?: number;\n textCase?: \"none\" | \"uppercase\" | \"lowercase\" | \"title\";\n wordsPerLine?: \"single\" | \"multiple\";\n verticalAlign?: \"top\" | \"center\" | \"bottom\";\n wordAnimation?: ICaptionWordAnimation;\n textBoxStyle?: TextBoxStyleJSON;\n appeared?: string;\n active?: string;\n activeFill?: string;\n captionBackground?: string;\n keyword?: string;\n // Text clip per-line background box\n background?: {\n color?: string;\n opacity?: number;\n borderRadius?: number;\n paddingX?: number;\n paddingY?: number;\n };\n}\n\nexport interface ICaptionWordAnimation {\n type: \"scale\" | \"opacity\";\n application: \"active\" | \"keyword\" | \"none\";\n value: number;\n mode?: \"static\" | \"dynamic\";\n}\n\nexport interface TextBoxStyleJSON {\n style?: \"tiktok\" | \"none\";\n textAlign?: \"left\" | \"center\" | \"right\" | \"\";\n maxLines?: number;\n borderRadius?: number;\n horizontalPadding?: number;\n verticalPadding?: number;\n}\n\n// Text clip specific\nexport interface TextJSON extends BaseClipJSON {\n type: \"Text\";\n text: string;\n style?: TextStyleJSON;\n}\n\n// Caption word style (used for active and future)\nexport interface CaptionWordStyleJSON {\n color?: string;\n border?: {\n color?: string;\n width?: number;\n };\n background?: string;\n}\n\n// Caption colors interface\nexport interface CaptionColorsJSON {\n /** Currently spoken word */\n active?: CaptionWordStyleJSON;\n /** Upcoming / future words */\n future?: CaptionWordStyleJSON;\n /** Keyword words */\n keyword?: {\n color?: string;\n preserveAfterSpoken?: boolean;\n };\n}\n\n// Caption positioning interface (new nested structure)\nexport interface CaptionPositioningJSON {\n bottomOffset?: number;\n videoWidth?: number;\n videoHeight?: number;\n}\n\n// Caption data interface (new nested structure)\nexport interface CaptionDataJSON {\n words?: Array<{\n text: string;\n from: number;\n to: number;\n isKeyWord?: boolean;\n paragraphIndex?: number;\n }>;\n colors?: CaptionColorsJSON;\n positioning?: CaptionPositioningJSON;\n wordAnimation?: ICaptionWordAnimation;\n textBoxStyle?: TextBoxStyleJSON;\n}\n\n// Caption clip specific\nexport interface CaptionJSON extends BaseClipJSON {\n type: \"Caption\";\n text: string;\n style?: TextStyleJSON;\n // New nested structure\n caption?: CaptionDataJSON;\n\n fontUrl?: string;\n mediaId?: string;\n wordsPerLine?: \"single\" | \"multiple\";\n textBoxStyle?: TextBoxStyleJSON;\n}\n\n// Effect clip specific\nexport interface EffectJSON extends BaseClipJSON {\n type: \"Effect\";\n effectKey: string;\n values?: Record<string, any>;\n}\n\n// Transition clip specific\nexport interface TransitionJSON extends BaseClipJSON {\n type: \"Transition\";\n transitionKey: string;\n fromClipId?: string | null;\n toClipId?: string | null;\n}\n\n// Placeholder clip specific\nexport interface PlaceholderJSON extends BaseClipJSON {\n type: \"Placeholder\";\n}\n\n// Shape clip specific\nexport interface ShapeJSON extends BaseClipJSON {\n type: \"Shape\";\n shapeType: ShapeType;\n}\n\n// Global Transition interface (applied between clips)\nexport interface GlobalTransitionJSON {\n key: string;\n duration: number;\n clips: string[];\n}\n\n// Union type for all clip types\n\nexport type ClipJSON =\n | VideoJSON\n | AudioJSON\n | ImageJSON\n | TextJSON\n | CaptionJSON\n | EffectJSON\n | TransitionJSON\n | PlaceholderJSON\n | ShapeJSON;\n\nexport interface StudioTrackJSON {\n id: string;\n name: string;\n type: string;\n clipIds: string[];\n muted?: boolean;\n}\n\nexport interface ProjectJSON {\n tracks?: StudioTrackJSON[];\n clips: Record<string, ClipJSON>;\n transition?: GlobalTransitionJSON[];\n transitions?: GlobalTransitionJSON[]; // Alias for transition for better compatibility\n globalEffects?: Array<{\n id: string;\n key: string;\n startTime: number;\n duration: number;\n }>;\n settings?: {\n width?: number;\n height?: number;\n fps?: number;\n duration?: number;\n backgroundColor?: string;\n format?: string;\n videoCodec?: string;\n bitrate?: number;\n audio?: boolean;\n audioCodec?: string;\n audioSampleRate?: number;\n metaDataTags?: Record<string, string>;\n };\n}\n\n/**\n * Normalize a clip's JSON structure to ensure compatibility and migrate old property structures\n */\nexport function normalizeClipJSON(json: ClipJSON): ClipJSON {\n const normalized = { ...json } as any;\n\n if (!normalized.timing) {\n normalized.timing = {\n display: json.display || { from: 0, to: 0 },\n trim: json.trim || { from: 0, to: 0 },\n duration: json.duration ?? 0,\n playbackRate: json.playbackRate ?? 1,\n fadeIn: (json as any).fadeIn,\n fadeOut: (json as any).fadeOut,\n };\n } else {\n normalized.timing = {\n display: normalized.timing.display || { from: 0, to: 0 },\n trim: normalized.timing.trim || { from: 0, to: 0 },\n duration: normalized.timing.duration ?? 0,\n playbackRate: normalized.timing.playbackRate ?? 1,\n fadeIn: normalized.timing.fadeIn ?? (json as any).fadeIn,\n fadeOut: normalized.timing.fadeOut ?? (json as any).fadeOut,\n };\n }\n delete normalized.fadeIn;\n delete normalized.fadeOut;\n\n if (!normalized.transform) {\n const raw = json as any;\n normalized.transform = {\n x: raw.left ?? 0,\n y: raw.top ?? 0,\n width: raw.width ?? 0,\n height: raw.height ?? 0,\n angle: raw.angle ?? 0,\n opacity: raw.opacity ?? 1,\n zIndex: raw.zIndex ?? 0,\n flip: raw.flip || null,\n };\n } else {\n normalized.transform = {\n x: normalized.transform.x ?? 0,\n y: normalized.transform.y ?? 0,\n width: normalized.transform.width ?? 0,\n height: normalized.transform.height ?? 0,\n angle: normalized.transform.angle ?? 0,\n opacity: normalized.transform.opacity ?? 1,\n zIndex: normalized.transform.zIndex ?? 0,\n flip: normalized.transform.flip || null,\n };\n }\n\n if (normalized.style) {\n normalized.style = normalizeClipStyleJSON(normalized.style, json.type);\n }\n\n return normalized as ClipJSON;\n}\n\nexport function normalizeClipStyleJSON(style: any, type: string): any {\n if (!style) return style;\n const normalized = { ...style };\n\n // Unify dropShadow into shadow\n if (normalized.dropShadow) {\n normalized.shadow = normalized.dropShadow;\n delete normalized.dropShadow;\n }\n\n if (normalized.shadow) {\n const shadow = { ...normalized.shadow };\n const hasOffset = shadow.offsetX !== undefined || shadow.offsetY !== undefined;\n const hasLegacy = shadow.distance !== undefined || shadow.angle !== undefined;\n\n if (hasLegacy && !hasOffset) {\n const d = shadow.distance ?? 0;\n const a = shadow.angle ?? 0;\n shadow.offsetX = Math.cos(a) * d;\n shadow.offsetY = Math.sin(a) * d;\n }\n delete shadow.distance;\n delete shadow.angle;\n normalized.shadow = shadow;\n }\n\n if (type === \"Text\" || type === \"Caption\") {\n if (normalized.fill !== undefined) {\n normalized.color = normalized.fill;\n delete normalized.fill;\n }\n }\n\n return normalized;\n}\n\n/**\n * Serialize a clip to JSON format\n * @param clip The clip to serialize\n * @param main Whether this is the main clip (for Compositor)\n */\nexport function clipToJSON(clip: IClip, main: boolean = false): ClipJSON {\n // Use the clip's own toJSON method if available (fabric.js pattern)\n // This allows each clip to control its own serialization and avoid circular references\n return clip.toJSON(main);\n}\n\n/**\n * Deserialize JSON to a clip instance\n * Uses fromObject static method if available (fabric.js pattern), otherwise falls back to manual construction\n */\nexport async function jsonToClip(json: ClipJSON, context?: ClipContext): Promise<IClip> {\n const normalizedJson = normalizeClipJSON(json);\n let clip: IClip;\n\n // Try to use fromObject static method if available (fabric.js pattern)\n const ClipClass = ClipRegistry.get(normalizedJson.type);\n\n if (ClipClass && typeof ClipClass.fromObject === \"function\") {\n clip = await ClipClass.fromObject(normalizedJson, context);\n } else {\n throw new Error(`Unsupported clip type or missing fromObject: ${normalizedJson.type}`);\n }\n\n // Final pass for modular animations to ensure they are always applied\n // (some fromObject implementations might only handle legacy animation)\n if (normalizedJson.animations && Array.isArray(normalizedJson.animations)) {\n clip.clearAnimations();\n for (const anim of normalizedJson.animations) {\n clip.addAnimation(anim.type, anim.options, anim.params);\n }\n }\n\n // Ensure id and name are correct\n if (normalizedJson.id) clip.id = normalizedJson.id;\n if (normalizedJson.name) clip.name = normalizedJson.name;\n if (normalizedJson.metadata) clip.metadata = normalizedJson.metadata;\n\n return clip;\n}\n","/**\n * Yield to the browser's task scheduler without vsync delay.\n *\n * Why MessageChannel instead of setTimeout or Promise.resolve?\n * - `setTimeout(0)` is clamped to ~4 ms and tied to vsync on active tabs.\n * - `await Promise.resolve()` is a microtask (no real yield).\n * - MessageChannel fires a true macrotask at full scheduler speed,\n * so the encoder runs at max CPU throughput on both active & background tabs.\n */\nconst schedulerChannel = new MessageChannel();\n\nexport function yieldToScheduler(): Promise<void> {\n return new Promise((resolve) => {\n schedulerChannel.port1.onmessage = () => resolve();\n schedulerChannel.port2.postMessage(null);\n });\n}\n\n/** Max frames allowed in the VideoEncoder queue before back-pressure kicks in. */\nexport const ENCODER_QUEUE_LIMIT = 20;\n\n/**\n * Wait until the encoder queue drains below the limit.\n * Prevents OOM from too many queued VideoFrames.\n */\nexport async function waitEncoderQueue(getQueueSize: () => number): Promise<void> {\n while (getQueueSize() > ENCODER_QUEUE_LIMIT) {\n await yieldToScheduler();\n }\n}\n","export const ROTATION_MOVEMENT_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float rotationCount; \n\nvoid main(void)\n{\n vec2 center = vec2(0.35, 0.35);\n vec2 uvs = vTextureCoord.xy - center;\n \n // Rotación en función de la cantidad de vueltas\n float angle = uTime * rotationCount * 6.28318530718;\n \n float cosAngle = cos(angle);\n float sinAngle = sin(angle);\n mat2 rotation = mat2(cosAngle, -sinAngle, sinAngle, cosAngle);\n \n uvs = rotation * uvs;\n uvs += center;\n \n if (uvs.x < 0.0 || uvs.x > 1.0 || uvs.y < 0.0 || uvs.y > 1.0) {\n discard;\n }\n \n vec4 fg = texture2D(uTexture, uvs);\n gl_FragColor = fg;\n}\n`;\n\nexport const ROTATION_MOVEMENT_UNIFORMS: Record<string, { value: any; type: string }> = {\n uTime: { value: 0, type: \"f32\" },\n rotationCount: { value: 4.0, type: \"f32\" },\n};\n\nexport const RED_GRADIENT_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime;\n\nvoid main(void)\n{\n vec2 uvs = vTextureCoord.xy;\n\n vec4 fg = texture2D(uTexture, vTextureCoord);\n\n fg.r = uvs.y + sin(uTime);\n\n gl_FragColor = fg;\n\n}\n`;\n\nexport const RED_GRADIENT_UNIFORMS: Record<string, { value: any; type: string }> = {\n uTime: { value: 0.0, type: \"f32\" },\n};\n\nexport const BUBBLE_SPARKLES_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform vec3 bubbleColor;\nuniform float bubbleCount;\n\nfloat rand(vec2 co){\n return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);\n}\n\nfloat softCircle(vec2 uv, vec2 c, float r, float g) {\n float d = distance(uv, c);\n float base = 1.0 - smoothstep(r * 0.9, r, d);\n float halo = (1.0 - smoothstep(r, r * (1.0 + g), d));\n return base + halo * 0.5;\n}\n\nvec2 bubblePos(float id) {\n float fx = rand(vec2(id, 1.234));\n float fy = rand(vec2(id, 9.345));\n return vec2(fx, fy);\n}\n\nfloat bubbleRadius(float id) {\n return mix(0.015, 0.025, rand(vec2(id, 44.123)));\n}\n\nvoid main(void)\n{\n vec2 uvs = vTextureCoord.xy;\n vec4 fg = texture2D(uTexture, uvs);\n\n float bubbles = 0.0;\n\n for(float i = 0.0; i < 200.0; i++) {\n\n if(i >= bubbleCount) break;\n float spawnSpeed = 8.0; \n float spawnTime = (i / bubbleCount) / spawnSpeed;\n float t = uTime - spawnTime;\n\n if(t < 0.0) continue;\n\n float grow = pow(clamp(t, 0.0, 1.0), 0.35);\n\n vec2 pos = bubblePos(i);\n vec2 bubbleCenter = pos;\n\n float baseR = bubbleRadius(i);\n\n float r = baseR * grow;\n\n float phase = rand(vec2(i, 999.0)) * 6.28318;\n float pulse = sin(t * 1.6 + phase) * 0.5 + 0.5;\n float opacity = mix(0.2, 1.0, pulse);\n\n bubbles += softCircle(uvs, bubbleCenter, r, 0.8) * opacity;\n }\n\n fg.rgb += bubbleColor * bubbles;\n gl_FragColor = fg;\n}\n`;\n\nexport const BUBBLE_SPARKLES_UNIFORMS: Record<string, { value: any; type: string }> = {\n uTime: { value: 0.0, type: \"f32\" },\n bubbleColor: { value: [1.0, 0.85, 0.4], type: \"vec3<f32>\" },\n bubbleCount: { value: 150.0, type: \"f32\" },\n};\n\nexport const SEPIA_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime; \nuniform float maxIntensity; \n\nvoid main(void)\n{\n vec2 uvs = vTextureCoord.xy;\n vec4 color = texture2D(uTexture, uvs);\n\n float intensity = (sin(uTime) * 0.5 + 0.5) * maxIntensity;\n\n vec3 sepiaColor;\n sepiaColor.r = dot(color.rgb, vec3(0.393, 0.769, 0.189));\n sepiaColor.g = dot(color.rgb, vec3(0.349, 0.686, 0.168));\n sepiaColor.b = dot(color.rgb, vec3(0.272, 0.534, 0.131));\n\n color.rgb = mix(color.rgb, sepiaColor, intensity);\n\n gl_FragColor = color;\n}\n`;\n\nexport const SEPIA_UNIFORMS: Record<string, { value: any; type: string }> = {\n uTime: { value: 0.0, type: \"f32\" },\n maxIntensity: { value: 1.0, type: \"f32\" },\n};\n\nexport const UV_GRADIENT_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform vec3 colorStart; \nuniform vec3 colorEnd; \nuniform int direction; \n\nvoid main(void)\n{\n vec2 uvs = vTextureCoord.xy;\n vec4 fg = texture2D(uTexture, uvs);\n\n float t = 0.0;\n if(direction == 0) {\n t = uvs.x; \n } else if(direction == 1) {\n t = uvs.y;\n } else {\n t = (uvs.x + uvs.y) * 0.5;\n }\n\n vec3 gradientColor = mix(colorStart, colorEnd, t);\n\n fg.rgb = fg.rgb * gradientColor; \n\n gl_FragColor = fg;\n}\n`;\n\nexport const UV_GRADIENT_UNIFORMS: Record<string, { value: any; type: string }> = {\n colorStart: { value: [1.0, 0.0, 0.0], type: \"vec3<f32>\" },\n colorEnd: { value: [0.0, 0.0, 1.0], type: \"vec3<f32>\" },\n direction: { value: 0, type: \"i32\" },\n};\n\nexport const RAINBOW_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float intensity;\nuniform int direction; \n\nvec3 rainbow(float t) {\n float r = 0.5 + 0.5 * sin(6.28318 * (t + 0.0));\n float g = 0.5 + 0.5 * sin(6.28318 * (t + 0.33));\n float b = 0.5 + 0.5 * sin(6.28318 * (t + 0.66));\n return vec3(r, g, b);\n}\n\nvoid main(void)\n{\n vec2 uvs = vTextureCoord.xy;\n vec4 fg = texture2D(uTexture, uvs);\n\n float t = 0.0;\n if(direction == 0) {\n t = uvs.x; \n } else if(direction == 1) {\n t = uvs.y; \n } else {\n t = (uvs.x + uvs.y) * 0.5; \n }\n\n vec3 rainbowColor = rainbow(t);\n\n fg.rgb = fg.rgb * rainbowColor*intensity;\n\n gl_FragColor = fg;\n}\n`;\n\nexport const RAINBOW_UNIFORMS: Record<string, { value: any; type: string }> = {\n intensity: { value: 1.0, type: \"f32\" },\n direction: { value: 0, type: \"i32\" },\n};\n\nexport const GLITCH_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime; \nuniform float intensity; \nuniform float sliceCount; \nuniform float rgbShift; \n\nfloat rand(float n) { return fract(sin(n) * 43758.5453123); }\nfloat rand2(vec2 p) { return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453); }\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n\n float sliceId = floor(uv.y * sliceCount);\n float sliceShift = (rand(sliceId + uTime * 10.0) - 0.5) * 0.2 * intensity;\n\n uv.x += sliceShift;\n\n float rShift = rgbShift * intensity;\n float gShift = -rgbShift * 0.5 * intensity;\n float bShift = rgbShift * 0.75 * intensity;\n\n vec3 col;\n col.r = texture2D(uTexture, uv + vec2(rShift, 0.0)).r;\n col.g = texture2D(uTexture, uv + vec2(gShift, 0.0)).g;\n col.b = texture2D(uTexture, uv + vec2(bShift, 0.0)).b;\n\n float noise = rand2(vec2(uTime * 50.0, uv.y * 100.0));\n float noiseIntensity = noise * 0.15 * intensity;\n\n col += noiseIntensity;\n\n gl_FragColor = vec4(col, 1.0);\n}\n`;\n\nexport const GLITCH_UNIFORMS: Record<string, { value: any; type: string }> = {\n uTime: { value: 0.0, type: \"f32\" },\n intensity: { value: 0.5, type: \"f32\" },\n sliceCount: { value: 12.0, type: \"f32\" },\n rgbShift: { value: 0.01, type: \"f32\" },\n};\n\nexport const PIXELATE_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float pixelSize;\nuniform float uTime;\nuniform float jitterStrength;\n\nfloat hash(vec2 p) {\n return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n\n vec2 pixelUV = floor(uv / pixelSize) * pixelSize;\n\n float n1 = hash(pixelUV + uTime * 1.5);\n float n2 = hash(pixelUV * 2.3 + uTime * 1.7);\n\n vec2 jitter = (vec2(n1, n2) - 0.5) * jitterStrength * pixelSize;\n\n vec2 finalUV = pixelUV + jitter;\n\n finalUV = clamp(finalUV, 0.0, 1.0);\n vec4 color = texture2D(uTexture, finalUV);\n\n gl_FragColor = color;\n}\n`;\n\nexport const PIXELATE_UNIFORMS = {\n pixelSize: { value: 0.02, type: \"f32\" },\n uTime: { value: 0, type: \"f32\" },\n jitterStrength: { value: 0.8, type: \"f32\" },\n};\nexport const RGB_GLITCH_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float glitchStrength;\nuniform float glitchSpeed;\n\nfloat hash(vec2 p) {\n return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);\n}\n\nfloat rand2(vec2 p) {\n return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n\n vec4 base = texture2D(uTexture, uv);\n if (base.a < 0.01) {\n gl_FragColor = base;\n return;\n }\n\n float lineNoise =\n hash(vec2(floor(uv.y * 300.0), uTime * glitchSpeed));\n\n float rOffset =\n (hash(vec2(uTime, 1.0)) - 0.5) * glitchStrength;\n\n float gOffset =\n (hash(vec2(uTime, 2.0)) - 0.5) * glitchStrength * 0.5;\n\n float bOffset =\n (hash(vec2(uTime, 3.0)) - 0.5) * glitchStrength;\n\n float rShift = rOffset * lineNoise;\n float gShift = gOffset * lineNoise;\n float bShift = bOffset * lineNoise;\n\n vec2 uvR = clamp(uv + vec2(rShift, 0.0), 0.0, 1.0);\n vec2 uvG = clamp(uv + vec2(gShift, 0.0), 0.0, 1.0);\n vec2 uvB = clamp(uv + vec2(bShift, 0.0), 0.0, 1.0);\n\n vec3 col;\n col.r = texture2D(uTexture, uvR).r;\n col.g = texture2D(uTexture, uvG).g;\n col.b = texture2D(uTexture, uvB).b;\n\n float noise =\n (rand2(vec2(uTime * 50.0, uv.y * 100.0)) - 0.5) * 0.15;\n\n col += noise;\n\n gl_FragColor = vec4(col, base.a);\n}\n`;\n\nexport const RGB_GLITCH_UNIFORMS = {\n uTime: { value: 0, type: \"f32\" },\n glitchStrength: { value: 0.02, type: \"f32\" },\n glitchSpeed: { value: 2.0, type: \"f32\" },\n};\nexport const RGB_SHIFT_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float shiftAmount;\nuniform float angle;\nuniform float uTime;\nuniform float wobbleAmount;\nuniform float wobbleSpeed;\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n\n vec4 base = texture2D(uTexture, uv);\n\n if (base.a < 0.01) {\n gl_FragColor = base;\n return;\n }\n\n vec2 dir = vec2(cos(angle), sin(angle));\n float wobble = sin(uTime * wobbleSpeed) * wobbleAmount;\n\n vec2 rUV = uv + dir * shiftAmount + vec2(wobble, 0.0);\n vec2 gUV = uv;\n vec2 bUV = uv - dir * shiftAmount - vec2(wobble, 0.0);\n\n rUV = clamp(rUV, 0.0, 1.0);\n gUV = clamp(gUV, 0.0, 1.0);\n bUV = clamp(bUV, 0.0, 1.0);\n\n float r = texture2D(uTexture, rUV).r;\n float g = texture2D(uTexture, gUV).g;\n float b = texture2D(uTexture, bUV).b;\n\n gl_FragColor = vec4(r, g, b, base.a);\n}\n`;\n\nexport const RGB_SHIFT_UNIFORMS = {\n shiftAmount: { value: 0.01, type: \"f32\" },\n angle: { value: 0.0, type: \"f32\" },\n uTime: { value: 0.0, type: \"f32\" },\n wobbleAmount: { value: 0.003, type: \"f32\" },\n wobbleSpeed: { value: 20.0, type: \"f32\" },\n};\n\nexport const HALFTONE_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float dotSize; \nuniform float intensity; \nuniform float angle; \nuniform float uTime; \nuniform float vibrateStrength;\n\nfloat luminance(vec3 c) {\n return dot(c, vec3(0.299, 0.587, 0.114));\n}\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n\n float ca = cos(angle);\n float sa = sin(angle);\n mat2 rot = mat2(ca, -sa, sa, ca);\n vec2 rotatedUV = rot * (uv - 0.5) + 0.5;\n vec2 grid = rotatedUV / dotSize;\n vec2 cell = floor(grid) + 0.5;\n\n vec2 cellCenter = cell * dotSize;\n\n float jitter = sin(uTime * 10.0 + cell.x * 12.989 + cell.y * 78.233) * 0.5;\n float dist = distance(rotatedUV, cellCenter + jitter * vibrateStrength * dotSize);\n vec4 texColor = texture2D(uTexture, uv);\n float lum = luminance(texColor.rgb);\n float radius = (1.0 - lum) * dotSize * 0.5;\n float mask = smoothstep(radius, radius * 0.8, dist);\n\n vec3 halftone = texColor.rgb * mask;\n texColor.rgb = mix(texColor.rgb, halftone, intensity);\n\n gl_FragColor = texColor;\n}\n`;\n\nexport const HALFTONE_UNIFORMS = {\n dotSize: { value: 0.03, type: \"f32\" },\n intensity: { value: 1.0, type: \"f32\" },\n angle: { value: 0.0, type: \"f32\" },\n uTime: { value: 0.0, type: \"f32\" },\n vibrateStrength: { value: 0.2, type: \"f32\" },\n};\n\nexport const SINEWAVE_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime; \nuniform float amplitude; \nuniform float frequency; \nuniform float speed; \nuniform int direction; \n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n\n vec2 offset = vec2(0.0);\n\n if(direction == 0) {\n offset.y = sin((uv.x + uTime * speed) * frequency * 6.2831853) * amplitude;\n } else {\n offset.x = sin((uv.y + uTime * speed) * frequency * 6.2831853) * amplitude;\n }\n\n vec4 color = texture2D(uTexture, uv + offset);\n gl_FragColor = color;\n}\n`;\n\nexport const SINEWAVE_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n amplitude: { value: 0.02, type: \"f32\" },\n frequency: { value: 3.0, type: \"f32\" },\n speed: { value: 0.5, type: \"f32\" },\n direction: { value: 0, type: \"i32\" },\n};\n\nexport const SHINE_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime; // tiempo para animación\nuniform vec3 shineColor; // color de los rayos\nuniform float rayWidth; // grosor del rayo\nuniform float rayCount; // cantidad de rayos\nuniform float rotationSpeed; // velocidad de rotación\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n vec2 center = vec2(0.3, 0.35);\n\n vec2 dir = uv - center;\n\n float angle = atan(dir.y, dir.x);\n\n angle += uTime * rotationSpeed;\n\n float normAngle = fract(angle / 6.28318530718); // 2π\n\n float rays = sin(normAngle * rayCount * 6.28318530718);\n\n float intensity = smoothstep(0.0, rayWidth, rays) - smoothstep(rayWidth, rayWidth*1.5, rays);\n\n vec4 color = texture2D(uTexture, uv);\n\n color.rgb += shineColor * intensity;\n\n gl_FragColor = color;\n}\n`;\n\nexport const SHINE_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n shineColor: { value: [1.0, 1.0, 1.0], type: \"vec3<f32>\" },\n rayWidth: { value: 0.05, type: \"f32\" },\n rayCount: { value: 12.0, type: \"f32\" },\n rotationSpeed: { value: 0.5, type: \"f32\" },\n};\n\nexport const BLINK_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime; \nuniform float blinkSpeed; \nuniform float minIntensity; \nuniform float maxIntensity; \n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n vec4 color = texture2D(uTexture, uv);\n float t = sin(uTime * blinkSpeed * 6.2831853) * 0.5 + 0.5;\n float intensity = mix(minIntensity, maxIntensity, t);\n\n color.rgb *= intensity;\n\n gl_FragColor = color;\n}\n`;\n\nexport const BLINK_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n blinkSpeed: { value: 2.0, type: \"f32\" },\n minIntensity: { value: 0.3, type: \"f32\" },\n maxIntensity: { value: 1.0, type: \"f32\" },\n};\n\nexport const SPRING_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime; \nuniform float frequency; \nuniform float damping; \nuniform float strength; \n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n\n float spring = exp(-damping * uTime) *\n sin(uTime * frequency * 6.2831853);\n\n uv.x += spring * strength;\n uv.y += spring * strength * 0.5; \n\n vec4 color = texture2D(uTexture, uv);\n\n gl_FragColor = color;\n}\n`;\n\nexport const SPRING_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n frequency: { value: 2.0, type: \"f32\" },\n damping: { value: 0.8, type: \"f32\" },\n strength: { value: 0.04, type: \"f32\" },\n};\n\nexport const DUOTONE_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform vec3 colorA; \nuniform vec3 colorB; \nuniform float intensity; \n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n\n vec4 tex = texture2D(uTexture, uv);\n float gray = dot(tex.rgb, vec3(0.299, 0.587, 0.114));\n vec3 duo = mix(colorA, colorB, gray);\n tex.rgb = mix(tex.rgb, duo, intensity);\n gl_FragColor = tex;\n}\n`;\n\nexport const DUOTONE_UNIFORMS = {\n colorA: { value: [0.1, 0.1, 0.5], type: \"vec3<f32>\" },\n colorB: { value: [1.0, 0.8, 0.2], type: \"vec3<f32>\" },\n intensity: { value: 1.0, type: \"f32\" },\n};\n\nexport const TRITONE_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform vec3 colorShadow; \nuniform vec3 colorMid; \nuniform vec3 colorHighlight;\n\nuniform float intensity; \n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n vec4 tex = texture2D(uTexture, uv);\n float gray = dot(tex.rgb, vec3(0.299, 0.587, 0.114));\n\n\n vec3 duoA = mix(colorShadow, colorMid, smoothstep(0.0, 0.5, gray));\n vec3 duoB = mix(colorMid, colorHighlight, smoothstep(0.5, 1.0, gray));\n vec3 tritone = mix(duoA, duoB, smoothstep(0.33, 0.66, gray));\n tex.rgb = mix(tex.rgb, tritone, intensity);\n\n gl_FragColor = tex;\n}\n`;\n\nexport const TRITONE_UNIFORMS = {\n colorShadow: { value: [0.1, 0.0, 0.3], type: \"vec3<f32>\" },\n colorMid: { value: [0.2, 0.8, 0.8], type: \"vec3<f32>\" },\n colorHighlight: { value: [1.0, 0.9, 0.4], type: \"vec3<f32>\" },\n intensity: { value: 1.0, type: \"f32\" },\n};\n\nexport const HUE_SHIFT_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime; \nuniform float amount; \n\nvec3 hueShift(vec3 color, float angle) {\n float cosA = cos(angle);\n float sinA = sin(angle);\n mat3 rot = mat3(\n 0.299 + 0.701 * cosA + 0.168 * sinA,\n 0.587 - 0.587 * cosA + 0.330 * sinA,\n 0.114 - 0.114 * cosA - 0.497 * sinA,\n\n 0.299 - 0.299 * cosA - 0.328 * sinA,\n 0.587 + 0.413 * cosA + 0.035 * sinA,\n 0.114 - 0.114 * cosA + 0.292 * sinA,\n\n 0.299 - 0.300 * cosA + 1.250 * sinA,\n 0.587 - 0.588 * cosA - 1.050 * sinA,\n 0.114 + 0.886 * cosA - 0.203 * sinA\n );\n\n return color * rot;\n}\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n vec4 tex = texture2D(uTexture, uv);\n\n vec3 shifted = hueShift(tex.rgb, uTime*2.5);\n\n tex.rgb = mix(tex.rgb, shifted, amount);\n\n gl_FragColor = tex;\n}\n`;\n\nexport const HUE_SHIFT_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n amount: { value: 1.0, type: \"f32\" },\n};\n\nexport const WARP_TRANSITION_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime; \nuniform float uStrength; \nuniform float swirl; \n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n vec2 center = vec2(0.5, 0.5);\n vec2 dir = uv - center;\n float dist = length(dir);\n float warpAmount = pow(dist, 2.0) * uStrength * uTime;\n float angle = swirl * uTime * 6.283185; \n\n float s = sin(angle * dist);\n float c = cos(angle * dist);\n\n mat2 rot = mat2(c, -s, s, c);\n vec2 warpedUV = center + rot * dir * (1.0 - warpAmount);\n vec4 color = texture2D(uTexture, warpedUV);\n\n gl_FragColor = color;\n}\n`;\n\nexport const WARP_TRANSITION_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uStrength: { value: 0.8, type: \"f32\" },\n swirl: { value: 0.3, type: \"f32\" },\n};\n\nexport const SLIT_SCAN_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime; \nuniform float uStrength; \nuniform int direction; \n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n float offset;\n if(direction == 0) {\n offset = (uv.y - 0.5) * uStrength * uTime;\n uv.x += offset;\n } else {\n offset = (uv.x - 0.5) * uStrength * uTime;\n uv.y += offset;\n }\n\n vec4 color = texture2D(uTexture, uv);\n\n gl_FragColor = color;\n}\n`;\n\nexport const SLIT_SCAN_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uStrength: { value: 0.2, type: \"f32\" },\n direction: { value: 0, type: \"i32\" },\n};\n\nexport const SLIT_SCAN_GLITCH_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float uStrength;\nuniform float uNoise;\nuniform int direction;\n\nfloat hash(float n) {\n return fract(sin(n) * 43758.5453);\n}\n\nfloat hash(vec2 p) {\n return fract(sin(dot(p ,vec2(12.9898,78.233))) * 43758.5453);\n}\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n\n float offset;\n if(direction == 0) {\n offset = (uv.y - 0.5) * uStrength * uTime;\n uv.x += offset;\n } else {\n offset = (uv.x - 0.5) * uStrength * uTime;\n uv.y += offset;\n }\n\n float jitter = (hash(floor(uv * 100.0) + uTime) - 0.5) * uNoise;\n if(direction == 0) {\n uv.x += jitter;\n } else {\n uv.y += jitter;\n }\n\n float rOffset = (hash(uv + 1.0) - 0.5) * uNoise * 0.5;\n float gOffset = (hash(uv + 2.0) - 0.5) * uNoise * 0.5;\n float bOffset = (hash(uv + 3.0) - 0.5) * uNoise * 0.5;\n\n vec4 texR = texture2D(uTexture, uv + vec2(rOffset, 0.0));\n vec4 texG = texture2D(uTexture, uv + vec2(gOffset, 0.0));\n vec4 texB = texture2D(uTexture, uv + vec2(bOffset, 0.0));\n\n gl_FragColor = vec4(texR.r, texG.g, texB.b, 1.0);\n}\n`;\n\nexport const SLIT_SCAN_GLITCH_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uStrength: { value: 0.2, type: \"f32\" },\n uNoise: { value: 0.05, type: \"f32\" },\n direction: { value: 0, type: \"i32\" },\n};\n\nexport const PIXELATE_TRANSITION_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime; \nuniform float maxPixelSize; \n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n float pixelSize = maxPixelSize * uTime;\n pixelSize = max(pixelSize, 0.001);\n vec2 pixelUV = floor(uv / pixelSize) * pixelSize;\n\n vec4 color = texture2D(uTexture, pixelUV);\n\n gl_FragColor = color;\n}\n`;\n\nexport const PIXELATE_TRANSITION_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n maxPixelSize: { value: 0.05, type: \"f32\" },\n};\n\nexport const FOCUS_TRANSITION_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime; \nuniform float maxBlur; \n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n vec4 color = vec4(0.0);\n float blur = maxBlur * (1.0 - uTime);\n\n if(blur < 0.001) {\n color = texture2D(uTexture, uv);\n } else {\n vec2 offsets[9];\n offsets[0] = vec2(-blur, -blur);\n offsets[1] = vec2(0.0, -blur);\n offsets[2] = vec2(blur, -blur);\n offsets[3] = vec2(-blur, 0.0);\n offsets[4] = vec2(0.0, 0.0);\n offsets[5] = vec2(blur, 0.0);\n offsets[6] = vec2(-blur, blur);\n offsets[7] = vec2(0.0, blur);\n offsets[8] = vec2(blur, blur);\n\n for(int i = 0; i < 9; i++) {\n color += texture2D(uTexture, uv + offsets[i]);\n }\n\n color /= 9.0;\n }\n\n gl_FragColor = color;\n}\n`;\n\nexport const FOCUS_TRANSITION_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n maxBlur: { value: 0.01, type: \"f32\" },\n};\nexport const INVERT_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float amount;\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n vec4 tex = texture2D(uTexture, uv);\n\n vec3 inverted = vec3(1.0) - tex.rgb;\n\n float strength = amount * tex.a;\n\n tex.rgb = mix(tex.rgb, inverted, strength);\n\n gl_FragColor = tex;\n}\n`;\n\nexport const INVERT_UNIFORMS = {\n amount: { value: 1.0, type: \"f32\" },\n};\n\nexport const GRAYSCALE_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float amount; \n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n vec4 tex = texture2D(uTexture, uv);\n float gray = dot(tex.rgb, vec3(0.299, 0.587, 0.114));\n vec3 grayscale = vec3(gray);\n\n tex.rgb = mix(tex.rgb, grayscale, amount);\n\n gl_FragColor = tex;\n}\n`;\n\nexport const GRAYSCALE_UNIFORMS = {\n amount: { value: 1.0, type: \"f32\" },\n};\n\nexport const VIGNETTE_FRAGMENT = `\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uIntensity; \nuniform float uSoftness; \n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n\n vec2 centered = uv - vec2(0.5);\n float dist = length(centered);\n float vignette = smoothstep(0.5, 0.5 - uSoftness, dist);\n vec4 color = texture(uTexture, uv);\n color.rgb *= 1.0 - (vignette * uIntensity);\n\n gl_FragColor = color;\n}\n`;\n\nexport const VIGNETTE_UNIFORMS = {\n uIntensity: { value: 0.5, type: \"f32\" },\n uSoftness: { value: 0.2, type: \"f32\" },\n};\n\nexport const CHROMATIC_FRAGMENT = `\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uIntensity; \nuniform vec2 uDirection; \n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n vec2 offset = uDirection * uIntensity;\n float r = texture(uTexture, uv + offset).r;\n float g = texture(uTexture, uv).g;\n float b = texture(uTexture, uv - offset).b;\n vec4 color = vec4(r, g, b, 1.0);\n\n gl_FragColor = color;\n}\n`;\n\nexport const CHROMATIC_UNIFORMS = {\n uIntensity: { value: 0.005, type: \"f32\" },\n uDirection: { value: [1.0, 0.0], type: \"vec2<f32>\" },\n};\n\nexport const SWIRL_MOVEMENT_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float rotationCount;\n\nuniform float swirlStrength; \nuniform float swirlRadius; \nuniform float rainbowIntensity;\n\nvec3 hsv2rgb(vec3 c)\n{\n vec3 rgb = clamp( abs(mod(c.x*6.0 + vec3(0.0,4.0,2.0), 6.0) - 3.0) - 1.0,\n 0.0,\n 1.0 );\n return c.z * mix(vec3(1.0), rgb, c.y);\n}\n\nfloat flamePattern(float dist, float angle, float time) {\n return pow(sin(dist * 10.0 - time * 5.0 + angle * 5.0) * 0.5 + 0.5, 2.0);\n}\n\nvoid main(void)\n{\n vec2 center = vec2(0.3, 0.45);\n vec2 uvs = vTextureCoord - center;\n\n // fade del rainbow (0 cuando uTime >= 0.75)\n float fadeRainbow = clamp(1.0 - smoothstep(0.7, 0.75, uTime), 0.0, 1.0);\n\n // fade de swirl, wave y blur (disminuye entre 0.8 y 1.0)\n float fadeMotion = clamp(1.0 - smoothstep(0.8, 1.0, uTime), 0.0, 1.0);\n\n // ángulo total acumulado para mantener la dirección del giro\n float angleTotal = uTime * rotationCount * 6.2831853; \n\n float cosA = cos(angleTotal);\n float sinA = sin(angleTotal);\n mat2 rotation = mat2(cosA, -sinA, sinA, cosA);\n vec2 rotatedUV = rotation * uvs + center;\n\n float dist = distance(rotatedUV, center);\n float d = clamp(dist / swirlRadius, 0.0, 1.0);\n\n // swirl disminuye suavemente sin invertir la dirección\n float swirlAngle = swirlStrength * d * d * 6.2831853 * fadeMotion;\n float cosS = cos(swirlAngle);\n float sinS = sin(swirlAngle);\n\n vec2 dir = rotatedUV - center;\n rotatedUV = vec2(\n dir.x * cosS - dir.y * sinS,\n dir.x * sinS + dir.y * cosS\n ) + center;\n\n float wave = sin(dist * 12.0 - uTime * 4.0) * 0.015 * fadeMotion; \n rotatedUV += wave * normalize(dir);\n\n // blur de la textura\n vec4 color = vec4(0.0);\n float blurAmount = (0.004 + rotationCount * 0.001) * fadeMotion; \n\n for (int i = -3; i <= 3; i++) {\n float offset = float(i) * blurAmount;\n vec2 blurUV = rotatedUV + vec2(offset * cosA, offset * sinA);\n color += texture2D(uTexture, blurUV);\n }\n color /= 7.0;\n\n // rainbow\n float rainbowScale = 0.05;\n float ang = atan(dir.y, dir.x);\n float hue = (ang / 6.2831853) + 0.5 + dist * rainbowScale;\n hue += uTime * 0.2 + rotationCount * 0.05;\n\n vec3 rainbow = hsv2rgb(vec3(hue, 0.35, 1.0));\n color.rgb = mix(color.rgb, rainbow, rainbowIntensity * fadeRainbow);\n\n // Flame disminuye con fadeMotion\n float flame = flamePattern(dist, ang, uTime) * fadeMotion;\n vec3 flameColor = vec3(1.0, 0.5, 0.0) * flame;\n flameColor = mix(flameColor, vec3(1.0,1.0,0.2), flame * 0.5);\n color.rgb += flameColor * 0.3;\n\n if (rotatedUV.x < 0.0 || rotatedUV.x > 1.0 || rotatedUV.y < 0.0 || rotatedUV.y > 1.0) {\n discard;\n }\n\n gl_FragColor = color;\n}\n\n`;\n\nexport const SWIRL_MOVEMENT_UNIFORMS = {\n uTime: { value: 0, type: \"f32\" },\n rotationCount: { value: 4.0, type: \"f32\" },\n\n swirlStrength: { value: 0.9, type: \"f32\" },\n swirlRadius: { value: 1.0, type: \"f32\" },\n\n rainbowIntensity: { value: 0.25, type: \"f32\" },\n};\n\nexport const HEART_SPARKLES_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform vec3 heartColor;\nuniform float heartCount;\n\nfloat rand(vec2 co){\n return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);\n}\n\nfloat heartShape(vec2 p) {\n p = (p - 0.5) * 2.0; \n p.y = -p.y; \n p.y += 0.25; \n float x = p.x;\n float y = p.y;\n float val = pow(x*x + y*y - 1.0, 3.0) - x*x * y*y*y;\n return smoothstep(0.0, 0.02, -val);\n}\n\nvec2 heartPos(float id) {\n float fx = rand(vec2(id, 1.234)) * 0.85 - 0.025; \n float fy = rand(vec2(id, 1.345)) * 0.85 + 0.025;\n return vec2(fx, fy);\n}\n\nfloat heartSize(float id) {\n return mix(0.02, 0.05, rand(vec2(id, 44.123))); \n}\n\nvoid main() {\n vec2 uv = vTextureCoord.xy;\n vec4 base = texture2D(uTexture, uv);\n\n float hearts = 0.0;\n\n for(float i = 0.0; i < 200.0; i++) {\n if(i >= heartCount) break;\n\n vec2 pos = heartPos(i);\n float size = heartSize(i);\n\n float vibX = (rand(vec2(i, uTime)) - 0.5) * 0.02;\n float vibY = (rand(vec2(i+1.0, uTime)) - 0.5) * 0.02;\n\n vec2 heartUV = (uv - (pos + vec2(vibX, vibY))) / size + 0.5;\n\n float h = heartShape(heartUV);\n\n float pulse = sin(uTime * 4.0 + i) * 0.2 + 1.0;\n h *= pulse;\n\n hearts += h;\n }\n\n base.rgb += heartColor * hearts;\n gl_FragColor = base;\n}\n`;\n\nexport const HEART_SPARKLES_UNIFORMS: Record<string, { value: any; type: string }> = {\n uTime: { value: 0.0, type: \"f32\" },\n heartColor: { value: [1.0, 0.2, 0.5], type: \"vec3<f32>\" },\n heartCount: { value: 150.0, type: \"f32\" },\n};\n\nexport const BUTTERFLY_SPARKLES_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform vec3 butterflyColor;\nuniform float butterflyCount;\n\nfloat rand(vec2 co){\n return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);\n}\n\nfloat wing(vec2 p) {\n float d = pow(p.x, 2.0) + pow(p.y * 1.2, 2.0);\n return smoothstep(0.3, 0.0, d);\n}\n\nfloat butterflyShape(vec2 uv) {\n vec2 p = (uv - 0.5) * 2.0;\n\n float body = smoothstep(0.12, 0.05, abs(p.x)) \n * smoothstep(0.4, 0.0, abs(p.y));\n\n float wL = wing(vec2(p.x * 1.2 + 0.6, p.y));\n float wR = wing(vec2(p.x * 1.2 - 0.6, p.y));\n\n return clamp(wL + wR + body, 0.0, 1.0);\n}\nvec2 butterflyPos(float id) {\n float fx = rand(vec2(id, 1.234)) * 0.85 - 0.025;\n float fy = rand(vec2(id, 1.345)) * 0.85 + 0.025;\n return vec2(fx, fy);\n}\n\nfloat butterflySize(float id) {\n return mix(0.03, 0.08, rand(vec2(id, 44.123)));\n}\n\nvoid main() {\n vec2 uv = vTextureCoord.xy;\n vec4 base = texture2D(uTexture, uv);\n\n float butterflies = 0.0;\n\n for(float i = 0.0; i < 200.0; i++) {\n if(i >= butterflyCount) break;\n\n vec2 pos = butterflyPos(i);\n float size = butterflySize(i);\n\n float vibX = (rand(vec2(i, uTime)) - 0.5) * 0.02;\n float vibY = (rand(vec2(i+1.0, uTime)) - 0.5) * 0.02;\n\n vec2 bUV = (uv - (pos + vec2(vibX, vibY))) / size + 0.5;\n\n float b = butterflyShape(bUV);\n\n float pulse = sin(uTime * 3.0 + i) * 0.25 + 1.0;\n b *= pulse;\n\n butterflies += b;\n }\n\n base.rgb += butterflyColor * butterflies;\n gl_FragColor = base;\n}\n`;\n\nexport const BUTTERFLY_SPARKLES_UNIFORMS: Record<string, { value: any; type: string }> = {\n uTime: { value: 0.0, type: \"f32\" },\n butterflyColor: { value: [0.5, 0.6, 1.0], type: \"vec3<f32>\" },\n butterflyCount: { value: 120.0, type: \"f32\" },\n};\n\nexport const DISTORT_EFFECT_FRAGMENT = `\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float amplitude; \nuniform float speed; \nuniform float uTime; \n\nvoid main() {\n vec2 p = vTextureCoord;\n vec2 center = vec2(0.28, 0.45);\n\n vec2 dir = p - center;\n float dist = length(dir);\n\n vec2 offset = vec2(0.0);\n\n if (dist <= uTime) {\n offset = dir * sin(dist * amplitude - uTime * speed);\n }\n\n gl_FragColor = texture2D(uTexture, p + offset);\n}\n`;\n\nexport const DISTORT_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n amplitude: { value: 30.0, type: \"f32\" },\n speed: { value: 30.0, type: \"f32\" },\n};\n\nexport const PERSPECTIVE_SINGLE_FRAGMENT = `\nprecision mediump float;\n\nuniform sampler2D uTexture;\nuniform float persp; \nuniform float unzoom; \nuniform float reflection; \nuniform float floating; \nuniform float uTime;\n\nvarying vec2 vTextureCoord;\n\nbool inBounds(vec2 p) {\n return all(greaterThanEqual(p, vec2(0.0))) &&\n all(lessThanEqual(p, vec2(1.0)));\n}\n\nvec2 project(vec2 p) {\n return p * vec2(1.0, -1.2) + vec2(0.0, -floating / 100.0);\n}\n\nvec2 xskew(vec2 p, float persp, float center) {\n float x = mix(p.x, 1.0 - p.x, center);\n\n return (\n (\n vec2(\n x,\n (p.y - 0.5*(1.0-persp) * x) /\n (1.0+(persp-1.0)*x)\n )\n - vec2(0.5 - abs(center - 0.5), 0.0)\n )\n * vec2(\n 0.5 / abs(center - 0.5) * (center < 0.5 ? 1.0 : -1.0),\n 1.0\n )\n + vec2(center < 0.5 ? 0.0 : 1.0, 0.0)\n );\n}\n\nvoid main() {\n vec2 p = vTextureCoord;\n\n float uz = unzoom * sin(uTime * 0.5);\n p = -uz * 0.5 + (1.0 + uz) * p;\n\n vec2 warped = xskew(p, persp, 0.0);\n\n vec4 baseColor = vec4(0.0);\n\n if (inBounds(warped)) {\n baseColor = texture2D(uTexture, warped);\n }\n\n vec2 proj = project(warped);\n if (inBounds(proj)) {\n vec4 refl = texture2D(uTexture, proj);\n refl.rgb *= reflection * (1.0 - proj.y);\n baseColor += refl;\n }\n\n gl_FragColor = baseColor;\n}\n\n`;\n\nexport const PERSPECTIVE_SINGLE_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n persp: { value: 0.7, type: \"f32\" },\n unzoom: { value: 0.3, type: \"f32\" },\n reflection: { value: 0.0, type: \"f32\" },\n floating: { value: 3.0, type: \"f32\" },\n};\n\nexport const DISTORT_SPIN_FRAGMENT = `\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime; \nuniform float radius; \nuniform float spinPower; \nuniform float speed; \n\nvoid main() {\n vec2 uv = vTextureCoord;\n vec2 center = vec2(0.28, 0.45);\n\n vec2 pos = uv - center;\n\n float dist = length(pos);\n\n if (dist < radius) {\n float percent = (radius - dist) / radius;\n\n float theta = percent * percent * spinPower * sin(uTime * speed);\n\n float s = sin(theta);\n float c = cos(theta);\n\n pos = vec2(\n pos.x * c - pos.y * s,\n pos.x * s + pos.y * c\n );\n }\n\n uv = pos + center;\n\n gl_FragColor = texture2D(uTexture, uv);\n}\n`;\n\nexport const DISTORT_SPIN_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n radius: { value: 1.0, type: \"f32\" },\n spinPower: { value: 18.0, type: \"f32\" },\n speed: { value: 4.0, type: \"f32\" },\n};\n\nexport const DISTORT_GRID_FRAGMENT = `\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\n\nuniform float speed; \nuniform float intensity; \nuniform int endx;\nuniform int endy;\n\n#define PI 3.14159265358979323\n\nfloat rand(vec2 v) {\n return fract(sin(dot(v.xy , vec2(12.9898,78.233))) * 43758.5453);\n}\n\nvec2 rotate2d(vec2 v, float a) {\n mat2 rm = mat2(cos(a), -sin(a),\n sin(a), cos(a));\n return rm * v;\n}\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n vec2 p = uv - 0.5;\n\n float t = sin(uTime * speed) * 0.5 + 0.5;\n\n float warp = 1.0 + intensity * abs(t - 0.5);\n\n vec2 rp = p * warp;\n float tx = float(endx) + 0.5;\n float ty = float(endy) + 0.5;\n\n vec2 shifted = mix(vec2(0.5, 0.5), vec2(tx, ty), t*t);\n\n vec2 tiled = fract(rp + shifted);\n\n vec2 cell = floor(rp + shifted);\n\n bool isEnd = int(cell.x) == endx && int(cell.y) == endy;\n\n if (!isEnd) {\n float rnd = rand(cell);\n float angle = float(int(rnd * 4.0)) * 0.5 * PI;\n tiled = vec2(0.5) + rotate2d(tiled - vec2(0.5), angle);\n }\n gl_FragColor = texture2D(uTexture, tiled);\n}\n`;\n\nexport const DISTORT_GRID_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n speed: { value: 2.0, type: \"f32\" },\n intensity: { value: 1.5, type: \"f32\" },\n endx: { value: 2, type: \"i32\" },\n endy: { value: -1, type: \"i32\" },\n};\n\nexport const DISTORT_RIP_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\nuniform sampler2D uTexture;\nuniform float uTime;\n\nuniform float intensity; \nuniform float speed; \nuniform int slices; \nuniform float randomness; \n\n#define PI 3.141592653589793\nfloat rand(float x) {\n return fract(sin(x * 12.9898) * 43758.5453);\n}\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n float sliceHeight = 1.0 / float(slices);\n float sliceIndex = floor(uv.y / sliceHeight);\n\n float offsetX = (rand(sliceIndex + uTime * speed) - 0.5) * intensity;\n\n float offsetY = sin(uTime * speed + sliceIndex * 1.5) * 0.01 * randomness;\n\n uv.x += offsetX;\n uv.y += offsetY;\n vec4 color = texture(uTexture, uv);\n\n gl_FragColor = color;\n}\n\n`;\n\nexport const DISTORT_RIP_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n intensity: { value: 0.05, type: \"f32\" },\n speed: { value: 2.0, type: \"f32\" },\n slices: { value: 10, type: \"i32\" },\n randomness: { value: 1.0, type: \"f32\" },\n};\n\nexport const TWO_CURTAIN_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\nuniform sampler2D uTexture;\nuniform float uTime; \nuniform float softness; \n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n float t_raw = clamp(uTime, 0.0, 1.0);\n float t = pow(t_raw, 0.55);\n\n float mid = 0.5;\n\n float leftEdge = mid - t * mid;\n float rightEdge = mid + t * mid;\n\n float mask = smoothstep(leftEdge, leftEdge + softness, uv.x) *\n (1.0 - smoothstep(rightEdge - softness, rightEdge, uv.x));\n\n vec4 color = texture(uTexture, uv);\n\n gl_FragColor = vec4(color.rgb * mask, color.a * mask);\n}\n`;\nexport const TWO_CURTAIN_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n softness: { value: 0.2, type: \"f32\" },\n};\n\nexport const TRIANGLE_PATTERN_EFFECT_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float softness;\nuniform float zoom;\n\n#define PI 3.141592653589793\n\nvec2 rotate2D(vec2 st, float angle) {\n st -= 0.5;\n st = mat2(cos(angle), -sin(angle),\n sin(angle), cos(angle)) * st;\n st += 0.5;\n return st;\n}\n\nvec2 tile(vec2 st, float zoom) {\n st *= zoom;\n return fract(st);\n}\n\nvec2 rotateTile(vec2 st) {\n st *= 2.0;\n\n float index = 0.0;\n if (fract(st.x * 0.5) > 0.5) index += 1.0;\n if (fract(st.y * 0.5) > 0.5) index += 2.0;\n\n st = fract(st);\n\n if (index == 1.0) st = rotate2D(st, PI * 0.5);\n else if (index == 2.0) st = rotate2D(st, PI * -0.5);\n else if (index == 3.0) st = rotate2D(st, PI);\n\n return st;\n}\n\nfloat triangleShape(vec2 st, float smoothness) {\n vec2 p0 = vec2(0.3, -0.5);\n vec2 p1 = vec2(0.7, -0.5);\n vec2 p2 = vec2(0.5, 1.0);\n\n vec3 e0, e1, e2;\n\n e0.xy = normalize(p1 - p0).yx * vec2(+1.0, -1.0);\n e1.xy = normalize(p2 - p1).yx * vec2(+1.0, -1.0);\n e2.xy = normalize(p0 - p2).yx * vec2(+1.0, -1.0);\n\n e0.z = dot(e0.xy, p0) - smoothness;\n e1.z = dot(e1.xy, p1) - smoothness;\n e2.z = dot(e2.xy, p2) - smoothness;\n\n float a = max(0.0, dot(e0.xy, st) - e0.z);\n float b = max(0.0, dot(e1.xy, st) - e1.z);\n float c = max(0.0, dot(e2.xy, st) - e2.z);\n\n return smoothstep(smoothness * 2.0, 1e-7, length(vec3(a, b, c)));\n}\n\nvoid main() {\n vec2 uv = vTextureCoord;\n vec2 st = uv;\n st = tile(st, zoom);\n st = rotateTile(st);\n st = rotate2D(st, -PI * 0.25 * uTime);\n\n float mask = triangleShape(st, softness);\n\n vec4 tex = texture(uTexture, uv);\n gl_FragColor = vec4(tex.rgb * mask, tex.a * mask);\n}\n`;\n\nexport const TRIANGLE_PATTERN_EFFECT_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n softness: { value: 0.2, type: \"f32\" },\n zoom: { value: 8.0, type: \"f32\" },\n};\n\nexport const MIRROR_TILE_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\nuniform sampler2D uTexture;\nuniform float uTime;\n\nvec2 mirrorTile(vec2 st, float zoom) {\n st *= zoom;\n\n if (fract(st.y * 0.5) > 0.5) {\n st.x = st.x + 0.5;\n st.y = 1.0 - st.y;\n }\n\n return fract(st);\n}\n\nfloat zigzag(vec2 st) {\n float x = st.x * 2.0;\n float a = floor(1.0 + sin(x * 3.14159));\n float b = floor(1.0 + sin((x + 1.0) * 3.14159));\n float f = fract(x);\n return mix(a, b, f);\n}\n\nvoid main() {\n vec2 st = vTextureCoord;\n\n st = mirrorTile(st * vec2(1.0, 2.0), 5.0);\n\n float zz = zigzag(st);\n\n st.y += zz * 0.03;\n\n vec4 tex = texture(uTexture, st);\n\n gl_FragColor = tex;\n}\n`;\n\nexport const MIRROR_TILE_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n};\n\nexport const FLASH_LOOP_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float speed; \nuniform float intensity; \n\nvoid main(void)\n{\n vec4 tex = texture2D(uTexture, vTextureCoord);\n float t = fract(uTime * speed);\n float wave = sin(t * 3.141592);\n float base = 0.6;\n float brightness = mix(base, 1.0, wave);\n float flash = 1.0 + brightness * intensity;\n\n vec3 color = tex.rgb * flash;\n\n gl_FragColor = vec4(color, tex.a);\n}\n`;\n\nexport const FLASH_LOOP_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n speed: { value: 10.2, type: \"f32\" },\n intensity: { value: 1.5, type: \"f32\" },\n};\n\nexport const FILM_STRIP_PRO_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\n\nuniform float framesPerScreen;\nuniform float scrollSpeed;\nuniform float gateWeave;\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n vec3 color = vec3(0.0);\n\n uv.y += uTime * scrollSpeed;\n uv.y += sin(uTime * 2.0) * 0.003 * gateWeave;\n\n float stripLeft = 0.025;\n float stripRight = 0.5;\n\n if (uv.x < stripLeft || uv.x > stripRight) {\n gl_FragColor = vec4(color, 1.0);\n return;\n }\n\n vec2 stripUV;\n stripUV.x = (uv.x - stripLeft) / (stripRight - stripLeft);\n stripUV.y = fract(uv.y);\n\n float holeZone = 0.06; \n float frameZone = 1.0 - holeZone * 2.0;\n\n float frameH = 1.0 / framesPerScreen;\n float localY = fract(stripUV.y / frameH);\n\n bool inFrameX =\n stripUV.x > holeZone &&\n stripUV.x < holeZone + frameZone;\n\n float marginX = 0.08;\n float marginY = 0.10;\n\n\n bool insideFrame =\n inFrameX &&\n stripUV.x > holeZone + marginX &&\n stripUV.x < holeZone + frameZone - marginX &&\n localY > marginY &&\n localY < 1.0 - marginY;\n\n float frameZoneX = frameZone - marginX * 4.0;\n float centerOffset = (1.0 - frameZoneX - holeZone * 2.0) * 0.5;\n\n vec2 frameUV;\n frameUV.x = (stripUV.x - (holeZone + marginX * 2.0) - centerOffset) / frameZoneX;\n frameUV.y = (localY - marginY) / (1.0 - marginY * 2.0);\n\n float holeH = 0.01;\n float holeSpacing = frameH * 0.1;\n\n float holeRow = step(mod(stripUV.y, holeSpacing), holeH);\n\n bool leftHole = stripUV.x < holeZone * 0.8;\n bool rightHole = stripUV.x > 1.0 - holeZone * 0.8;\n\n bool isHole = holeRow > 0.5 && (leftHole || rightHole);\n if (isHole) {\n color = vec3(1.0);\n }\n else if (insideFrame) {\n color = texture2D(uTexture, frameUV).rgb;\n }\n else {\n color = vec3(0.0);\n }\n\n gl_FragColor = vec4(color, 1.0);\n}\n`;\n\nexport const FILM_STRIP_PRO_UNIFORMS = {\n uTime: { value: 0, type: \"f32\" },\n framesPerScreen: { value: 2.0, type: \"f32\" },\n scrollSpeed: { value: 0.35, type: \"f32\" },\n gateWeave: { value: 0.6, type: \"f32\" },\n};\n\nexport const BAD_SIGNAL_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nfloat rand(vec2 co) {\n return fract(sin(dot(co, vec2(12.9898,78.233))) * 43758.5453);\n}\n\nfloat noise(float y) {\n return rand(vec2(y, uTime));\n}\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n float flicker = 0.9 + 0.1 * sin(uTime * 30.0);\n float lineNoise = noise(floor(uv.y * 200.0));\n uv.x += (lineNoise - 0.5) * 0.03;\n uv.x += sin(uv.y * 40.0 + uTime * 10.0) * 0.005;\n float rgbShift = 0.004 * sin(uTime * 5.0);\n\n vec4 colR = texture2D(uTexture, uv + vec2(rgbShift, 0.0));\n vec4 colG = texture2D(uTexture, uv);\n vec4 colB = texture2D(uTexture, uv - vec2(rgbShift, 0.0));\n\n vec4 color;\n color.r = colR.r;\n color.g = colG.g;\n color.b = colB.b;\n color.a = colG.a;\n float staticNoise = rand(uv * uTime) * 0.08;\n color.rgb += staticNoise;\n float scanline = sin(uv.y * 800.0) * 0.04;\n color.rgb -= scanline;\n color.rgb *= flicker;\n\n gl_FragColor = color;\n}\n\n`;\n\nexport const BAD_SIGNAL_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n};\n\nexport const OMNIFLEXION_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime;\n\n/* Configuración */\nuniform float strength; // fuerza de la omniflexión\nuniform float frequency; // frecuencia de ondas\nuniform float speed; // velocidad animación\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n vec2 center = vec2(0.5);\n\n vec2 dir = uv - center;\n float dist = length(dir);\n float wave =\n sin(dist * frequency - uTime * speed) *\n strength;\n\n float lens = dist * dist;\n\n vec2 flexUV = uv + normalize(dir) * wave * lens;\n vec4 color = texture2D(uTexture, flexUV);\n\n gl_FragColor = color;\n}\n\n`;\n\nexport const OMNIFLEXION_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n\n strength: { value: 0.08, type: \"f32\" },\n frequency: { value: 18.0, type: \"f32\" },\n speed: { value: 3.5, type: \"f32\" },\n};\n\nexport const INVERSE_APERTURE_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime;\n\nuniform float feather;\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n\n vec2 center = vec2(0.28, 0.48);\n\n float dist = distance(uv, center);\n\n float maxRadius = 0.8;\n\n float radius = mix(maxRadius, 0.0, uTime);\n\n float mask = smoothstep(\n radius - feather,\n radius + feather,\n dist\n );\n\n vec4 color = texture2D(uTexture, uv);\n\n gl_FragColor = vec4(color.rgb * mask, color.a);\n}\n\n`;\n\nexport const INVERSE_APERTURE_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n feather: { value: 0.03, type: \"f32\" },\n};\n\nexport const CURTAIN_OPEN_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime;\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n\n float openPhase = smoothstep(0.0, 0.6, uTime);\n float zoomPhase = smoothstep(0.6, 1.0, uTime);\n\n float zoom =\n 1.0 +\n sin(zoomPhase * 3.141592) * 0.2;\n\n vec2 center = vec2(0.28, 0.35);\n vec2 zoomUV = (uv - center) / zoom + center;\n\n vec4 tex = texture2D(uTexture, zoomUV);\n\n float centerY = 0.48;\n float halfOpen = openPhase * 0.5;\n\n float mask = step(abs(zoomUV.y - centerY), halfOpen);\n\n gl_FragColor = vec4(tex.rgb * mask, tex.a);\n}\n\n`;\n\nexport const CURTAIN_OPEN_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n};\n\nexport const CURTAIN_BLUR_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime;\n\nvec4 blur9(sampler2D tex, vec2 uv, vec2 resolution, float radius)\n{\n vec4 color = vec4(0.0);\n vec2 off = radius / resolution;\n\n color += texture2D(tex, uv + off * vec2(-1.0, -1.0)) * 0.0625;\n color += texture2D(tex, uv + off * vec2( 0.0, -1.0)) * 0.125;\n color += texture2D(tex, uv + off * vec2( 1.0, -1.0)) * 0.0625;\n\n color += texture2D(tex, uv + off * vec2(-1.0, 0.0)) * 0.125;\n color += texture2D(tex, uv) * 0.25;\n color += texture2D(tex, uv + off * vec2( 1.0, 0.0)) * 0.125;\n\n color += texture2D(tex, uv + off * vec2(-1.0, 1.0)) * 0.0625;\n color += texture2D(tex, uv + off * vec2( 0.0, 1.0)) * 0.125;\n color += texture2D(tex, uv + off * vec2( 1.0, 1.0)) * 0.0625;\n\n return color;\n}\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n\n float openPhase = smoothstep(0.0, 0.3, uTime);\n float zoomPhase = smoothstep(0.3, 1.0, uTime);\n\n float zoom =\n 1.0 +\n sin(zoomPhase * 3.141592) * 0.2;\n\n vec2 center = vec2(0.28, 0.35);\n vec2 zoomUV = (uv - center) / zoom + center;\n\n float blurAmount = mix(10.0, 0.0, openPhase);\n\n vec4 blurred =\n blur9(uTexture, zoomUV, vec2(1024.0, 1024.0), blurAmount);\n\n float pulse =\n (sin(uTime * 2.0) * 0.5 + 0.5) * 0.8;\n blurred.rgb *= (1.0 + pulse);\n float centerY = 0.48;\n float halfOpen = openPhase * 0.5;\n\n float mask = step(abs(zoomUV.y - centerY), halfOpen);\n\n gl_FragColor = vec4(blurred.rgb * mask, blurred.a);\n}\n\n`;\n\nexport const CURTAIN_BLUR_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n};\n\nexport const DISTORT_V2_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\n\nuniform float strength;\n\nuniform float frequency;\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n\n float waveX = sin((uv.y + uTime * 0.6) * frequency) * strength;\n float waveY = cos((uv.x + uTime * 0.4) * frequency) * strength;\n\n vec2 distortedUV = uv + vec2(waveX, waveY);\n\n distortedUV = clamp(distortedUV, 0.0, 1.0);\n\n vec4 color = texture2D(uTexture, distortedUV);\n\n gl_FragColor = color;\n}\n`;\n\nexport const DISTORT_V2_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n\n strength: { value: 0.015, type: \"f32\" },\n frequency: { value: 10.0, type: \"f32\" },\n};\nexport const LIGHTNING_FRAGMENT = `\nprecision mediump float;\n\nvarying vec2 vTextureCoord;\nvarying vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime;\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n vec2 center = vec2(0.28, 0.45);\n\n float dist = distance(uv, center);\n\n float speed = 0.7;\n float progress = mod(uTime * speed, 1.0);\n\n float width = mix(0.01, 0.07, progress);\n\n float lightning = smoothstep(progress + width, progress, dist);\n\n float noise = sin((uv.x + uv.y) * 30.0 + uTime * 12.0);\n lightning *= noise * 0.5 + 0.5;\n\n float explosion = smoothstep(0.85, 1.0, progress);\n float burst = explosion * smoothstep(0.25, 0.0, dist);\n\n vec3 lightningColor = vec3(1.0, 0.9, 0.6) * lightning * 2.5;\n vec3 explosionColor = vec3(1.0, 0.4, 0.2) * burst * 4.0;\n\n vec4 base = texture2D(uTexture, uv);\n\n gl_FragColor = vec4(base.rgb + lightningColor + explosionColor, base.a);\n}\n`;\n\nexport const LIGHTNING_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n};\n\nexport const LIGHTNING_VEINS_FRAGMENT = `\nprecision mediump float;\n\nvarying vec2 vTextureCoord;\nvarying vec4 vColor;\n\nuniform sampler2D uTexture;\nuniform float uTime;\n\nfloat hash(vec2 p) {\n return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);\n}\n\nfloat noise(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n\n float a = hash(i);\n float b = hash(i + vec2(1.0, 0.0));\n float c = hash(i + vec2(0.0, 1.0));\n float d = hash(i + vec2(1.0, 1.0));\n\n vec2 u = f * f * (3.0 - 2.0 * f);\n\n return mix(a, b, u.x) +\n (c - a) * u.y * (1.0 - u.x) +\n (d - b) * u.x * u.y;\n}\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n vec2 center = vec2(0.5);\n\n vec2 dir = uv - center;\n float dist = length(dir);\n float t = uTime * 1.5;\n\n float veinNoise =\n noise(dir * 6.0 + t) * 0.6 +\n noise(dir * 12.0 - t * 1.3) * 0.3;\n\n float warpedDist = dist + veinNoise * 0.08;\n\n float thickness = 0.04 + veinNoise * 0.02;\n\n float lightning =\n smoothstep(thickness, 0.0, warpedDist);\n\n float branches =\n smoothstep(0.02, 0.0,\n abs(noise(dir * 20.0 + t) - 0.5));\n\n lightning += branches * 0.35;\n\n float pulse = sin(uTime * 10.0) * 0.3 + 0.7;\n lightning *= pulse;\n\n vec3 veinColor =\n vec3(0.6, 0.85, 1.0) * lightning * 2.5;\n\n vec4 base = texture2D(uTexture, uv);\n\n gl_FragColor =\n vec4(base.rgb + veinColor, base.a);\n}\n`;\n\nexport const LIGHTNING_VEINS_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n};\n\nexport const PIXEL_ERROR_FRAGMENT = `\nprecision mediump float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\n\nfloat rand(float x)\n{\n return fract(sin(x) * 43758.5453123);\n}\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n\n float pixelRows = 120.0;\n float row = floor(uv.y * pixelRows) / pixelRows;\n\n float offset =\n sin(row * 40.0 + uTime * 3.0) *\n 0.015;\n\n offset += (rand(row * 10.0) - 0.5) * 0.01;\n\n vec2 distortedUV = vec2(uv.x + offset, uv.y);\n\n distortedUV = clamp(distortedUV, 0.0, 1.0);\n\n vec4 color = texture2D(uTexture, distortedUV);\n\n gl_FragColor = color;\n}\n`;\n\nexport const PIXEL_ERROR_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n};\n\nexport const NEON_FLASH_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float uIntensity;\n\nuniform float neonR;\nuniform float neonG;\nuniform float neonB;\n\nvoid main(void)\n{\n vec4 base = texture2D(uTexture, vTextureCoord);\n\n float speed = 4.2; \n float t = fract(uTime * speed); \n\n float rise = smoothstep(0.0, 0.25, t);\n float fall = smoothstep(0.85, 0.55, t);\n float flash = rise * fall;\n\n flash = mix(0.25, 1.0, flash);\n\n flash *= uIntensity;\n\n base.r += base.r * neonR * flash;\n base.g += base.g * neonG * flash;\n base.b += base.b * neonB * flash;\n\n gl_FragColor = base;\n}\n`;\n\nexport const NEON_FLASH_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uIntensity: { value: 1.8, type: \"f32\" },\n\n neonR: { value: 0.1, type: \"f32\" },\n neonG: { value: 0.9, type: \"f32\" },\n neonB: { value: 1.0, type: \"f32\" },\n};\n\nexport const WAVE_DISTORT_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float uStrength;\nuniform float uSpeed;\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n float time = uTime * uSpeed;\n\n float wave = sin((uv.y * 18.0) - time);\n\n float offsetX = wave * uStrength;\n\n vec2 distortedUV = uv + vec2(offsetX, 0.0);\n\n distortedUV = clamp(distortedUV, 0.0, 1.0);\n\n vec4 color = texture2D(uTexture, distortedUV);\n\n gl_FragColor = color;\n}\n`;\n\nexport const WAVE_DISTORT_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uStrength: { value: 0.02, type: \"f32\" },\n uSpeed: { value: 20.0, type: \"f32\" },\n};\n\nexport const BOUNCING_BALLS_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\n\nconst int BALL_COUNT = 10;\nfloat radius = 0.05;\nfloat border = 0.006;\n\nvec2 bounce(vec2 p)\n{\n return abs(fract(p) * 2.0 - 1.0);\n}\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n\n /* Textura base */\n vec4 color = texture2D(uTexture, uv);\n\n float ballsAlpha = 0.0;\n\n for (int i = 0; i < BALL_COUNT; i++)\n {\n float id = float(i) + 1.0;\n\n vec2 speed = vec2(\n 0.3 + id * 0.12,\n 0.25 + id * 0.15\n );\n\n vec2 pos = bounce(vec2(\n uTime * speed.x + id * 0.17,\n uTime * speed.y + id * 0.29\n ));\n\n float d = distance(uv, pos);\n\n float edge =\n smoothstep(radius, radius - border, d) -\n smoothstep(radius - border, radius - border - 0.01, d);\n\n ballsAlpha += edge;\n }\n\n ballsAlpha = clamp(ballsAlpha, 0.0, 1.0);\n color.rgb = mix(color.rgb, vec3(1.0), ballsAlpha);\n\n gl_FragColor = color;\n}\n`;\n\nexport const BOUNCING_BALLS_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n};\n\nexport const WATER_REFLECTION_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float uWaveStrength;\nuniform float uWaveSpeed;\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n\n if (uv.y < 0.5)\n {\n gl_FragColor = texture2D(uTexture, uv);\n return;\n }\n\n vec2 reflectUV = uv;\n reflectUV.y = 1.0 - uv.y;\n\n float wave =\n sin(reflectUV.y * 30.0 + uTime * uWaveSpeed) *\n uWaveStrength;\n\n reflectUV.x += wave;\n reflectUV = clamp(reflectUV, 0.0, 1.0);\n\n vec4 reflectColor = texture2D(uTexture, reflectUV);\n\n float fade = smoothstep(0.5, 1.0, uv.y);\n\n reflectColor.rgb *= (1.0 - fade) * 0.85;\n reflectColor.a *= (1.0 - fade);\n\n gl_FragColor = reflectColor;\n}\n`;\n\nexport const WATER_REFLECTION_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uWaveStrength: { value: 0.02, type: \"f32\" },\n uWaveSpeed: { value: 2.5, type: \"f32\" },\n};\n\nexport const DARK_ERROR_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float uStrength;\n\nfloat rand(vec2 co)\n{\n return fract(sin(dot(co, vec2(12.9898,78.233))) * 43758.5453);\n}\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n\n float t = floor(uTime * 6.0);\n\n float blockSize = 0.08;\n float blockY = floor(uv.y / blockSize) * blockSize;\n\n float noise = rand(vec2(blockY, t));\n\n float shift =\n step(0.65, noise) *\n (rand(vec2(blockY, t + 1.0)) - 0.5) *\n uStrength;\n\n vec2 glitchUV = uv + vec2(shift, 0.0);\n glitchUV = clamp(glitchUV, 0.0, 1.0);\n\n vec4 color = texture2D(uTexture, glitchUV);\n float darkPulse =\n step(0.75, noise) *\n (0.4 + rand(vec2(uv.x, t)) * 0.6);\n\n color.rgb *= 1.0 - darkPulse;\n float pixelNoise = rand(uv * t);\n color.rgb *= 1.0 - step(0.96, pixelNoise) * 0.8;\n\n gl_FragColor = color;\n}\n`;\n\nexport const DARK_ERROR_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uStrength: { value: 0.08, type: \"f32\" },\n};\n\nexport const SCALE_MOVE_BLUR_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\n\nvec4 blur5(sampler2D tex, vec2 uv, float strength)\n{\n vec4 col = vec4(0.0);\n float s = strength;\n\n col += texture2D(tex, uv + vec2(-s, -s)) * 0.05;\n col += texture2D(tex, uv + vec2( 0.0, -s)) * 0.10;\n col += texture2D(tex, uv + vec2( s, -s)) * 0.05;\n\n col += texture2D(tex, uv + vec2(-s, 0.0)) * 0.10;\n col += texture2D(tex, uv) * 0.40;\n col += texture2D(tex, uv + vec2( s, 0.0)) * 0.10;\n\n col += texture2D(tex, uv + vec2(-s, s)) * 0.05;\n col += texture2D(tex, uv + vec2( 0.0, s)) * 0.10;\n col += texture2D(tex, uv + vec2( s, s)) * 0.05;\n\n return col;\n}\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n vec2 center = vec2(0.5, 0.5);\n\n float t = clamp(uTime, 0.0, 1.0);\n float zoomPhase = smoothstep(0.0, 0.5, t) *\n (1.0 - smoothstep(0.5, 1.0, t));\n\n float scale = 1.0 + zoomPhase * 0.5;\n\n vec2 offset = vec2(0.0);\n\n if (t < 0.33)\n {\n offset = vec2(0.12 * (t / 0.33), 0.0);\n }\n else if (t < 0.66)\n {\n offset = vec2(\n 0.12 * (1.0 - (t - 0.33) / 0.33),\n 0.0\n );\n }\n else\n {\n offset = vec2(\n 0.08 * ((t - 0.66) / 0.34),\n -0.08 * ((t - 0.66) / 0.34)\n );\n }\n\n offset *= zoomPhase;\n vec2 transformedUV =\n (uv - center) / scale +\n center -\n offset;\n\n transformedUV = clamp(transformedUV, 0.0, 1.0);\n float blurStrength = zoomPhase * 0.015;\n\n vec4 color = blur5(uTexture, transformedUV, blurStrength);\n\n gl_FragColor = color;\n}\n`;\n\nexport const SCALE_MOVE_BLUR_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n};\n\nexport const PAPER_BREAK_REVEAL_FRAGMENT = `\nprecision highp float;\n\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float uCutPos;\n\n\nfloat noise(float x)\n{\n return sin(x * 28.0) * 0.035;\n}\n\nvec4 blur5(sampler2D tex, vec2 uv, float s)\n{\n vec4 c = vec4(0.0);\n c += texture2D(tex, uv + vec2(-s, -s)) * 0.05;\n c += texture2D(tex, uv + vec2( 0.0, -s)) * 0.10;\n c += texture2D(tex, uv + vec2( s, -s)) * 0.05;\n c += texture2D(tex, uv + vec2(-s, 0.0)) * 0.10;\n c += texture2D(tex, uv) * 0.40;\n c += texture2D(tex, uv + vec2( s, 0.0)) * 0.10;\n c += texture2D(tex, uv + vec2(-s, s)) * 0.05;\n c += texture2D(tex, uv + vec2( 0.0, s)) * 0.10;\n c += texture2D(tex, uv + vec2( s, s)) * 0.05;\n return c;\n}\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n vec2 center = vec2(0.5);\n float movePhase = smoothstep(0.0, 0.45, uTime);\n float settle = smoothstep(0.45, 0.6, uTime);\n float cutPhase = smoothstep(0.7, 0.9, uTime);\n float cleanPhase = smoothstep(0.9, 1.0, uTime);\n float scale = mix(1.5, 1.0, settle);\n\n float moveAlive = 1.0 - settle;\n\n vec2 movement = vec2(\n sin(uTime * 6.0) * 0.18 * moveAlive,\n 0.0\n );\n\n vec2 uvScaled =\n (uv - center) / scale +\n center -\n movement;\n\n uvScaled = clamp(uvScaled, 0.0, 1.0);\n\n float blurStrength = (1.0 - cleanPhase) * 0.025;\n vec4 blurred = blur5(uTexture, uvScaled, blurStrength);\n vec4 clean = texture2D(uTexture, uv);\n\n float tearLine =\n mix(\n uCutPos,\n uCutPos + noise(uv.y + uTime * 3.0),\n cutPhase\n );\n\n tearLine = clamp(tearLine, uCutPos - 0.05, uCutPos + 0.05);\n\n float split = cutPhase * 0.35;\n\n vec2 leftUV = uv;\n vec2 rightUV = uv;\n\n leftUV.x -= split * step(uv.x, tearLine);\n rightUV.x += split * step(tearLine, uv.x);\n\n leftUV = clamp(leftUV, 0.0, 1.0);\n rightUV = clamp(rightUV, 0.0, 1.0);\n\n vec4 left = texture2D(uTexture, leftUV);\n vec4 right = texture2D(uTexture, rightUV);\n\n float cutMask =\n smoothstep(tearLine - 0.02, tearLine + 0.02, uv.x);\n\n vec4 broken = mix(left, right, cutMask);\n\n float edge =\n smoothstep(0.0, 0.02, abs(uv.x - tearLine)) *\n (1.0 - smoothstep(0.02, 0.05, abs(uv.x - tearLine)));\n\n vec3 edgeColor = vec3(1.0) * edge * cutPhase;\n\n broken.rgb += edgeColor;\n\n vec4 result = mix(blurred, broken, cutPhase);\n result = mix(result, clean, cleanPhase);\n\n gl_FragColor = result;\n}\n`;\n\nexport const PAPER_BREAK_REVEAL_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uCutPos: { value: 0.28, type: \"f32\" },\n};\n\nexport const GRAFFITI_FRAGMENT = `\n#ifdef GL_ES\nprecision mediump float;\n#endif\n\nvarying vec2 vTextureCoord;\n\nuniform float uTime;\nuniform sampler2D uTexture;\n\nfloat rand(vec2 st)\n{\n return fract(sin(dot(st, vec2(12.9898,78.233))) * 43758.5453123);\n}\n\nfloat noise(vec2 st)\n{\n vec2 i = floor(st);\n vec2 f = fract(st);\n\n float a = rand(i);\n float b = rand(i + vec2(1.0, 0.0));\n float c = rand(i + vec2(0.0, 1.0));\n float d = rand(i + vec2(1.0, 1.0));\n\n vec2 u = f * f * (3.0 - 2.0 * f);\n\n return mix(a, b, u.x) +\n (c - a) * u.y * (1.0 - u.x) +\n (d - b) * u.x * u.y;\n}\n\nfloat spray(vec2 st, float radius)\n{\n float dist = length(st - vec2(0.28, 0.5));\n float base = smoothstep(radius, radius - 0.06, dist);\n\n float speckle =\n noise(st * 45.0 + uTime * 3.0) *\n noise(st * 90.0);\n\n return clamp(base + speckle * 0.7, 0.0, 1.0);\n}\n\nfloat drips(vec2 st, float mask)\n{\n float column = noise(vec2(st.x * 25.0, 0.0));\n\n float drip =\n smoothstep(0.3, 0.7, column) *\n smoothstep(0.1, 1.0, 1.0 - st.y);\n\n float flow =\n noise(vec2(st.x * 35.0, st.y * 6.0 + uTime * 2.5));\n\n return drip * flow * mask;\n}\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord;\n\n vec4 base = texture2D(uTexture, uv);\n\n vec3 graffitiColor = vec3(1.0, 0.0, 0.5);\n\n float reveal = smoothstep(0.0, 1.0, uTime);\n\n float sprayMask =\n spray(uv, 0.35 * reveal);\n\n float dripMask =\n drips(uv, sprayMask) * reveal;\n\n float graffitiMask =\n clamp(sprayMask + dripMask * 1.3, 0.0, 1.0);\n\n vec3 graffiti =\n graffitiColor * graffitiMask;\n\n vec3 Color =\n base.rgb + graffiti;\n\n gl_FragColor = vec4(Color, base.a);\n}\n`;\n\nexport const GRAFFITI_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n};\n\nexport const LASER_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform vec3 uColor;\nuniform float uThickness;\nuniform float uIntensity;\n\nfloat noise(float x) {\n return sin(x * 40.0) * 0.005;\n}\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n vec4 baseColor = texture2D(uTexture, uv);\n\n float beamY = 0.48 + noise(uv.x + uTime * 5.0);\n\n float dist = abs(uv.y - beamY);\n\n float core = smoothstep(uThickness, 0.0, dist);\n\n float glow = smoothstep(uThickness * 4.0, uThickness, dist);\n\n float pulse = 0.6 + 0.4 * sin(uTime * 10.0);\n\n float laserMask = (core + glow * uIntensity) * pulse;\n\n vec3 laserColor = uColor * laserMask;\n\n vec3 color = baseColor.rgb + laserColor;\n\n gl_FragColor = vec4(color, baseColor.a);\n}\n`;\n\nexport const LASER_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uColor: { value: [1.0, 0.0, 0.2], type: \"vec3<f32>\" },\n uThickness: { value: 0.02, type: \"f32\" },\n uIntensity: { value: 1.5, type: \"f32\" },\n};\n\nexport const WAVE_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float uStrength;\nuniform float uFrequency;\nuniform float uSpeed;\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n vec2 center = vec2(0.5, 0.5);\n\n float dist = distance(uv, center);\n\n float wave =\n sin(dist * uFrequency - uTime * uSpeed) *\n uStrength *\n smoothstep(1.0, 0.0, dist);\n\n vec2 dir = normalize(uv - center);\n\n vec2 distortedUV = uv + dir * wave;\n\n vec4 color = texture2D(uTexture, distortedUV);\n\n gl_FragColor = color;\n}\n`;\n\nexport const WAVE_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uStrength: { value: 0.02, type: \"f32\" },\n uFrequency: { value: 20.0, type: \"f32\" },\n uSpeed: { value: 4.0, type: \"f32\" },\n};\n\nexport const SPARKS_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float uDensity;\nuniform float uSpeed;\nuniform float uSize;\n\nfloat hash(vec2 p) {\n return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);\n}\nvec3 randomColor(float h) {\n return vec3(\n 0.5 + 0.5 * sin(h * 6.2831),\n 0.5 + 0.5 * sin(h * 6.2831 + 2.1),\n 0.5 + 0.5 * sin(h * 6.2831 + 4.2)\n );\n}\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n vec4 base = texture2D(uTexture, uv);\n\n vec3 sparkColor = vec3(0.0);\n float sparkAlpha = 0.0;\n\n vec2 grid = floor(uv * uDensity);\n vec2 id = grid;\n\n float h = hash(id);\n\n vec2 sparkPos = fract(vec2(\n h,\n h + uTime * uSpeed\n ));\n\n float d = distance(fract(uv * uDensity), sparkPos);\n\n float spark = smoothstep(uSize, 0.0, d);\n\n vec3 color = randomColor(h) * spark;\n\n sparkColor += color;\n sparkAlpha += spark;\n\n vec3 colorValue = base.rgb + sparkColor;\n\n gl_FragColor = vec4(colorValue, max(base.a, sparkAlpha));\n}\n`;\n\nexport const SPARKS_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uDensity: { value: 30.0, type: \"f32\" },\n uSpeed: { value: 2.5, type: \"f32\" },\n uSize: { value: 0.15, type: \"f32\" },\n};\n\nexport const HOLOGRAM_SCAN_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform vec3 uColor; \nuniform float uScanWidth; \nuniform float uIntensity; \n\nfloat noise(float x) {\n return sin(x * 120.0) * 0.02;\n}\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n vec4 base = texture2D(uTexture, uv);\n\n float scanPos = fract(uTime * 0.5);\n float scanLine = smoothstep(\n uScanWidth,\n 0.0,\n abs(uv.y - scanPos)\n );\n\n float lines = 0.5 + 0.5 * sin(uv.y * 300.0 + uTime * 10.0);\n\n float flicker = 0.9 + 0.1 * sin(uTime * 50.0);\n\n float holo =\n scanLine +\n lines * 0.2 +\n noise(uv.x + uTime) * 0.5;\n\n holo *= uIntensity * flicker;\n\n vec3 holoColor = uColor * holo;\n\n vec3 colorValue = base.rgb + holoColor;\n\n gl_FragColor = vec4(colorValue, base.a);\n}\n`;\n\nexport const HOLOGRAM_SCAN_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uColor: { value: [0.0, 1.0, 1.0], type: \"vec3<f32>\" },\n uScanWidth: { value: 0.02, type: \"f32\" },\n uIntensity: { value: 1.2, type: \"f32\" },\n};\n\nexport const RETRO_70S_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float uGrain; \nuniform float uFade; \nuniform float uVignette; \n\nfloat noise(vec2 p) {\n return fract(sin(dot(p, vec2(12.9898,78.233)) + uTime) * 43758.5453);\n}\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n vec4 color = texture2D(uTexture, uv);\n\n vec3 faded = mix(color.rgb, vec3(\n dot(color.rgb, vec3(0.393, 0.769, 0.189)),\n dot(color.rgb, vec3(0.349, 0.686, 0.168)),\n dot(color.rgb, vec3(0.272, 0.534, 0.131))\n ), uFade);\n\n float grain = (noise(uv * 500.0) - 0.5) * uGrain;\n faded += grain;\n\n float flicker = 0.97 + 0.03 * sin(uTime * 60.0);\n faded *= flicker;\n\n float dist = distance(uv, vec2(0.5));\n float vignette = smoothstep(0.8, uVignette, dist);\n faded *= 1.0 - vignette;\n\n gl_FragColor = vec4(faded, color.a);\n}\n`;\n\nexport const RETRO_70S_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uGrain: { value: 0.08, type: \"f32\" },\n uFade: { value: 0.6, type: \"f32\" },\n uVignette: { value: 1.0, type: \"f32\" },\n};\n\nexport const IG_OUTLINE_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uThickness;\nuniform vec3 uOutlineColor;\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n vec2 px = vec2(uThickness) / vec2(1024.0, 1024.0);\n\n vec4 centerTex = texture2D(uTexture, uv);\n vec3 center = centerTex.rgb;\n\n vec3 up = texture2D(uTexture, uv + vec2(0.0, px.y)).rgb;\n vec3 down = texture2D(uTexture, uv - vec2(0.0, px.y)).rgb;\n vec3 left = texture2D(uTexture, uv - vec2(px.x, 0.0)).rgb;\n vec3 right = texture2D(uTexture, uv + vec2(px.x, 0.0)).rgb;\n\n float edge =\n length(center - up) +\n length(center - down) +\n length(center - left) +\n length(center - right);\n\n edge = smoothstep(0.15, 0.4, edge);\n\n vec3 colorValue = mix(center, uOutlineColor, edge);\n gl_FragColor = vec4(colorValue, centerTex.a);\n}\n\n`;\n\nexport const IG_OUTLINE_UNIFORMS = {\n uThickness: { value: 1.5, type: \"f32\" },\n uOutlineColor: { value: [1.0, 1.0, 1.0], type: \"vec3<f32>\" },\n};\n\nexport const RANDOM_ACCENTS_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float uDensity;\nuniform float uSize;\nuniform float uIntensity;\nuniform vec3 uColorA;\nuniform vec3 uColorB;\n\nfloat hash(vec2 p) {\n return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);\n}\n\nvec3 accentColor(float h) {\n return mix(uColorA, uColorB, fract(h * 7.0));\n}\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n vec4 base = texture2D(uTexture, uv);\n\n vec2 gridUV = floor(uv * uDensity);\n float h = hash(gridUV);\n\n vec2 offset = vec2(\n fract(h * 13.3),\n fract(h * 7.7)\n );\n\n vec2 accentUV = fract(uv * uDensity) - offset;\n\n float dist = length(accentUV);\n\n float accent = smoothstep(uSize, 0.0, dist);\n\n accent *= 0.6 + 0.4 * sin(uTime * 10.0 + h * 6.28);\n\n vec3 color = accentColor(h) * accent * uIntensity;\n\n float alpha = accent;\n\n gl_FragColor = vec4(color + base.rgb, max(base.a, alpha));\n}\n`;\n\nexport const RANDOM_ACCENTS_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uDensity: { value: 20.0, type: \"f32\" },\n uSize: { value: 0.25, type: \"f32\" },\n uIntensity: { value: 1.2, type: \"f32\" },\n uColorA: { value: [1.0, 0.2, 0.6], type: \"vec3<f32>\" },\n uColorB: { value: [0.2, 0.8, 1.0], type: \"vec3<f32>\" },\n};\n\nexport const SOLUTION_EFFECT_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform vec3 uColorA;\nuniform vec3 uColorB;\nuniform float uIntensity;\n\nfloat noise(vec2 st) {\n return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123);\n}\n\nvec2 swirl(vec2 uv, float t) {\n vec2 center = vec2(0.5);\n vec2 diff = uv - center;\n float angle = 0.5 * t * length(diff);\n float s = sin(angle);\n float c = cos(angle);\n return center + vec2(c*diff.x - s*diff.y, s*diff.x + c*diff.y);\n}\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n vec2 uvSwirl = swirl(uv, uTime);\n\n vec4 base = texture2D(uTexture, uvSwirl);\n\n float n = noise(uv * 20.0 + uTime * 2.0);\n vec3 liquid = mix(uColorA, uColorB, n);\n\n vec3 colorValue = mix(base.rgb, liquid, uIntensity * n);\n\n gl_FragColor = vec4(colorValue, base.a);\n}\n`;\n\nexport const SOLUTION_EFFECT_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uColorA: { value: [0.2, 0.8, 1.0], type: \"vec3<f32>\" },\n uColorB: { value: [1.0, 0.2, 0.6], type: \"vec3<f32>\" },\n uIntensity: { value: 0.8, type: \"f32\" },\n};\n\nexport const TV_SCANLINES_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float uLineThickness;\nuniform float uLineIntensity;\nuniform float uNoiseIntensity;\nuniform vec3 uLineColor;\n\nfloat rand(vec2 p){\n return fract(sin(dot(p ,vec2(12.9898,78.233))) * 43758.5453);\n}\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n vec4 tex = texture2D(uTexture, uv);\n vec3 base = tex.rgb;\n\n float line = sin(uv.y * 800.0 * uLineThickness) * 0.5 + 0.5;\n line = mix(1.0, line, uLineIntensity);\n\n float noise =\n (rand(vec2(uTime, uv.y * 1000.0)) - 0.5) * uNoiseIntensity;\n\n vec3 colorValue = base * line + noise;\n\n gl_FragColor = vec4(colorValue, tex.a);\n}\n`;\n\nexport const TV_SCANLINES_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uLineThickness: { value: 2.0, type: \"f32\" },\n uLineIntensity: { value: 0.6, type: \"f32\" },\n uNoiseIntensity: { value: 0.05, type: \"f32\" },\n uLineColor: { value: [0.8, 1.0, 0.8], type: \"vec3<f32>\" },\n};\n\nexport const HDR_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uExposure;\nuniform float uSaturation;\nuniform float uContrast;\n\nvec3 adjustSaturation(vec3 color, float sat) {\n float grey = dot(color, vec3(0.299, 0.587, 0.114));\n return mix(vec3(grey), color, sat);\n}\n\nvec3 adjustContrast(vec3 color, float contrast) {\n return (color - 0.5) * contrast + 0.5;\n}\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n vec4 tex = texture2D(uTexture, uv);\n vec3 color = tex.rgb;\n color *= uExposure;\n\n color = adjustSaturation(color, uSaturation);\n\n color = adjustContrast(color, uContrast);\n\n color = color / (color + vec3(1.0));\n\n gl_FragColor = vec4(color, tex.a);\n}\n`;\n\nexport const HDR_UNIFORMS = {\n uExposure: { value: 1.2, type: \"f32\" },\n uSaturation: { value: 4.3, type: \"f32\" },\n uContrast: { value: 2.2, type: \"f32\" },\n};\n\nexport const BLACK_FLASH_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float uIntensity;\nuniform float uDuration;\n\nvoid main() {\n vec2 uv = vTextureCoord;\n vec4 base = texture2D(uTexture, uv);\n\n float flash = smoothstep(0.0, uDuration * 0.5, mod(uTime, uDuration)) *\n (1.0 - smoothstep(uDuration * 0.5, uDuration, mod(uTime, uDuration)));\n\n flash *= uIntensity;\n\n vec3 color = mix(base.rgb, vec3(0.0), flash);\n\n gl_FragColor = vec4(color, base.a);\n}\n`;\n\nexport const BLACK_FLASH_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uIntensity: { value: 0.7, type: \"f32\" },\n uDuration: { value: 0.2, type: \"f32\" },\n};\n\nexport const BRIGHT_PULSE_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float uPulseScale; \nuniform float uBlurStrength; \nuniform float uGlowBoost; \n\nvec4 blur3(sampler2D tex, vec2 uv, float s) {\n vec4 c = vec4(0.0);\n c += texture2D(tex, uv + vec2(-s, -s)) * 0.0625;\n c += texture2D(tex, uv + vec2( 0.0, -s)) * 0.125;\n c += texture2D(tex, uv + vec2( s, -s)) * 0.0625;\n c += texture2D(tex, uv + vec2(-s, 0.0)) * 0.125;\n c += texture2D(tex, uv) * 0.25;\n c += texture2D(tex, uv + vec2( s, 0.0)) * 0.125;\n c += texture2D(tex, uv + vec2(-s, s)) * 0.0625;\n c += texture2D(tex, uv + vec2( 0.0, s)) * 0.125;\n c += texture2D(tex, uv + vec2( s, s)) * 0.0625;\n return c * uGlowBoost;\n}\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n float scale = 1.0 + uPulseScale * (0.5 + 0.5 * sin(uTime * 3.0));\n vec2 center = vec2(0.28,0.48); \n vec2 uvScaled = (uv - center) / scale + center;\n uvScaled = clamp(uvScaled, 0.0, 1.0);\n vec4 base = texture2D(uTexture, uvScaled);\n vec4 blurred = blur3(uTexture, uvScaled, uBlurStrength);\n vec4 colorValue = mix(base, blurred, 0.8);\n\n gl_FragColor = colorValue;\n}\n`;\n\nexport const BRIGHT_PULSE_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uPulseScale: { value: 0.2, type: \"f32\" },\n uBlurStrength: { value: 0.02, type: \"f32\" },\n uGlowBoost: { value: 2.0, type: \"f32\" },\n};\nexport const NEGATIVE_DIVISION_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uIntensity; // 0 → original, 1 → negativo completo\nuniform float uContrast; // fuerza de contraste\n\nvoid main() {\n vec2 uv = vTextureCoord;\n vec4 color = texture2D(uTexture, uv);\n vec3 negative = 1.0 - color.rgb;\n\n vec3 contrasted = (negative - 0.5) * uContrast + 0.5;\n\n float maskedIntensity = uIntensity * color.a;\n\n vec3 colorValue =\n mix(color.rgb, contrasted, maskedIntensity);\n\n gl_FragColor = vec4(colorValue, color.a);\n}\n`;\n\nexport const NEGATIVE_DIVISION_UNIFORMS = {\n uIntensity: { value: 1.0, type: \"f32\" },\n uContrast: { value: 2.5, type: \"f32\" },\n};\n\nexport const CAMERA_MOVE_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float uIntensity;\nuniform float uSpeed;\n\nfloat rand(float x){\n return fract(sin(x * 12.9898) * 43758.5453);\n}\n\nvec2 shakeOffset(float time){\n float x = (rand(time * 0.7) - 0.5) * uIntensity;\n float y = (rand(time * 1.3 + 10.0) - 0.5) * uIntensity;\n return vec2(x, y);\n}\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n vec2 offset = shakeOffset(uTime * uSpeed);\n\n vec2 uvMoved = clamp(uv + offset, 0.0, 1.0);\n\n vec4 color = texture2D(uTexture, uvMoved);\n\n gl_FragColor = color;\n}\n\n`;\n\nexport const CAMERA_MOVE_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uIntensity: { value: 1.0, type: \"f32\" },\n uSpeed: { value: 1.0, type: \"f32\" },\n};\nexport const HDR_V2_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uExposure;\nuniform float uBloom;\nuniform float uContrast;\n\nvec3 tonemapReinhard(vec3 color){\n return color / (color + vec3(1.0));\n}\n\nvoid main() {\n vec2 uv = vTextureCoord;\n vec4 tex = texture2D(uTexture, uv);\n\n if (tex.a < 0.01) {\n gl_FragColor = tex;\n return;\n }\n\n vec3 color = tex.rgb;\n\n vec3 bright = max(color - 0.6, 0.0) * uBloom;\n bright = tonemapReinhard(bright);\n\n vec3 hdrColor = color + bright * 0.6;\n\n hdrColor *= uExposure;\n\n hdrColor = (hdrColor - 0.5) * uContrast + 0.5;\n\n hdrColor = clamp(hdrColor, 0.0, 1.0);\n\n gl_FragColor = vec4(hdrColor, tex.a);\n}\n`;\n\nexport const HDR_V2_UNIFORMS = {\n uExposure: { value: 1.0, type: \"f32\" },\n uBloom: { value: 1.5, type: \"f32\" },\n uContrast: { value: 2.0, type: \"f32\" },\n};\n\nexport const FAST_ZOOM_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime; \nuniform float uZoomSpeed; \nuniform float uMaxZoom; \nuniform float uBlurStrength; \n\nvec4 blur3(sampler2D tex, vec2 uv, float s) {\n vec4 c = vec4(0.0);\n c += texture2D(tex, uv + vec2(-s, -s)) * 0.0625;\n c += texture2D(tex, uv + vec2( 0.0, -s)) * 0.125;\n c += texture2D(tex, uv + vec2( s, -s)) * 0.0625;\n c += texture2D(tex, uv + vec2(-s, 0.0)) * 0.125;\n c += texture2D(tex, uv) * 0.25;\n c += texture2D(tex, uv + vec2( s, 0.0)) * 0.125;\n c += texture2D(tex, uv + vec2(-s, s)) * 0.0625;\n c += texture2D(tex, uv + vec2( 0.0, s)) * 0.125;\n c += texture2D(tex, uv + vec2( s, s)) * 0.0625;\n return c;\n}\n\nvoid main() {\n vec2 uv = vTextureCoord;\n vec2 center = vec2(0.28,0.48); \n\n float zoom = 1.0 + (uMaxZoom - 1.0) * smoothstep(0.0, 1.0, sin(uTime * uZoomSpeed));\n\n vec2 uvZoomed = (uv - center) / zoom + center;\n\n uvZoomed = clamp(uvZoomed, 0.0, 1.0);\n\n vec4 color = texture2D(uTexture, uvZoomed);\n\n if (uBlurStrength > 0.0) {\n vec4 blurred = blur3(uTexture, uvZoomed, uBlurStrength);\n color = mix(color, blurred, 0.5);\n }\n\n gl_FragColor = color;\n}\n`;\n\nexport const FAST_ZOOM_UNIFORMS = {\n uTime: { value: 0.0, type: \"f32\" },\n uZoomSpeed: { value: 5.0, type: \"f32\" },\n uMaxZoom: { value: 2.0, type: \"f32\" },\n uBlurStrength: { value: 0.01, type: \"f32\" },\n};\n\nexport const CHROMA_KEY_FRAGMENT = `\nprecision highp float;\n\nvarying vec2 vTextureCoord;\nuniform sampler2D uTexture;\n\nuniform vec3 uKeyColor; \nuniform float uSimilarity; \nuniform float uSpill; \n\nvoid main() {\n vec4 color = texture2D(uTexture, vTextureCoord);\n \n float maxChannel = max(max(uKeyColor.r, uKeyColor.g), uKeyColor.b);\n \n float diff;\n float spillAmount = 0.0;\n \n if (maxChannel == uKeyColor.g && uKeyColor.g > uKeyColor.r && uKeyColor.g > uKeyColor.b) {\n diff = color.g - max(color.r, color.b);\n spillAmount = max(0.0, color.g - max(color.r, color.b));\n color.g -= spillAmount * uSpill;\n \n float avg = (color.r + color.b) * 0.5;\n color.r = mix(color.r, avg, spillAmount);\n color.b = mix(color.b, avg, spillAmount);\n } \n else if (maxChannel == uKeyColor.b && uKeyColor.b > uKeyColor.r && uKeyColor.b > uKeyColor.g) {\n diff = color.b - max(color.r, color.g);\n spillAmount = max(0.0, color.b - max(color.r, color.g));\n color.b -= spillAmount * uSpill;\n \n float avg = (color.r + color.g) * 0.5;\n color.r = mix(color.r, avg, spillAmount);\n color.g = mix(color.g, avg, spillAmount);\n } \n else {\n diff = color.r - max(color.g, color.b);\n spillAmount = max(0.0, color.r - max(color.g, color.b));\n color.r -= spillAmount * uSpill;\n \n float avg = (color.g + color.b) * 0.5;\n color.g = mix(color.g, avg, spillAmount);\n color.b = mix(color.b, avg, spillAmount);\n }\n \n float mask = step(uSimilarity, diff); \n float alpha = 1.0 - mask;\n\n if (diff > uSimilarity) {\n gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n return;\n }\n\n gl_FragColor = vec4(color.rgb, color.a * alpha);\n}\n`;\n\nexport const CHROMA_KEY_UNIFORMS = {\n uKeyColor: { value: [0.176, 0.792, 0.098], type: \"vec3<f32>\" },\n uSimilarity: { value: 0.0, type: \"f32\" },\n uSpill: { value: 0.0, type: \"f32\" },\n};\n\nexport const SELECTIVE_HSL_FRAGMENT = `\nin vec2 vTextureCoord;\nin vec4 vColor;\nuniform sampler2D uTexture;\nout vec4 finalColor;\n\nuniform vec3 uTargetColor;\nuniform float uHueShift;\nuniform float uSatShift;\nuniform float uLightShift;\nuniform float uTolerance;\nuniform float uSoftness;\n\nvec3 rgb2hsl(vec3 c) {\n float maxc = max(max(c.r, c.g), c.b);\n float minc = min(min(c.r, c.g), c.b);\n float h = 0.0;\n float s = 0.0;\n float l = (maxc + minc) * 0.5;\n\n float d = maxc - minc;\n if (d > 0.00001) {\n s = l > 0.5 ? d / (2.0 - maxc - minc) : d / (maxc + minc);\n if (maxc == c.r) {\n h = (c.g - c.b) / d + (c.g < c.b ? 6.0 : 0.0);\n } else if (maxc == c.g) {\n h = (c.b - c.r) / d + 2.0;\n } else {\n h = (c.r - c.g) / d + 4.0;\n }\n h /= 6.0;\n }\n return vec3(h, s, l);\n}\n\nfloat hue2rgb(float p, float q, float t) {\n if (t < 0.0) t += 1.0;\n if (t > 1.0) t -= 1.0;\n if (t < 1.0 / 6.0) return p + (q - p) * 6.0 * t;\n if (t < 1.0 / 2.0) return q;\n if (t < 2.0 / 3.0) return p + (q - p) * (2.0 / 3.0 - t) * 6.0;\n return p;\n}\n\nvec3 hsl2rgb(vec3 hsl) {\n float h = hsl.x;\n float s = hsl.y;\n float l = hsl.z;\n if (s <= 0.00001) return vec3(l);\n float q = l < 0.5 ? l * (1.0 + s) : l + s - l * s;\n float p = 2.0 * l - q;\n return vec3(\n hue2rgb(p, q, h + 1.0 / 3.0),\n hue2rgb(p, q, h),\n hue2rgb(p, q, h - 1.0 / 3.0)\n );\n}\n\nvoid main() {\n vec4 src = texture(uTexture, vTextureCoord);\n float dist = distance(src.rgb, uTargetColor);\n float mask = 1.0 - smoothstep(uTolerance, uTolerance + uSoftness, dist);\n\n vec3 hsl = rgb2hsl(src.rgb);\n hsl.x = mod(hsl.x + (uHueShift / 360.0), 1.0);\n hsl.y = clamp(hsl.y + uSatShift, 0.0, 1.0);\n hsl.z = clamp(hsl.z + uLightShift, 0.0, 1.0);\n vec3 adjusted = hsl2rgb(hsl);\n\n vec3 resultColor = mix(src.rgb, adjusted, mask);\n finalColor = vec4(resultColor, src.a);\n}\n`;\n\nexport const FADE_IN_FRAGMENT = `\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float uDuration;\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n vec4 color = texture2D(uTexture, uv);\n\n float t = clamp(uTime / max(uDuration, 0.0001), 0.0, 1.0);\n float alpha = smoothstep(0.0, 1.0, t);\n\n color.rgb *= alpha;\n color.a *= alpha;\n\n gl_FragColor = color;\n}\n`;\n\nexport const FADE_IN_UNIFORMS: Record<string, { value: any; type: string }> = {\n uTime: { value: 0.0, type: \"f32\" },\n uDuration: { value: 1.0, type: \"f32\" },\n};\n\nexport const FADE_OUT_FRAGMENT = `\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform float uDuration;\n\nvoid main(void)\n{\n vec2 uv = vTextureCoord.xy;\n vec4 color = texture2D(uTexture, uv);\n\n float t = clamp(uTime / max(uDuration, 0.0001), 0.0, 1.0);\n float alpha = smoothstep(1.0, 0.0, t);\n\n color.rgb *= alpha;\n color.a *= alpha;\n\n gl_FragColor = color;\n}\n`;\n\nexport const FADE_OUT_UNIFORMS: Record<string, { value: any; type: string }> = {\n uTime: { value: 0.0, type: \"f32\" },\n uDuration: { value: 1.0, type: \"f32\" },\n};\n","export const vertex = `\nin vec2 aPosition;\nout vec2 vTextureCoord;\n\nuniform vec4 uInputSize;\nuniform vec4 uOutputFrame;\nuniform vec4 uOutputTexture;\n\nvec4 filterVertexPosition( void )\n{\n vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;\n\n position.x = position.x * (2.0 / uOutputTexture.x) - 1.0;\n position.y = position.y * (2.0*uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;\n\n return vec4(position, 0.0, 1.0);\n}\n\nvec2 filterTextureCoord( void )\n{\n return aPosition * (uOutputFrame.zw * uInputSize.zw);\n}\n\nvoid main(void)\n{\n gl_Position = filterVertexPosition();\n vTextureCoord = filterTextureCoord();\n}\n`;\n","import { ColorMatrixFilter } from \"pixi.js\";\n\nexport interface ColorAdjustmentBasic {\n saturation?: number;\n temperature?: number;\n hue?: number;\n brightness?: number;\n contrast?: number;\n shine?: number;\n highlight?: number;\n shadow?: number;\n sharpness?: number;\n vignette?: number;\n fade?: number;\n grain?: number;\n}\n\nexport interface ColorAdjustmentHsl {\n hue?: number;\n saturation?: number;\n lightness?: number;\n selectedColor?: string;\n byColor?: Record<\n string,\n {\n hue?: number;\n saturation?: number;\n lightness?: number;\n }\n >;\n}\n\nexport interface CurvePoint {\n x: number;\n y: number;\n}\n\nexport interface ColorAdjustmentCurves {\n rgb?: CurvePoint[];\n red?: CurvePoint[];\n green?: CurvePoint[];\n blue?: CurvePoint[];\n}\n\nexport interface ColorAdjustment {\n enabled?: boolean;\n type?: \"basic\" | \"hsl\" | \"curves\";\n basic?: ColorAdjustmentBasic;\n hsl?: ColorAdjustmentHsl;\n curves?: ColorAdjustmentCurves;\n}\n\nexport interface ActiveSelectiveHslAdjustment {\n targetColor: string;\n hue: number;\n saturation: number;\n lightness: number;\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\nfunction getCurveValue(points: CurvePoint[] | undefined, x: number): number {\n if (!points || points.length === 0) return x;\n const sorted = [...points].sort((a, b) => a.x - b.x);\n if (x <= sorted[0].x) return sorted[0].y;\n if (x >= sorted[sorted.length - 1].x) return sorted[sorted.length - 1].y;\n\n for (let i = 0; i < sorted.length - 1; i++) {\n const p1 = sorted[i];\n const p2 = sorted[i + 1];\n if (x >= p1.x && x <= p2.x) {\n const t = (x - p1.x) / Math.max(p2.x - p1.x, 1e-6);\n return p1.y + (p2.y - p1.y) * t;\n }\n }\n return x;\n}\n\nexport function hasColorAdjustment(adjustment?: ColorAdjustment): boolean {\n if (!adjustment || adjustment.enabled === false) return false;\n return Boolean(adjustment.basic || adjustment.hsl || adjustment.curves);\n}\n\nexport function getActiveSelectiveHsl(\n adjustment?: ColorAdjustment,\n): ActiveSelectiveHslAdjustment | null {\n const all = getAllSelectiveHsl(adjustment);\n return all.length > 0 ? all[0] : null;\n}\n\nexport function getAllSelectiveHsl(adjustment?: ColorAdjustment): ActiveSelectiveHslAdjustment[] {\n if (!adjustment || adjustment.enabled === false) return [];\n const hsl = adjustment.hsl;\n if (!hsl) return [];\n\n const byColor = hsl.byColor ?? {};\n const entries = Object.entries(byColor)\n .map(([targetColor, value]) => ({\n targetColor,\n hue: value?.hue ?? 0,\n saturation: value?.saturation ?? 0,\n lightness: value?.lightness ?? 0,\n }))\n .filter((entry) => entry.hue !== 0 || entry.saturation !== 0 || entry.lightness !== 0);\n\n if (entries.length > 0) return entries;\n\n if (!hsl.selectedColor) return [];\n\n const hue = hsl.hue ?? 0;\n const saturation = hsl.saturation ?? 0;\n const lightness = hsl.lightness ?? 0;\n if (hue === 0 && saturation === 0 && lightness === 0) return [];\n\n return [\n {\n targetColor: hsl.selectedColor,\n hue,\n saturation,\n lightness,\n },\n ];\n}\n\nexport function applyColorAdjustmentToMatrix(\n matrix: ColorMatrixFilter,\n adjustment?: ColorAdjustment,\n animationBrightnessMultiplier = 1,\n): void {\n matrix.reset();\n\n const basic = adjustment?.basic ?? {};\n const hsl = adjustment?.hsl ?? {};\n const curves = adjustment?.curves;\n const selectiveHsl = getActiveSelectiveHsl(adjustment);\n\n const combinedSaturation = (basic.saturation ?? 0) + (selectiveHsl ? 0 : (hsl.saturation ?? 0));\n if (combinedSaturation !== 0) {\n matrix.saturate(clamp(combinedSaturation / 100, -1, 2), true);\n }\n\n const combinedHue = (basic.hue ?? 0) + (selectiveHsl ? 0 : (hsl.hue ?? 0));\n if (combinedHue !== 0) {\n matrix.hue(combinedHue, true);\n }\n\n const basicBrightness = basic.brightness ?? 0;\n const shine = basic.shine ?? 0;\n const highlight = basic.highlight ?? 0;\n const shadow = basic.shadow ?? 0;\n const hslLightness = selectiveHsl ? 0 : (hsl.lightness ?? 0);\n const lightnessScore =\n basicBrightness + hslLightness + shine * 0.25 + highlight * 0.25 - shadow * 0.25;\n const brightness = clamp(1 + lightnessScore / 100, 0, 5) * animationBrightnessMultiplier;\n if (brightness !== 1) {\n matrix.brightness(brightness, true);\n }\n\n const contrast = clamp(1 + (basic.contrast ?? 0) / 100, 0, 5);\n if (contrast !== 1) {\n matrix.contrast(contrast, true);\n }\n\n // Effects (basic approximation on top of the color matrix pipeline)\n // Sharpness is approximated as extra micro-contrast.\n const sharpness = basic.sharpness ?? 0;\n if (sharpness !== 0) {\n const sharpnessContrast = clamp(1 + sharpness / 300, 0, 5);\n matrix.contrast(sharpnessContrast, true);\n }\n\n // Fade reduces punch and color intensity.\n const fade = basic.fade ?? 0;\n if (fade !== 0) {\n const fadeFactor = clamp(fade / 100, 0, 1);\n const fadeContrast = clamp(1 - fadeFactor * 0.35, 0, 5);\n const fadeSaturation = clamp(-fadeFactor * 0.45, -1, 2);\n matrix.contrast(fadeContrast, true);\n matrix.saturate(fadeSaturation, true);\n }\n\n // Vignette is approximated as a global edge-darkening feel by reducing\n // overall brightness. A true radial vignette would require a fragment shader.\n const vignette = Math.abs(basic.vignette ?? 0);\n if (vignette !== 0) {\n const vignetteFactor = clamp(vignette / 100, 0, 1);\n const vignetteBrightness = clamp(1 - vignetteFactor * 0.2, 0, 5);\n matrix.brightness(vignetteBrightness, true);\n }\n\n // Grain is approximated with a subtle contrast + saturation perturbation.\n // Real per-pixel film grain requires a noise shader/filter.\n const grain = basic.grain ?? 0;\n if (grain !== 0) {\n const grainFactor = clamp(grain / 100, 0, 1);\n const grainContrast = clamp(1 + grainFactor * 0.08, 0, 5);\n const grainSaturation = clamp(-grainFactor * 0.05, -1, 2);\n matrix.contrast(grainContrast, true);\n matrix.saturate(grainSaturation, true);\n }\n\n const temperature = clamp((basic.temperature ?? 0) / 100, -1, 1);\n if (temperature !== 0) {\n // Warmth/coolness approximation via RGB channel balance.\n const m = matrix.matrix;\n const redScale = 1 + temperature * 0.2;\n const blueScale = 1 - temperature * 0.2;\n m[0] *= redScale;\n m[6] *= 1;\n m[12] *= blueScale;\n }\n\n if (curves) {\n // Curves approximation from midpoint response in each channel.\n const rgbMid = getCurveValue(curves.rgb, 0.5);\n const redMid = getCurveValue(curves.red, 0.5);\n const greenMid = getCurveValue(curves.green, 0.5);\n const blueMid = getCurveValue(curves.blue, 0.5);\n\n const rgbContrast = clamp((rgbMid - 0.5) * 1.8, -0.6, 0.6);\n if (rgbContrast !== 0) {\n matrix.contrast(1 + rgbContrast, true);\n }\n\n const m = matrix.matrix;\n m[0] *= clamp(1 + (redMid - 0.5) * 0.8, 0.6, 1.4);\n m[6] *= clamp(1 + (greenMid - 0.5) * 0.8, 0.6, 1.4);\n m[12] *= clamp(1 + (blueMid - 0.5) * 0.8, 0.6, 1.4);\n }\n}\n","import {\n Application,\n Sprite,\n Texture,\n Container,\n Graphics,\n BlurFilter,\n ColorMatrixFilter,\n Filter,\n GlProgram,\n UniformGroup,\n} from \"pixi.js\";\nimport { ZoomBlurFilter } from \"pixi-filters\";\n\nimport type { IClip } from \"../clips/iclip\";\nimport type { MaskTransform } from \"../animation/types\";\nimport { parseColor, hexToRgb } from \"../utils/color\";\nimport { CHROMA_KEY_FRAGMENT, SELECTIVE_HSL_FRAGMENT } from \"../effect/glsl/custom-glsl\";\nimport { vertex } from \"../effect/vertex\";\nimport {\n applyColorAdjustmentToMatrix,\n getAllSelectiveHsl,\n hasColorAdjustment,\n} from \"../utils/color-adjustment\";\n\n/**\n * Update sprite transform based on clip properties\n * Utility function for updating standalone sprites (e.g., video sprites from HTMLVideoElement)\n * For sprites managed by PixiSpriteRenderer, use renderer.updateTransforms() instead\n */\nexport function updateSpriteTransform(clip: IClip, sprite: Sprite): void {\n const { opacity, zIndex, flip, left, top, width, height, angle } = clip;\n\n // Position and size\n sprite.x = left;\n sprite.y = top;\n sprite.width = Math.abs(width);\n sprite.height = Math.abs(height);\n\n // Rotation (angle property)\n sprite.angle = angle;\n\n // Opacity\n sprite.alpha = opacity;\n\n // Z-index\n sprite.zIndex = zIndex;\n // Flip\n if (flip?.x) {\n sprite.scale.x = -Math.abs(sprite.scale.x);\n } else {\n sprite.scale.x = Math.abs(sprite.scale.x);\n }\n if (flip?.y) {\n sprite.scale.y = -Math.abs(sprite.scale.y);\n } else {\n sprite.scale.y = Math.abs(sprite.scale.y);\n }\n}\n\n/**\n * Renders video frames using Pixi.js\n * Creates textures directly from VideoFrame/ImageBitmap sources for zero-copy GPU upload\n */\nexport class PixiSpriteRenderer {\n private pixiSprite: Sprite | null = null;\n private mirrorSprites: Sprite[] = [];\n private mirrorContainer: Container | null = null;\n private isMirrorActive = false;\n private texture: Texture | null = null;\n private root: Container | null = null;\n private strokeGraphics: Graphics | null = null;\n private maskGraphics: Graphics | null = null;\n private shadowGraphics: Graphics | null = null;\n private shadowContainer: Container | null = null;\n private animationContainer: Container | null = null;\n private resolution = 1;\n private destroyed = false;\n private lastFrame: any = null;\n\n constructor(\n _pixiApp: Application | null,\n private sprite: IClip,\n private targetContainer: Container | null = null,\n ) {\n // If targetContainer is not provided, try to use pixiApp.stage (fallback/legacy)\n if (!targetContainer && _pixiApp) {\n this.targetContainer = _pixiApp.stage;\n }\n\n // Capture resolution from renderer to normalize filters\n this.resolution = _pixiApp?.renderer?.resolution ?? 1;\n\n // Initialize Root Container immediately\n this.root = new Container();\n this.root.label = \"RootContainer\";\n this.root.visible = false; // Hidden until first frame\n\n // Initialize Animation Container (isolation layer for animations)\n this.animationContainer = new Container();\n this.animationContainer.label = \"AnimationContainer\";\n this.root.addChild(this.animationContainer);\n\n // If we have a target container, add root to it\n if (this.targetContainer) {\n this.targetContainer.addChild(this.root);\n }\n }\n\n /**\n * Update the sprite with a new video frame or Texture\n * @param frame VideoFrame, ImageBitmap, Texture, or null to render\n * VideoFrames are consumed (closed) after texture upload.\n */\n async updateFrame(frame: VideoFrame | ImageBitmap | Texture | null): Promise<void> {\n if (this.destroyed) return;\n\n if (frame === this.lastFrame) {\n if (this.root != null) {\n this.root.visible = frame != null;\n this.applySpriteTransforms();\n }\n return;\n }\n this.lastFrame = frame;\n\n if (frame == null) {\n // Hide sprite if no frame, but still apply transforms in case animation is running\n if (this.root != null) {\n this.root.visible = false;\n this.applySpriteTransforms();\n }\n return;\n }\n\n // Optimized path: If frame is already a Texture, use it directly\n // Duck typing: Check for Texture-like object (has source property) to avoid instanceof issues\n // This is critical because sometimes RenderTexture instance checks fail across module boundaries\n const isTexture =\n frame instanceof Texture ||\n (frame && typeof (frame as any).source !== \"undefined\" && !(frame instanceof VideoFrame));\n\n if (isTexture) {\n // Validate texture dimensions\n if (frame.width === 0 || frame.height === 0) {\n console.warn(\"PixiSpriteRenderer: Texture has zero dimensions\", frame.width, frame.height);\n return;\n }\n\n if (this.pixiSprite == null) {\n this.pixiSprite = new Sprite(frame as Texture);\n this.pixiSprite.label = \"MainSprite\";\n // Add to animationContainer instead of root directly\n this.animationContainer!.addChild(this.pixiSprite);\n this.applySpriteTransforms();\n } else {\n this.pixiSprite.texture = frame as Texture;\n }\n\n if (this.root != null) {\n this.root.visible = true;\n this.applySpriteTransforms();\n }\n return;\n }\n\n // Fast path: VideoFrame or ImageBitmap → Texture.from() directly\n // Avoids the old Canvas 2D drawImage intermediate copy\n const width = (frame as any).width;\n const height = (frame as any).height;\n\n if (typeof width !== \"number\" || typeof height !== \"number\" || width <= 0 || height <= 0) {\n console.warn(\"PixiSpriteRenderer: Invalid frame dimensions\", width, height);\n if (frame instanceof VideoFrame) frame.close();\n return;\n }\n\n // Destroy previous texture to avoid GPU memory leak\n if (this.texture != null) {\n this.texture.destroy(true);\n this.texture = null;\n }\n\n // Create texture directly from the frame source (VideoFrame or ImageBitmap)\n // This uploads to GPU in a single copy instead of frame→canvas→GPU\n this.texture = Texture.from(frame as any);\n\n if (!this.texture || !this.texture.source) {\n console.error(\"PixiSpriteRenderer: Failed to create valid texture\");\n if (frame instanceof VideoFrame) frame.close();\n return;\n }\n\n if (this.pixiSprite == null) {\n this.pixiSprite = new Sprite(this.texture);\n this.pixiSprite.label = \"MainSprite\";\n this.animationContainer!.addChild(this.pixiSprite);\n this.applySpriteTransforms();\n } else {\n this.pixiSprite.texture = this.texture;\n }\n\n // Close VideoFrame after GPU upload — it is single-use\n if (frame instanceof VideoFrame) {\n frame.close();\n }\n\n if (this.root != null) {\n this.root.visible = true;\n this.applySpriteTransforms();\n }\n }\n\n /**\n * Apply sprite transformations to the Pixi Sprite\n */\n private applySpriteTransforms(): void {\n if (this.pixiSprite == null || this.root == null || this.destroyed) return;\n\n const { flip, center, width, height, angle, opacity, zIndex, renderTransform } = this.sprite;\n\n const xOffset = renderTransform?.x ?? 0;\n const yOffset = renderTransform?.y ?? 0;\n const angleOffset = renderTransform?.angle ?? 0;\n const scaleMultiplier = renderTransform?.scale ?? 1;\n const scaleXMultiplier = renderTransform?.scaleX ?? 1;\n const scaleYMultiplier = renderTransform?.scaleY ?? 1;\n const opacityMultiplier = renderTransform?.opacity ?? 1;\n const blurOffset = renderTransform?.blur ?? 0;\n const motionBlurOffset = renderTransform?.motionBlur ?? 0;\n const brightnessMultiplier = renderTransform?.brightness ?? 1;\n const isMirrored = (renderTransform?.mirror ?? 0) > 0.5;\n\n // 1. Root container stays at the stable \"Anchor\" position\n // This ensures the wireframe/transformer remains stationary during animation\n // Mirror renderTexturePadding onto the root so Transformer can read it per-container.\n (this.root as any).renderTexturePadding = this.sprite.renderTexturePadding ?? 0;\n this.root.x = center.x;\n this.root.y = center.y;\n this.root.angle = (flip?.x || flip?.y ? -1 : 1) * angle;\n this.root.alpha = opacity;\n this.root.zIndex = zIndex;\n this.root.scale.set(1, 1);\n\n // 2. Apply animation transforms to the internal animationContainer\n if (this.animationContainer) {\n this.animationContainer.x = xOffset;\n this.animationContainer.y = yOffset;\n this.animationContainer.angle = (flip?.x || flip?.y ? -1 : 1) * angleOffset;\n this.animationContainer.alpha = opacityMultiplier;\n this.animationContainer.scale.set(\n scaleMultiplier * scaleXMultiplier,\n scaleMultiplier * scaleYMultiplier,\n );\n this.applyBlur(blurOffset);\n this.applyMotionBlur(motionBlurOffset);\n this.applyBrightness(brightnessMultiplier);\n this.applySelectiveHsl();\n this.applyChromaKey();\n }\n\n // 3. Handle true reflection mirroring\n this.pixiSprite.anchor.set(0.5, 0.5);\n this.pixiSprite.position.set(0, 0);\n\n const textureWidth = this.pixiSprite.texture?.width ?? 1;\n const textureHeight = this.pixiSprite.texture?.height ?? 1;\n\n const isCaption = (this.sprite as any).type === \"Caption\";\n const isText = (this.sprite as any).type === \"Text\";\n\n // When the clip has animation padding (oversized texture for slide/zoom room),\n // the texture is rendered at scale=1. The content is centred inside the padded texture,\n // so at rest it aligns exactly with the clip bounding box. When an animation offsets\n // animationContainer, the transparent padding comes into view (no hard clip).\n // Caption clips always use scale=1 (positioned by absolute coords).\n const animPad: number = this.sprite.renderTexturePadding ?? 0;\n\n // Base scale to fit texture into clip dimensions\n // Text/Caption clips with padding use scale=1; other clips scale to fit their bounds.\n const baseScaleX =\n isCaption || isText || animPad > 0\n ? 1\n : width && width !== 0\n ? Math.abs(width) / textureWidth\n : 1;\n const baseScaleY =\n isCaption || isText || animPad > 0\n ? 1\n : height && height !== 0\n ? Math.abs(height) / textureHeight\n : 1;\n\n if (isMirrored) {\n // Create mirror container if it doesn't exist\n if (!this.isMirrorActive) {\n this.isMirrorActive = true;\n\n // Create a container to hold the original and all mirrored sprites\n this.mirrorContainer = new Container();\n this.mirrorContainer.label = \"MirrorContainer\";\n\n // Move the main sprite into the mirror container\n if (this.animationContainer) {\n const idx = this.animationContainer.getChildIndex(this.pixiSprite);\n this.animationContainer.removeChild(this.pixiSprite);\n this.mirrorContainer.addChild(this.pixiSprite);\n this.animationContainer.addChildAt(this.mirrorContainer, idx);\n }\n\n // Create 8 mirror sprites for all directions:\n // right, left, bottom, top, bottom-right, bottom-left, top-right, top-left\n this.mirrorSprites = [];\n for (let i = 0; i < 8; i++) {\n const ms = new Sprite(this.pixiSprite.texture);\n ms.label = `MirrorSprite_${i}`;\n ms.anchor.set(0.5, 0.5);\n this.mirrorContainer.addChild(ms);\n this.mirrorSprites.push(ms);\n }\n }\n\n // Update mirror sprite textures to match main sprite\n for (const ms of this.mirrorSprites) {\n ms.texture = this.pixiSprite.texture;\n }\n\n const scaledW = textureWidth * baseScaleX;\n const scaledH = textureHeight * baseScaleY;\n\n // Original sprite stays at its normal position (0,0)\n this.pixiSprite.position.set(0, 0);\n this.pixiSprite.scale.set(baseScaleX, baseScaleY);\n\n // Mirror layout: [dx, dy, scaleX, scaleY]\n // We flip horizontally for sides, vertically for top/bottom, and both for corners\n const mirrors: [number, number, number, number][] = [\n [scaledW, 0, -baseScaleX, baseScaleY], // right\n [-scaledW, 0, -baseScaleX, baseScaleY], // left\n [0, scaledH, baseScaleX, -baseScaleY], // bottom\n [0, -scaledH, baseScaleX, -baseScaleY], // top\n [scaledW, scaledH, -baseScaleX, -baseScaleY], // bottom-right\n [-scaledW, scaledH, -baseScaleX, -baseScaleY], // bottom-left\n [scaledW, -scaledH, -baseScaleX, -baseScaleY], // top-right\n [-scaledW, -scaledH, -baseScaleX, -baseScaleY], // top-left\n ];\n\n for (let i = 0; i < 8; i++) {\n const [dx, dy, sx, sy] = mirrors[i];\n this.mirrorSprites[i].position.set(dx, dy);\n this.mirrorSprites[i].scale.set(sx, sy);\n }\n\n // Apply flip to the whole grid if needed\n if (flip?.x) {\n this.pixiSprite.scale.x = -baseScaleX;\n for (let i = 0; i < 8; i++) {\n // Flip the flips\n this.mirrorSprites[i].scale.x = -mirrors[i][2];\n }\n }\n if (flip?.y) {\n this.pixiSprite.scale.y = -baseScaleY;\n for (let i = 0; i < 8; i++) {\n this.mirrorSprites[i].scale.y = -mirrors[i][3];\n }\n }\n } else {\n // Remove mirror container if it exists\n if (this.isMirrorActive) {\n this.isMirrorActive = false;\n\n if (this.mirrorContainer && this.animationContainer) {\n const idx = this.animationContainer.getChildIndex(this.mirrorContainer);\n // Move main sprite back to animationContainer\n this.mirrorContainer.removeChild(this.pixiSprite);\n this.animationContainer.addChildAt(this.pixiSprite, idx);\n\n // Destroy mirror sprites and container\n for (const ms of this.mirrorSprites) {\n ms.destroy();\n }\n this.mirrorSprites = [];\n this.animationContainer.removeChild(this.mirrorContainer);\n this.mirrorContainer.destroy();\n this.mirrorContainer = null;\n }\n }\n\n // Standard Sprite behavior\n this.pixiSprite.scale.x = flip?.x ? -baseScaleX : baseScaleX;\n this.pixiSprite.scale.y = flip?.y ? -baseScaleY : baseScaleY;\n }\n\n this.applyStyle();\n this.applyContainerAnimations();\n }\n\n /**\n * Unified mask compositor.\n * Reads renderTransform.mask (set by WipeAnimation, CircleRevealAnimation, etc.)\n * and draws the correct shape into a single reusable Graphics mask.\n * Supports: rect wipe (4 directions + angle), circle expand, ellipse expand.\n * Feather (soft edge) is approximated via alpha gradient on the mask shape.\n */\n private applyContainerAnimations(): void {\n if (!this.animationContainer || this.destroyed) return;\n const clip = this.sprite as any;\n const renderTransform = clip.renderTransform ?? {};\n const maskDef: MaskTransform | undefined = renderTransform.mask;\n\n // No mask animation active — clear any existing mask\n if (!maskDef) {\n if (this.animationContainer.mask) {\n this.animationContainer.mask = null;\n const g = (this.animationContainer as any).__maskGraphics as Graphics | undefined;\n if (g) g.visible = false;\n }\n return;\n }\n\n const { progress, shape, direction, angle, origin, feather } = maskDef;\n\n // Fully visible — no mask needed\n if (progress >= 1) {\n this.animationContainer.mask = null;\n const g = (this.animationContainer as any).__maskGraphics as Graphics | undefined;\n if (g) g.visible = false;\n return;\n }\n\n const dims = this._getMaskDimensions();\n if (dims.width <= 0 || dims.height <= 0) return;\n const { width, height } = dims;\n\n // Create or reuse a single Graphics object for the mask\n let g = (this.animationContainer as any).__maskGraphics as Graphics | undefined;\n if (!g) {\n g = new Graphics();\n g.label = \"MaskGraphics\";\n this.animationContainer.addChild(g);\n (this.animationContainer as any).__maskGraphics = g;\n }\n g.visible = true;\n g.clear();\n g.scale.set(1, 1);\n\n const featherPx = feather ?? 0;\n\n // Remap progress: initialProgress defines the starting size (default 0).\n // All painters/shapes receive a remapped value in [0, 1] so they don't\n // need to handle this individually.\n const ip = maskDef.initialProgress ?? 0;\n const remapped = ip + (1 - ip) * progress;\n\n // edgeCrop still shows the uncropped centre at progress 0\n if (remapped <= 0 && shape !== \"edgeCrop\") {\n // Fully hidden — empty mask, set and return\n this.animationContainer.mask = g;\n return;\n }\n\n if (shape === \"custom\" && maskDef.painter) {\n // Delegate drawing entirely to the animation's painter — no switch needed\n maskDef.painter(g, width, height, remapped);\n } else if (shape === \"edgeCrop\") {\n // Counter the animated scale so the crop distances stay in canvas pixels\n const sx = Math.max(1e-3, (renderTransform.scale ?? 1) * (renderTransform.scaleX ?? 1));\n const sy = Math.max(1e-3, (renderTransform.scale ?? 1) * (renderTransform.scaleY ?? 1));\n g.scale.set(1 / sx, 1 / sy);\n this._drawEdgeCropMask(\n g,\n width,\n height,\n remapped,\n origin ?? \"center\",\n maskDef.xDistance ?? 100,\n maskDef.yDistance ?? 100,\n maskDef.maskBorderRadius ?? 0,\n );\n } else if (shape === \"circle\" || shape === \"ellipse\") {\n this._drawExpandMask(g, width, height, remapped, origin ?? \"center\", shape, featherPx);\n } else {\n // Rect wipe — supports direction + angle\n const deg = angle ?? 0;\n if (deg !== 0) {\n this._drawAngleWipeMask(g, width, height, remapped, deg, featherPx);\n } else {\n this._drawRectWipeMask(g, width, height, remapped, direction ?? \"left\", featherPx);\n }\n }\n\n this.animationContainer.mask = g;\n }\n\n private _drawEdgeCropMask(\n g: Graphics,\n width: number,\n height: number,\n progress: number,\n origin: string,\n xDistance: number,\n yDistance: number,\n radius: number,\n ): void {\n const cx = xDistance * (1 - progress);\n const cy = yDistance * (1 - progress);\n let x = -width / 2;\n let y = -height / 2;\n let w = width;\n let h = height;\n switch (origin) {\n case \"topLeft\":\n w = width - cx;\n h = height - cy;\n break;\n case \"topRight\":\n x += cx;\n w = width - cx;\n h = height - cy;\n break;\n case \"bottomLeft\":\n y += cy;\n w = width - cx;\n h = height - cy;\n break;\n case \"bottomRight\":\n x += cx;\n y += cy;\n w = width - cx;\n h = height - cy;\n break;\n default:\n x += cx;\n y += cy;\n w = width - 2 * cx;\n h = height - 2 * cy;\n }\n if (w <= 0 || h <= 0) return;\n if (radius > 0) g.roundRect(x, y, w, h, radius).fill({ color: 0xffffff });\n else g.rect(x, y, w, h).fill({ color: 0xffffff });\n }\n\n private _getMaskDimensions(): { width: number; height: number } {\n const container = this.animationContainer!;\n const parent = container.parent as any;\n const pad: number = parent?.renderTexturePadding ?? 0;\n\n if (container.children) {\n for (const child of container.children as any[]) {\n if (!child || child.label === \"MaskGraphics\" || child.label === \"WipeMask\") continue;\n if (child.label === \"MainSprite\") {\n const tw = Math.abs(child.width ?? 0) - pad * 2;\n const th = Math.abs(child.height ?? 0) - pad * 2;\n if (tw > 0 && th > 0) return { width: tw, height: th };\n }\n if (child.children) {\n for (const gc of child.children as any[]) {\n if (gc?.label === \"MainSprite\") {\n const tw = Math.abs(gc.width ?? 0) - pad * 2;\n const th = Math.abs(gc.height ?? 0) - pad * 2;\n if (tw > 0 && th > 0) return { width: tw, height: th };\n }\n }\n }\n }\n }\n try {\n const lb = container.getLocalBounds();\n if (lb.width > 0 && lb.height > 0)\n return { width: lb.width - pad * 2, height: lb.height - pad * 2 };\n } catch {\n /* before first render */\n }\n return { width: 0, height: 0 };\n }\n\n private _drawRectWipeMask(\n g: Graphics,\n width: number,\n height: number,\n progress: number,\n direction: string,\n feather: number,\n ): void {\n let rx = -width / 2;\n let ry = -height / 2;\n let rw = width;\n let rh = height;\n\n switch (direction) {\n case \"left\":\n rw = width * progress;\n rx = -width / 2;\n break;\n case \"right\":\n rw = width * progress;\n rx = width / 2 - rw;\n break;\n case \"top\":\n rh = height * progress;\n ry = -height / 2;\n break;\n case \"bottom\":\n rh = height * progress;\n ry = height / 2 - rh;\n break;\n }\n\n if (rw <= 0 || rh <= 0) return;\n\n if (feather > 0) {\n // Draw the solid core\n g.rect(rx, ry, rw, rh).fill({ color: 0xffffff, alpha: 1 });\n } else {\n g.rect(rx, ry, rw, rh).fill({ color: 0xffffff });\n }\n }\n\n private _drawAngleWipeMask(\n g: Graphics,\n width: number,\n height: number,\n progress: number,\n angleDeg: number,\n _feather: number,\n ): void {\n // Rotate the wipe axis by angleDeg.\n // We draw an oversized rect covering the revealed portion, then rotate the Graphics.\n const diagonal = Math.sqrt(width * width + height * height);\n const revealedW = diagonal * progress;\n\n // Save and apply rotation\n g.rotation = (angleDeg * Math.PI) / 180;\n g.rect(-diagonal / 2, -diagonal / 2, revealedW, diagonal).fill({ color: 0xffffff });\n // Reset rotation so subsequent reuse doesn't accumulate\n g.rotation = 0;\n }\n\n private _drawExpandMask(\n g: Graphics,\n width: number,\n height: number,\n progress: number,\n origin: string,\n shape: \"circle\" | \"ellipse\",\n _feather: number,\n ): void {\n // Determine origin point in local space\n let ox = 0;\n let oy = 0;\n switch (origin) {\n case \"topLeft\":\n ox = -width / 2;\n oy = -height / 2;\n break;\n case \"topRight\":\n ox = width / 2;\n oy = -height / 2;\n break;\n case \"bottomLeft\":\n ox = -width / 2;\n oy = height / 2;\n break;\n case \"bottomRight\":\n ox = width / 2;\n oy = height / 2;\n break;\n default:\n ox = 0;\n oy = 0; // center\n }\n\n // Max radius needed to cover the entire clip from this origin\n const corners = [\n { x: -width / 2, y: -height / 2 },\n { x: width / 2, y: -height / 2 },\n { x: -width / 2, y: height / 2 },\n { x: width / 2, y: height / 2 },\n ];\n const maxR = Math.max(...corners.map((c) => Math.hypot(c.x - ox, c.y - oy)));\n const r = maxR * progress;\n\n if (shape === \"circle\") {\n g.circle(ox, oy, r).fill({ color: 0xffffff });\n } else {\n // Ellipse scales independently on each axis\n const rx = (width / 2) * progress;\n const ry = (height / 2) * progress;\n g.ellipse(ox, oy, rx, ry).fill({ color: 0xffffff });\n }\n }\n\n /**\n * Apply all styles (stroke, borderRadius, dropShadow) to the sprite\n */\n private applyStyle(): void {\n if (this.pixiSprite == null || this.destroyed) return;\n\n const style = (this.sprite as any).style || {};\n const textureWidth = this.pixiSprite.texture?.width ?? 0;\n const textureHeight = this.pixiSprite.texture?.height ?? 0;\n\n if (textureWidth === 0 || textureHeight === 0) return;\n\n const width = Math.abs(this.sprite.width ?? 0);\n const height = Math.abs(this.sprite.height ?? 0);\n\n // 1. Apply BorderRadius (Masking)\n const borderRadius = style.borderRadius || 0;\n if (borderRadius > 0) {\n if (this.maskGraphics == null) {\n this.maskGraphics = new Graphics();\n this.maskGraphics.label = \"MaskGraphics\";\n (this.maskGraphics as any)._calculateBounds = () => {}; // Do not affect bounding box\n this.animationContainer!.addChild(this.maskGraphics);\n }\n this.maskGraphics.clear();\n this.maskGraphics.roundRect(\n -width / 2,\n -height / 2,\n width,\n height,\n Math.min(borderRadius, width / 2, height / 2),\n );\n this.maskGraphics.fill({ color: 0xffffff, alpha: 1 });\n this.maskGraphics.visible = true;\n\n // Force mask update by resetting the mask property\n this.pixiSprite.mask = null;\n this.pixiSprite.mask = this.maskGraphics;\n } else {\n if (this.maskGraphics) {\n this.maskGraphics.visible = false;\n this.pixiSprite.mask = null;\n }\n }\n\n // Skip stroke for clips that handle their own rendering (Text, Caption, Shape)\n if (\n this.sprite.type !== \"Text\" &&\n this.sprite.type !== \"Caption\" &&\n this.sprite.type !== \"Shape\"\n ) {\n this.applyStroke(style);\n } else if (this.strokeGraphics) {\n this.strokeGraphics.visible = false;\n }\n\n // 3. Apply Drop Shadow (Media only)\n if (\n this.sprite.type !== \"Text\" &&\n this.sprite.type !== \"Caption\" &&\n this.sprite.type !== \"Shape\"\n ) {\n this.applyShadow(style);\n } else if (this.shadowContainer) {\n this.shadowContainer.visible = false;\n this.shadowContainer.filters = [];\n }\n }\n\n private applyStroke(style: any): void {\n const stroke = style.stroke;\n if (stroke && stroke.width > 0) {\n if (this.strokeGraphics == null) {\n this.strokeGraphics = new Graphics();\n this.strokeGraphics.label = \"StrokeGraphics\";\n (this.strokeGraphics as any)._calculateBounds = () => {}; // Do not affect bounding box\n this.animationContainer!.addChild(this.strokeGraphics);\n }\n\n this.strokeGraphics.clear();\n const color = parseColor(stroke.color) ?? 0xffffff;\n const strokeWidth = stroke.width;\n const borderRadius = style.borderRadius || 0;\n const width = Math.abs(this.sprite.width ?? 0);\n const height = Math.abs(this.sprite.height ?? 0);\n\n let alignment = 1; // Default outside (1)\n if (stroke.alignment !== undefined) {\n if (typeof stroke.alignment === \"number\") {\n alignment = stroke.alignment;\n } else if (stroke.alignment === \"center\" || stroke.alignment === \"middle\") {\n alignment = 0.5;\n } else if (stroke.alignment === \"inside\") {\n alignment = 0;\n } else if (stroke.alignment === \"outside\") {\n alignment = 1;\n }\n }\n\n this.strokeGraphics.setStrokeStyle({\n width: strokeWidth,\n color: color,\n alignment: alignment,\n });\n\n if (borderRadius > 0) {\n const r = Math.min(borderRadius, width / 2, height / 2);\n this.strokeGraphics.roundRect(-width / 2, -height / 2, width, height, r);\n } else {\n this.strokeGraphics.rect(-width / 2, -height / 2, width, height);\n }\n\n this.strokeGraphics.stroke();\n this.strokeGraphics.visible = true;\n } else if (this.strokeGraphics != null) {\n this.strokeGraphics.visible = false;\n }\n }\n\n private applyShadow(style: any): void {\n const shadow = style.shadow;\n const width = Math.abs(this.sprite.width ?? 0);\n const height = Math.abs(this.sprite.height ?? 0);\n\n if (\n shadow &&\n width > 0 &&\n height > 0 &&\n (shadow.blur > 0 || (shadow.offsetX ?? 0) !== 0 || (shadow.offsetY ?? 0) !== 0)\n ) {\n if (this.shadowContainer == null) {\n this.shadowContainer = new Container();\n this.shadowContainer.label = \"ShadowContainer\";\n (this.shadowContainer as any)._calculateBounds = () => {}; // Do not affect bounding box\n this.shadowGraphics = new Graphics();\n this.shadowGraphics.label = \"ShadowGraphics\";\n (this.shadowGraphics as any)._calculateBounds = () => {}; // Do not affect bounding box\n this.shadowContainer.addChild(this.shadowGraphics);\n // Add shadow container to animationContainer at index 0\n this.animationContainer!.addChildAt(this.shadowContainer, 0);\n }\n\n const color = parseColor(shadow.color) ?? 0x000000;\n const alpha = shadow.alpha ?? 0.5;\n const blur = shadow.blur ?? 0;\n const dx = shadow.offsetX ?? 0;\n const dy = shadow.offsetY ?? 0;\n\n // Position the container\n this.shadowContainer.position.set(dx, dy);\n\n this.shadowGraphics!.clear();\n const borderRadius = style.borderRadius || 0;\n\n if (borderRadius > 0) {\n const r = Math.min(borderRadius, width / 2, height / 2);\n this.shadowGraphics!.roundRect(-width / 2, -height / 2, width, height, r);\n } else {\n this.shadowGraphics!.rect(-width / 2, -height / 2, width, height);\n }\n\n this.shadowGraphics!.fill({ color, alpha });\n\n // In v8, we use BlurFilter for blurring - apply to container for better bounds handling\n if (blur > 0) {\n if (!this.shadowContainer.filters || this.shadowContainer.filters.length === 0) {\n this.shadowContainer.filters = [new BlurFilter()];\n }\n const blurFilter = this.shadowContainer.filters[0] as BlurFilter;\n\n // Calculate global scale to ensure blur looks consistent regardless of zoom\n // Use worldTransform to get the effective scale on screen\n const worldScale = this.root\n ? Math.sqrt(this.root.worldTransform.a ** 2 + this.root.worldTransform.b ** 2)\n : 1;\n\n // Normalize strength by world scale\n // We set blurFilter.resolution below, which handles the renderer resolution scaling\n blurFilter.strength = blur * worldScale;\n\n // Explicitly set filter resolution to match renderer for consistency\n blurFilter.resolution = this.resolution;\n\n // Padding is important to prevent clipping, also needs to scale\n blurFilter.padding = Math.max(blur * 2 * worldScale, 20);\n } else {\n this.shadowContainer.filters = [];\n }\n\n this.shadowContainer.visible = true;\n } else if (this.shadowContainer != null) {\n this.shadowContainer.visible = false;\n this.shadowContainer.filters = [];\n }\n }\n\n private applyBlur(blur: number): void {\n if (!this.animationContainer || this.destroyed) return;\n\n // Safety check for valid number\n if (typeof blur !== \"number\" || !isFinite(blur) || blur <= 0) {\n if (this.animationContainer.filters && this.animationContainer.filters.length > 0) {\n this.animationContainer.filters = [];\n }\n return;\n }\n\n let blurFilter = this.animationContainer.filters?.find(\n (f) => f instanceof BlurFilter,\n ) as BlurFilter;\n if (!blurFilter) {\n blurFilter = new BlurFilter();\n const currentFilters = this.animationContainer.filters || [];\n this.animationContainer.filters = [...currentFilters, blurFilter];\n }\n\n // Calculate global scale\n const worldScale = this.root\n ? Math.sqrt(this.root.worldTransform.a ** 2 + this.root.worldTransform.b ** 2)\n : 1;\n\n // Normalize strength by world scale (clamped to sensible minimum if worldScale is essentially 0)\n const effectiveScale = Math.max(worldScale, 0.001);\n blurFilter.strength = blur * effectiveScale;\n blurFilter.resolution = this.resolution;\n blurFilter.padding = Math.max(blur * 2 * effectiveScale, 20);\n blurFilter.quality = 4;\n (blurFilter as any).repeatEdgePixels = true;\n }\n\n private applyMotionBlur(motionBlur: number): void {\n if (!this.animationContainer || this.destroyed) return;\n\n // Safety check for valid number\n if (typeof motionBlur !== \"number\" || !isFinite(motionBlur) || motionBlur <= 0) {\n if (this.animationContainer.filters) {\n this.animationContainer.filters = this.animationContainer.filters.filter(\n (f) => !(f instanceof ZoomBlurFilter),\n );\n }\n return;\n }\n\n let zoomBlurFilter = this.animationContainer.filters?.find(\n (f) => f instanceof ZoomBlurFilter,\n ) as ZoomBlurFilter;\n\n if (!zoomBlurFilter) {\n zoomBlurFilter = new ZoomBlurFilter();\n const currentFilters = this.animationContainer.filters || [];\n this.animationContainer.filters = [...currentFilters, zoomBlurFilter];\n }\n\n zoomBlurFilter.strength = motionBlur / 200;\n\n if (this.pixiSprite) {\n const bounds = this.pixiSprite.getBounds();\n zoomBlurFilter.center = {\n x: bounds.width / 2,\n y: bounds.height / 2,\n };\n }\n\n zoomBlurFilter.innerRadius = 0;\n zoomBlurFilter.radius = -1; // Infinite\n }\n\n private applyBrightness(brightness: number): void {\n if (!this.animationContainer || this.destroyed) return;\n const hasClipColorAdjustment = hasColorAdjustment(this.sprite.colorAdjustment);\n if (brightness === 1 && !hasClipColorAdjustment) {\n // Remove brightness filter if it exists\n if (this.animationContainer.filters) {\n this.animationContainer.filters = this.animationContainer.filters.filter(\n (f) => (f as any).label !== \"ColorAdjustmentFilter\",\n );\n }\n return;\n }\n\n let brightnessFilter = this.animationContainer.filters?.find(\n (f) => (f as any).label === \"ColorAdjustmentFilter\",\n ) as ColorMatrixFilter;\n\n if (!brightnessFilter) {\n brightnessFilter = new ColorMatrixFilter();\n (brightnessFilter as any).label = \"ColorAdjustmentFilter\";\n const currentFilters = this.animationContainer.filters || [];\n this.animationContainer.filters = [...currentFilters, brightnessFilter];\n }\n\n applyColorAdjustmentToMatrix(brightnessFilter, this.sprite.colorAdjustment, brightness);\n }\n\n private applySelectiveHsl(): void {\n if (!this.animationContainer || this.destroyed) return;\n\n const activeHslList = getAllSelectiveHsl(this.sprite.colorAdjustment);\n const baseFilters = (this.animationContainer.filters || []).filter(\n (f) => !(f as any).label?.startsWith(\"SelectiveHslFilter\"),\n );\n\n if (activeHslList.length === 0) {\n this.animationContainer.filters = baseFilters;\n return;\n }\n\n const selectiveHslFilters: Filter[] = [];\n for (let i = 0; i < activeHslList.length; i++) {\n const activeHsl = activeHslList[i];\n const hslUniforms = new UniformGroup({\n uTargetColor: { value: [1, 1, 0], type: \"vec3<f32>\" },\n uHueShift: { value: activeHsl.hue, type: \"f32\" },\n uSatShift: { value: activeHsl.saturation / 100, type: \"f32\" },\n uLightShift: { value: activeHsl.lightness / 100, type: \"f32\" },\n uTolerance: { value: 0.22, type: \"f32\" },\n uSoftness: { value: 0.12, type: \"f32\" },\n });\n const rgb = hexToRgb(activeHsl.targetColor);\n if (rgb) {\n hslUniforms.uniforms.uTargetColor[0] = rgb.r / 255;\n hslUniforms.uniforms.uTargetColor[1] = rgb.g / 255;\n hslUniforms.uniforms.uTargetColor[2] = rgb.b / 255;\n }\n const selectiveHslFilter = new Filter({\n glProgram: new GlProgram({\n vertex,\n fragment: SELECTIVE_HSL_FRAGMENT,\n name: `SelectiveHslShader_${i}`,\n }),\n resources: { hslUniforms },\n });\n (selectiveHslFilter as any).label = `SelectiveHslFilter_${i}`;\n selectiveHslFilters.push(selectiveHslFilter);\n }\n\n this.animationContainer.filters = [...baseFilters, ...selectiveHslFilters];\n }\n\n private applyChromaKey(): void {\n if (!this.animationContainer || this.destroyed) return;\n\n const { chromaKey } = this.sprite;\n\n if (!chromaKey || !chromaKey.enabled) {\n if (this.animationContainer.filters) {\n this.animationContainer.filters = this.animationContainer.filters.filter(\n (f) => (f as any).label !== \"ChromaKeyFilter\",\n );\n }\n return;\n }\n\n let chromaFilter = this.animationContainer.filters?.find(\n (f) => (f as any).label === \"ChromaKeyFilter\",\n ) as Filter;\n\n if (!chromaFilter) {\n const program = new GlProgram({\n vertex,\n fragment: CHROMA_KEY_FRAGMENT,\n name: \"ChromaKeyShader\",\n });\n\n const chromaUniforms = new UniformGroup({\n uKeyColor: { value: [0, 1, 0], type: \"vec3<f32>\" },\n uSimilarity: { value: 0.1, type: \"f32\" },\n uSpill: { value: 0.0, type: \"f32\" },\n });\n\n chromaFilter = new Filter({\n glProgram: program,\n resources: {\n chromaUniforms,\n },\n });\n (chromaFilter as any).label = \"ChromaKeyFilter\";\n\n const currentFilters = this.animationContainer.filters || [];\n this.animationContainer.filters = [...currentFilters, chromaFilter];\n }\n\n // Update uniforms\n const uniforms = (chromaFilter.resources as any).chromaUniforms.uniforms;\n const rgb = hexToRgb(chromaKey.color);\n if (rgb) {\n uniforms.uKeyColor[0] = rgb.r / 255;\n uniforms.uKeyColor[1] = rgb.g / 255;\n uniforms.uKeyColor[2] = rgb.b / 255;\n }\n uniforms.uSimilarity = chromaKey.similarity;\n uniforms.uSpill = chromaKey.spill;\n }\n\n updateTransforms(): void {\n if (this.root != null && !this.destroyed) {\n this.applySpriteTransforms();\n }\n }\n\n getSprite(): Sprite | null {\n return this.pixiSprite;\n }\n\n getRoot(): Container | null {\n return this.root;\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n\n if (this.root != null) {\n if (this.root.parent) {\n this.root.parent.removeChild(this.root);\n }\n this.root.destroy({ children: true });\n this.root = null;\n this.pixiSprite = null; // pixiSprite is a child of root\n }\n\n if (this.strokeGraphics != null) {\n this.strokeGraphics.destroy();\n this.strokeGraphics = null;\n }\n\n if (this.maskGraphics != null) {\n this.maskGraphics.destroy();\n this.maskGraphics = null;\n }\n\n if (this.shadowGraphics != null) {\n this.shadowGraphics.destroy();\n this.shadowGraphics = null;\n }\n\n if (this.shadowContainer != null) {\n this.shadowContainer.destroy({ children: true });\n this.shadowContainer = null;\n }\n\n if (this.texture != null) {\n this.texture.destroy();\n this.texture = null;\n }\n }\n}\n","export const vertex = `\n\tin vec2 aPosition;\n\tout vec2 _uv; \n\tuniform mat3 projectionMatrix;\n\tuniform vec4 uInputSize;\n\tuniform vec4 uOutputFrame;\n\tout vec2 vTextureCoord;\n\tuniform vec4 uOutputTexture;\n\n\tvec4 filterVertexPosition( void )\n\t{\n\t\t\tvec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;\n\n\t\t\tposition.x = position.x * (2.0 / uOutputTexture.x) - 1.0;\n\t\t\tposition.y = position.y * (2.0*uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;\n\n\t\t\treturn vec4(position, 0.0, 1.0);\n\t}\n\n\tvec2 filterTextureCoord( void )\n\t{\n\treturn aPosition * (uOutputFrame.zw * uInputSize.zw);\n\t}\n\n\tvoid main(void)\n\t{\n\tgl_Position = filterVertexPosition();\n\tvTextureCoord = filterTextureCoord();\n\tvec2 absolute = aPosition * uOutputFrame.zw + uOutputFrame.xy;\n\t_uv = absolute / uOutputTexture.xy;\n\t}\n`;\n","import { GLTransition } from \"./types\";\n\nexport const uniforms = {\n custom: (transition: GLTransition) => {\n // Handle transitions without defaultParams (like local custom transitions)\n const defaultParams = transition.defaultParams || {};\n const paramsTypes = transition.paramsTypes || {};\n\n return Object.fromEntries(\n Object.entries(defaultParams).map(([name, value]) => [\n name,\n {\n value,\n type: getUniformType(paramsTypes[name]),\n },\n ]),\n );\n },\n basics: {\n _fromR: { value: 1, type: \"f32\" },\n _toR: { value: 1, type: \"f32\" },\n ratio: { value: 1, type: \"f32\" },\n progress: { value: 0, type: \"f32\" },\n customUniform: { value: 0, type: \"f32\" },\n center: { value: [0.5, 0.5], type: \"vec2<f32>\" }, // Center point of the canvas (not element centers)\n },\n};\n\nconst getUniformType = (type: string) => {\n if (type === \"f32\" || type === \"i32\") {\n return type;\n } else if (type === \"float\") {\n return \"f32\";\n } else return `${type}<f32>`;\n};\n","export const fragment = (glsl: string) => `\n\tprecision highp float;\n\tin vec2 vTextureCoord;\n\tin vec2 _uv; // Normalized [0,1] coordinates with center at (0.5, 0.5) for canvas-centered transitions\n\tuniform sampler2D from, to;\n\tuniform float progress, ratio, _fromR, _toR;\n\tuniform float customUniform;\n\tuniform vec2 center; // Center point of the canvas (0.5, 0.5) - NOT element centers\n\n\tvec4 getFromColor(vec2 uv){\n\t\treturn texture2D(from, .5+(uv-.5)*vec2(max(ratio/_fromR,1.), max(_fromR/ratio,1.)));\n\t}\n\tvec4 getToColor(vec2 uv){\n\t\treturn texture2D(to, .5+(uv-.5)*vec2(max(ratio/_toR,1.), max(_toR/ratio,1.)));\n\t}\n\n\t// Helper function to get distance from canvas center\n\tfloat distanceFromCenter(vec2 uv) {\n\t\treturn distance(uv, center);\n\t}\n\t\n\t// Helper function to get angle from canvas center\n\tfloat angleFromCenter(vec2 uv) {\n\t\tvec2 centered = uv - center;\n\t\treturn atan(centered.y, centered.x);\n\t}\n\t\n\t// Helper function to get centered coordinates relative to canvas center\n\tvec2 getCenteredCoord(vec2 uv) {\n\t\treturn uv - center; // Coordinates relative to canvas center\n\t}\n\n\t// gl-transition code here\n\t${glsl}\n\t// gl-transition code end\n\n\tvoid main(){\n\t\t// Use _uv which is properly normalized to [0,1] range with center at (0.5, 0.5)\n\t\t// This ensures transitions are centered on the canvas, not element centers\n\t\tvec2 uv = _uv;\n\t\tgl_FragColor = transition(uv);\n\t}\n`;\n","export const RADIAL_SWIPE_FRAGMENT = `\nconst float PI = 3.141592653589;\n\nvec4 transition(vec2 p) {\n vec2 rp = p * 2.0 - 1.0;\n float angle = atan(rp.y, rp.x);\n float threshold = (progress - 0.5) * PI * 2.5;\n float mix_factor = smoothstep(0.0, 0.1, angle - threshold);\n return mix(getToColor(p), getFromColor(p), mix_factor);\n}\n`;\n\n/**\n * GridFlip transition configuration\n * Custom fragment shader and uniforms for GridFlip transition\n */\n\nexport const GRIDFLIP_FRAGMENT = `\nuniform vec2 gridSize;\nuniform float pause;\nuniform float dividerWidth;\nuniform vec4 bgColor;\nuniform float randomness;\n\nfloat rand(vec2 co) { \n return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\nfloat getDelta(vec2 p) { \n vec2 rectanglePos = floor(gridSize * p); \n vec2 rectangleSize = vec2(1.0 / gridSize.x, 1.0 / gridSize.y); \n float top = rectangleSize.y * (rectanglePos.y + 1.0); \n float bottom = rectangleSize.y * rectanglePos.y; \n float left = rectangleSize.x * rectanglePos.x; \n float right = rectangleSize.x * (rectanglePos.x + 1.0); \n float minX = min(abs(p.x - left), abs(p.x - right)); \n float minY = min(abs(p.y - top), abs(p.y - bottom)); \n return min(minX, minY);\n}\n\nfloat getDividerSize() { \n vec2 rectangleSize = vec2(1.0 / gridSize.x, 1.0 / gridSize.y); \n return min(rectangleSize.x, rectangleSize.y) * dividerWidth;\n}\n\nvec4 transition(vec2 p) { \n if (progress < pause) { \n float currentProg = progress / pause; \n float a = 1.0; \n if (getDelta(p) < getDividerSize()) { \n a = 1.0 - currentProg; \n } \n return mix(bgColor, getFromColor(p), a); \n } \n\n if (progress < 1.0 - pause) { \n if (getDelta(p) < getDividerSize()) { \n return bgColor; \n } \n\n float currentProg = (progress - pause) / (1.0 - pause * 2.0); \n vec2 rectanglePos = floor(gridSize * p); \n float r = rand(rectanglePos) - randomness; \n float cp = smoothstep(0.0, 1.0 - r, currentProg); \n float rectangleSize = 1.0 / gridSize.x; \n float delta = rectanglePos.x * rectangleSize; \n float offset = rectangleSize * 0.5 + delta; \n\n vec2 warped = p; \n warped.x = (warped.x - offset) / max(abs(cp - 0.5), 0.001) * 0.5 + offset; \n\n float s = step(abs(gridSize.x * (p.x - delta) - 0.5), abs(cp - 0.5)); \n vec4 mixColor = mix(getToColor(warped), getFromColor(warped), step(cp, 0.5)); \n return mix(bgColor, mixColor, s); \n } \n\n float currentProg = (progress - 1.0 + pause) / pause; \n float a = 1.0; \n if (getDelta(p) < getDividerSize()) { \n a = currentProg; \n } \n return mix(bgColor, getToColor(p), a);\n}\n`;\n\nexport const GRIDFLIP_UNIFORMS: Record<string, { value: any; type: string }> = {\n gridSize: { value: [4, 4], type: \"vec2<f32>\" },\n pause: { value: 0.1, type: \"f32\" },\n dividerWidth: { value: 0.05, type: \"f32\" },\n bgColor: { value: [0, 0, 0, 1], type: \"vec4<f32>\" },\n randomness: { value: 0.1, type: \"f32\" },\n};\n\n/**\n * Circle transition configuration\n * Custom fragment shader and uniforms for Circle transition\n */\n\nexport const CIRCLE_FRAGMENT = `\nuniform vec3 backColor;\n\nvec4 transition(vec2 uv) { \n float distance = length(uv - center); \n float radius = sqrt(8.0) * abs(progress - 0.5); \n\n if (distance > radius) { \n return vec4(backColor, 1.0); \n } else { \n if (progress < 0.5) return getFromColor(uv); \n else return getToColor(uv); \n }\n}\n`;\n\n/**\n * Directional transition configuration\n * Custom fragment shader and uniforms for Directional transition\n */\n\nexport const DIRECTIONAL_FRAGMENT = `\nuniform vec2 direction;\n\nvec4 transition(vec2 uv) { \n vec2 p = uv + progress * sign(direction); \n vec2 f = fract(p); \n return mix( \n getToColor(f), \n getFromColor(f), \n step(0.0, p.y) * step(p.y, 1.0) * step(0.0, p.x) * step(p.x, 1.0) \n );\n}\n`;\n\nexport const DIRECTIONAL_UNIFORMS: Record<string, { value: any; type: string }> = {\n direction: { value: [0.0, 1.0], type: \"vec2<f32>\" },\n};\n\n/**\n * UndulatingBurnOut transition configuration\n * Custom fragment shader and uniforms for UndulatingBurnOut transition\n */\n\nexport const UNDULATING_BURN_OUT_FRAGMENT = `\nuniform float smoothness;\nuniform vec3 color;\n\nconst float M_PI = 3.14159265358979323846;\n\nfloat quadraticInOut(float t) { \n float p = 2.0 * t * t; \n return t < 0.5 ? p : -p + (4.0 * t) - 1.0;\n}\n\nfloat getGradient(float r, float dist) { \n float d = r - dist; \n return mix( \n smoothstep(-smoothness, 0.0, r - dist * (1.0 + smoothness)), \n -1.0 - step(0.005, d), \n step(-0.005, d) * step(d, 0.01) \n );\n}\n\nfloat getWave(vec2 p){ \n vec2 _p = p - center; // offset from center \n float rads = atan(_p.y, _p.x); \n float degs = degrees(rads) + 180.0; \n vec2 range = vec2(0.0, M_PI * 30.0); \n vec2 domain = vec2(0.0, 360.0); \n float ratio = (M_PI * 30.0) / 360.0; \n degs = degs * ratio; \n float x = progress; \n float magnitude = mix(0.02, 0.09, smoothstep(0.0, 1.0, x)); \n float offset = mix(40.0, 30.0, smoothstep(0.0, 1.0, x)); \n float ease_degs = quadraticInOut(sin(degs)); \n float deg_wave_pos = (ease_degs * magnitude) * sin(x * offset); \n return x + deg_wave_pos;\n}\n\nvec4 transition(vec2 p) { \n float dist = distance(center, p); \n float m = getGradient(getWave(p), dist); \n vec4 cfrom = getFromColor(p); \n vec4 cto = getToColor(p); \n return mix(mix(cfrom, cto, m), mix(cfrom, vec4(color, 1.0), 0.75), step(m, -2.0));\n}\n`;\n\nexport const UNDULATING_BURN_OUT_UNIFORMS: Record<string, { value: any; type: string }> = {\n smoothness: { value: 0.1, type: \"f32\" },\n center: { value: [0.5, 0.5], type: \"vec2<f32>\" },\n color: { value: [1.0, 0.5, 0.0], type: \"vec3<f32>\" },\n};\n\n/**\n * SquaresWire transition configuration\n * Custom fragment shader and uniforms for SquaresWire transition\n */\n\nexport const SQUARESWIRE_FRAGMENT = `\nuniform ivec2 squares;\nuniform vec2 direction;\nuniform float smoothness;\n\nvec4 transition (vec2 p) { \n vec2 v = normalize(direction); \n v /= abs(v.x)+abs(v.y); \n float d = v.x * center.x + v.y * center.y; \n float offset = smoothness; \n float pr = smoothstep(-offset, 0.0, v.x * p.x + v.y * p.y - (d-0.5+progress*(1.+offset))); \n vec2 squarep = fract(p*vec2(squares)); \n vec2 squaremin = vec2(pr/2.0); \n vec2 squaremax = vec2(1.0 - pr/2.0); \n float a = (1.0 - step(progress, 0.0)) * step(squaremin.x, squarep.x) * step(squaremin.y, squarep.y) * step(squarep.x, squaremax.x) * step(squarep.y, squaremax.y); \n return mix(getFromColor(p), getToColor(p), a);\n}\n`;\n\nexport const SQUARESWIRE_UNIFORMS: Record<string, { value: any; type: string }> = {\n squares: { value: [10, 10], type: \"vec2<i32>\" },\n direction: { value: [1.0, -0.5], type: \"vec2<f32>\" },\n smoothness: { value: 1.6, type: \"f32\" },\n};\n\n/**\n * RotateScaleFade transition configuration\n * Custom fragment shader and uniforms for RotateScaleFade transition\n */\n\nexport const ROTATE_SCALE_FADE_FRAGMENT = `\n#define PI 3.14159265359\n\nuniform float rotations;\nuniform float scale;\nuniform vec4 backColor;\n\nvec4 transition (vec2 uv) { \n vec2 difference = uv - center; \n vec2 dir = normalize(difference); \n float dist = length(difference); \n\n float angle = 2.0 * PI * rotations * progress; \n\n float c = cos(angle); \n float s = sin(angle); \n\n float currentScale = mix(scale, 1.0, 2.0 * abs(progress - 0.5)); \n\n vec2 rotatedDir = vec2(dir.x * c - dir.y * s, dir.x * s + dir.y * c); \n vec2 rotatedUv = center + rotatedDir * dist / currentScale; \n\n if (rotatedUv.x < 0.0 || rotatedUv.x > 1.0 || \n rotatedUv.y < 0.0 || rotatedUv.y > 1.0) \n return backColor; \n\n return mix(getFromColor(rotatedUv), getToColor(rotatedUv), progress);\n}\n`;\n\nexport const ROTATE_SCALE_FADE_UNIFORMS: Record<string, { value: any; type: string }> = {\n center: { value: [0.5, 0.5], type: \"vec2<f32>\" },\n rotations: { value: 1.0, type: \"f32\" },\n scale: { value: 8.0, type: \"f32\" },\n backColor: { value: [0.15, 0.15, 0.15, 1.0], type: \"vec4<f32>\" },\n};\n\n/**\n * RandomSquares transition configuration\n * Custom fragment shader and uniforms for RandomSquares transition\n */\n\nexport const RANDOMSQUARES_FRAGMENT = `\nuniform ivec2 size;\nuniform float smoothness;\n\nfloat rand (vec2 co) { \n return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);\n}\n\nvec4 transition(vec2 p) { \n float r = rand(floor(vec2(size) * p)); \n float m = smoothstep(0.0, -smoothness, r - (progress * (1.0 + smoothness))); \n return mix(getFromColor(p), getToColor(p), m);\n}\n`;\n\nexport const RANDOMSQUARES_UNIFORMS: Record<string, { value: any; type: string }> = {\n size: { value: [10, 10], type: \"vec2<i32>\" },\n smoothness: { value: 0.5, type: \"f32\" },\n};\n\n/**\n * PolarFunction transition configuration\n * Custom fragment shader and uniforms for PolarFunction transition\n */\n\nexport const POLAR_FUNCTION_FRAGMENT = `\n#define PI 3.14159265359\n\nuniform int segments;\n\nvec4 transition (vec2 uv) { \n float angle = atan(uv.y - 0.5, uv.x - 0.5) - 0.5 * PI; \n float normalized = (angle + 1.5 * PI) * (2.0 * PI); \n\n float radius = (cos(float(segments) * angle) + 4.0) / 4.0; \n float difference = length(uv - vec2(0.5, 0.5)); \n\n if (difference > radius * progress) \n return getFromColor(uv); \n else \n return getToColor(uv);\n}\n`;\n\nexport const POLAR_FUNCTION_UNIFORMS: Record<string, { value: any; type: string }> = {\n segments: { value: 5, type: \"i32\" },\n};\n\n/**\n * Pixelize transition configuration\n * Custom fragment shader and uniforms for Pixelize transition\n */\n\nexport const PIXELIZE_FRAGMENT = `\nuniform ivec2 squaresMin;\nuniform int steps;\n\nvec4 transition(vec2 uv) { \n float d = min(progress, 1.0 - progress);\n float dist = steps>0 ? ceil(d * float(steps)) / float(steps) : d;\n vec2 squareSize = 2.0 * dist / vec2(squaresMin);\n \n vec2 p = dist>0.0 ? (floor(uv / squareSize) + 0.5) * squareSize : uv; \n return mix(getFromColor(p), getToColor(p), progress);\n}\n`;\n\nexport const PIXELIZE_UNIFORMS: Record<string, { value: any; type: string }> = {\n squaresMin: { value: [20, 20], type: \"vec2<i32>\" },\n steps: { value: 50, type: \"i32\" },\n};\n\n/**\n * Perlin transition configuration\n * Custom fragment shader and uniforms for Perlin transition\n */\n\nexport const PERLIN_FRAGMENT = `\nuniform float scale;\nuniform float smoothness;\nuniform float seed;\n\n// http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/\nfloat random(vec2 co)\n{ \n float a = seed; \n float b = 78.233; \n float c = 43758.5453; \n float dt = dot(co.xy, vec2(a, b)); \n float sn = mod(dt, 3.14); \n return fract(sin(sn) * c);\n}\n\n// 2D Noise based on Morgan McGuire @morgan3d\n// https://www.shadertoy.com/view/4dS3Wd\nfloat noise(vec2 st) { \n vec2 i = floor(st); \n vec2 f = fract(st); \n\n // Four corners in 2D of a tile \n float a = random(i); \n float b = random(i + vec2(1.0, 0.0)); \n float c = random(i + vec2(0.0, 1.0)); \n float d = random(i + vec2(1.0, 1.0)); \n\n //Smooth Interpolation \n\n // Cubic Hermine Curve. Same as SmoothStep() \n vec2 u = f*f*(3.0-2.0*f); \n // u = smoothstep(0.,1.,f); \n\n // Mix 4 coorners percentages \n return mix(a, b, u.x) + \n (c - a)* u.y * (1.0 - u.x) + \n (d - b) * u.x * u.y;\n}\n\nvec4 transition (vec2 uv) { \n vec4 from = getFromColor(uv); \n vec4 to = getToColor(uv); \n float n = noise(uv * scale); \n\n float p = mix(-smoothness, 1.0 + smoothness, progress); \n float lower = p - smoothness; \n float higher = p + smoothness; \n\n float q = smoothstep(lower, higher, n); \n\n return mix( \n from, \n to, \n 1.0 - q \n );\n}\n`;\n\nexport const PERLIN_UNIFORMS: Record<string, { value: any; type: string }> = {\n scale: { value: 4.0, type: \"f32\" },\n smoothness: { value: 0.01, type: \"f32\" },\n seed: { value: 12.9898, type: \"f32\" },\n};\n\n/**\n * Luma transition configuration\n * Custom fragment shader and uniforms for Luma transition\n * Creates a counter-clockwise spiral effect that fragments the image\n */\n\nexport const LUMA_FRAGMENT = `\n\n#define PI 3.14159265358979323846\n\nuniform float spiralTurns;\nuniform float spiralWidth;\n\nvec4 transition(vec2 uv) {\n\n vec2 p = uv - center;\n\n float r = length(p);\n float angle = atan(p.y, p.x);\n\n float normalizedAngle = (angle + PI) / (2.0 * PI);\n\n float spiral = normalizedAngle + r * spiralTurns;\n spiral = fract(spiral);\n\n float factor = smoothstep(\n progress - spiralWidth,\n progress + spiralWidth,\n spiral\n );\n return mix(\n getToColor(uv), // ahora aparece primero\n getFromColor(uv), // aparece después\n factor\n );\n}\n\n\n`;\n\nexport const LUMA_UNIFORMS: Record<string, { value: any; type: string }> = {\n spiralTurns: { value: 1.5, type: \"f32\" },\n spiralWidth: { value: 0.02, type: \"f32\" },\n};\n\n/**\n * LuminanceMelt transition configuration\n * Custom fragment shader and uniforms for LuminanceMelt transition\n * Creates a melting effect based on luminance threshold\n */\n\nexport const LUMINANCE_MELT_FRAGMENT = `\n//direction of movement : 0 : up, 1, down\nuniform float direction; // = 1.0 (using float instead of bool for WebGPU)\n\n//luminance threshold\nuniform float l_threshold; // = 0.8\n\n//does the movement take effect above or below luminance threshold ?\nuniform float above; // = 0.0 (false) (using float instead of bool for WebGPU)\n\n//Random function borrowed from everywhere\nfloat rand(vec2 co){ \n return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);\n}\n\n// Simplex noise:\n// Description : Array and textureless GLSL 2D simplex noise function.\n// Author: Ian McEwan, Ashima Arts.\n// Maintainer : ijm\n// Lastmod: 20110822 (ijm)\n// License: MIT\n// 2011 Ashima Arts. All rights reserved.\n// Distributed under the MIT License. See LICENSE file.\n// https://github.com/ashima/webgl-noise\n\nvec3 mod289(vec3 x) { \n return x - floor(x * (1.0 / 289.0)) * 289.0;\n}\n\nvec2 mod289(vec2 x) { \n return x - floor(x * (1.0 / 289.0)) * 289.0;\n}\n\nvec3 permute(vec3 x) { \n return mod289(((x*34.0)+1.0)*x);\n}\n\nfloat snoise(vec2 v) \n{ \n const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 \n 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) \n -0.577350269189626, // -1.0 + 2.0 * C.x \n 0.024390243902439); // 1.0 / 41.0\n // First corner \n vec2 i = floor(v + dot(v, C.yy) ); \n vec2 x0 = v - i + dot(i, C.xx);\n\n // Other corners \n vec2 i1; \n //i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0 \n //i1.y = 1.0 - i1.x; \n i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); \n // x0 = x0 - 0.0 + 0.0 * C.xx ; \n // x1 = x0 - i1 + 1.0 * C.xx ; \n // x2 = x0 - 1.0 + 2.0 * C.xx ; \n vec4 x12 = x0.xyxy + C.xxzz; \n x12.xy -= i1;\n\n //Permutations \n i = mod289(i); // Avoid truncation effects in permutation \n vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) \n + i.x + vec3(0.0, i1.x, 1.0 )); \n\n vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); \n m = m*m ; \n m = m*m ;\n\n // Gradients: 41 points uniformly over a line, mapped onto a diamond.\n // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) \n\n vec3 x = 2.0 * fract(p * C.www) - 1.0; \n vec3 h = abs(x) - 0.5; \n vec3 ox = floor(x + 0.5); \n vec3 a0 = x - ox;\n\n // Normalize gradients implicitly by scaling m\n // Approximation of: m *= inversesqrt( a0*a0 + h*h ); \n m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );\n\n // Compute final noise value at P \n vec3 g; \n g.x = a0.x * x0.x + h.x * x0.y; \n g.yz = a0.yz * x12.xz + h.yz * x12.yw; \n return 130.0 * dot(m, g);\n}\n\n// Simplex noise -- end\n\nfloat luminance(vec4 color){ \n //(0.299*R + 0.587*G + 0.114*B) \n return color.r*0.299+color.g*0.587+color.b*0.114;\n}\n\nvec4 transition(vec2 uv) { \n vec2 p = uv.xy / vec2(1.0).xy; \n vec2 center = vec2(1.0, direction);\n \n if (progress == 0.0) { \n return getFromColor(p); \n } else if (progress == 1.0) { \n return getToColor(p); \n } else { \n float x = progress; \n float dist = distance(center, p) - progress*exp(snoise(vec2(p.x, 0.0))); \n float r = x - rand(vec2(p.x, 0.1)); \n float m; \n if(above > 0.5){ \n m = dist <= r && luminance(getFromColor(p))>l_threshold ? 1.0 : (progress*progress*progress); \n } \n else{ \n m = dist <= r && luminance(getFromColor(p))<l_threshold ? 1.0 : (progress*progress*progress); \n } \n return mix(getFromColor(p), getToColor(p), m); \n }\n}\n`;\n\nexport const LUMINANCE_MELT_UNIFORMS: Record<string, { value: any; type: string }> = {\n direction: { value: 1.0, type: \"f32\" }, // 0.0 = up, 1.0 = down\n l_threshold: { value: 0.8, type: \"f32\" },\n above: { value: 0.0, type: \"f32\" }, // 0.0 = false (below threshold), 1.0 = true (above threshold)\n};\n\n/**\n * Hexagonalize transition configuration\n * Custom fragment shader and uniforms for Hexagonalize transition\n * Creates a hexagonal pixelation effect\n */\n\nexport const HEXAGONALIZE_FRAGMENT = `\nuniform int steps; // = 50\nuniform float horizontalHexagons; // = 20.0\n\nstruct Hexagon { \n float q; \n float r; \n float s;\n};\n\nHexagon createHexagon(float q, float r){ \n Hexagon hex; \n hex.q = q; \n hex.r = r; \n hex.s = -q - r; \n return hex;\n}\n\nHexagon roundHexagon(Hexagon hex){ \n float q = floor(hex.q + 0.5); \n float r = floor(hex.r + 0.5); \n float s = floor(hex.s + 0.5); \n\n float deltaQ = abs(q - hex.q); \n float deltaR = abs(r - hex.r); \n float deltaS = abs(s - hex.s); \n\n if (deltaQ > deltaR && deltaQ > deltaS) \n q = -r - s; \n else if (deltaR > deltaS) \n r = -q - s; \n else \n s = -q - r; \n\n return createHexagon(q, r);\n}\n\nHexagon hexagonFromPoint(vec2 point, float size) { \n point.y /= ratio; \n point = (point - 0.5) / size; \n\n float q = (sqrt(3.0) / 3.0) * point.x + (-1.0 / 3.0) * point.y; \n float r = 0.0 * point.x + 2.0/3.0 * point.y; \n\n Hexagon hex = createHexagon(q, r); \n return roundHexagon(hex);\n}\n\nvec2 pointFromHexagon(Hexagon hex, float size) { \n float x = (sqrt(3.0) * hex.q + (sqrt(3.0) / 2.0) * hex.r) * size + 0.5; \n float y = (0.0 * hex.q + (3.0/2.0) * hex.r) * size + 0.5; \n\n return vec2(x, y * ratio);\n}\n\nvec4 transition (vec2 uv) { \n float dist = 2.0 * min(progress, 1.0 - progress); \n dist = steps > 0 ? ceil(dist * float(steps)) / float(steps) : dist; \n\n float size = (sqrt(3.0) / 3.0) * dist / horizontalHexagons; \n\n vec2 point = dist > 0.0 ? pointFromHexagon(hexagonFromPoint(uv, size), size) : uv; \n\n return mix(getFromColor(point), getToColor(point), progress);\n}\n`;\n\nexport const HEXAGONALIZE_UNIFORMS: Record<string, { value: any; type: string }> = {\n steps: { value: 50, type: \"i32\" },\n horizontalHexagons: { value: 20.0, type: \"f32\" },\n};\n\n/**\n * Heart transition configuration\n * Custom fragment shader and uniforms for Heart transition\n * Creates a heart-shaped reveal effect\n */\n\nexport const HEART_FRAGMENT = `\nfloat inHeart (vec2 p, vec2 center, float size) { \n if (size==0.0) return 0.0; \n vec2 o = (p-center)/(1.6*size); \n o.y = -o.y;\n float a = o.x*o.x+o.y*o.y-0.3; \n return step(a*a*a, o.x*o.x*o.y*o.y*o.y);\n}\n\nvec4 transition (vec2 uv) { \n return mix( \n getFromColor(uv), \n getToColor(uv), \n inHeart(uv, vec2(0.5, 0.5), progress) \n );\n}\n`;\n\nexport const HEART_UNIFORMS: Record<string, { value: any; type: string }> = {\n // No custom uniforms needed, uses progress from basics\n};\n\n/**\n * Displacement transition configuration\n * Custom fragment shader and uniforms for Displacement transition\n * Creates a displacement effect using a displacement map\n */\n\nexport const DISPLACEMENT_FRAGMENT = `\nuniform sampler2D displacementMap;\nuniform float strength; // = 0.5\n\nvec4 transition (vec2 uv) { \n float displacement = texture2D(displacementMap, uv).r * strength; \n\n vec2 uvFrom = vec2(uv.x + progress * displacement, uv.y); \n vec2 uvTo = vec2(uv.x - (1.0 - progress) * displacement, uv.y); \n\n return mix( \n getFromColor(uvFrom), \n getToColor(uvTo), \n progress \n );\n}\n`;\n\nexport const DISPLACEMENT_UNIFORMS: Record<string, { value: any; type: string }> = {\n strength: { value: 0.5, type: \"f32\" },\n};\n\n/**\n * DirectionalWipe transition configuration\n * Custom fragment shader and uniforms for DirectionalWipe transition\n * Creates a directional wipe effect\n */\n\nexport const DIRECTIONALWIPE_FRAGMENT = `\nuniform vec2 direction; // = vec2(1.0, -1.0)\nuniform float smoothness; // = 0.5\n\n// Note: center is already defined as a uniform in the fragment wrapper\n\nvec4 transition (vec2 uv) {\n vec2 v = normalize(direction);\n v /= abs(v.x)+abs(v.y);\n float d = v.x * center.x + v.y * center.y;\n float m = \n (1.0-step(progress, 0.0)) * // there is something wrong with our formula that makes m not equals 0.0 with progress is 0.0 \n (1.0 - smoothstep(-smoothness, 0.0, v.x * uv.x + v.y * uv.y - (d-0.5+progress*(1.+smoothness)))); \n return mix(getFromColor(uv), getToColor(uv), m);\n}\n`;\n\nexport const DIRECTIONALWIPE_UNIFORMS: Record<string, { value: any; type: string }> = {\n direction: { value: [1.0, -1.0], type: \"vec2<f32>\" },\n smoothness: { value: 0.5, type: \"f32\" },\n};\n\n/**\n * DirectionalWarp transition configuration\n * Custom fragment shader and uniforms for DirectionalWarp transition\n * Creates a directional warp effect\n */\n\nexport const DIRECTIONALWARP_FRAGMENT = `\nuniform vec2 direction; // = vec2(-1.0, 1.0)\n\nconst float smoothness = 0.5;\n// Note: center is already defined as a uniform in the fragment wrapper\n\nvec4 transition (vec2 uv) { \n vec2 v = normalize(direction); \n v /= abs(v.x) + abs(v.y); \n float d = v.x * center.x + v.y * center.y; \n float m = 1.0 - smoothstep(-smoothness, 0.0, v.x * uv.x + v.y * uv.y - (d - 0.5 + progress * (1.0 + smoothness))); \n return mix(getFromColor((uv - 0.5) * (1.0 - m) + 0.5), getToColor((uv - 0.5) * m + 0.5), m);\n}\n`;\n\nexport const DIRECTIONALWARP_UNIFORMS: Record<string, { value: any; type: string }> = {\n direction: { value: [-1.0, 1.0], type: \"vec2<f32>\" },\n};\n\n/**\n * Crosshatch transition configuration\n * Custom fragment shader and uniforms for Crosshatch transition\n * Creates a crosshatch pattern transition effect\n */\n\nexport const CROSSHATCH_FRAGMENT = `\nuniform float threshold; // = 3.0\nuniform float fadeEdge; // = 0.1\n\n// Note: center is already defined as a uniform in the fragment wrapper\n\nfloat rand(vec2 co) { \n return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);\n}\n\nvec4 transition(vec2 p) { \n float dist = distance(center, p) / threshold; \n float r = progress - min(rand(vec2(p.y, 0.0)), rand(vec2(0.0, p.x))); \n return mix(getFromColor(p), getToColor(p), mix(0.0, mix(step(dist, r), 1.0, smoothstep(1.0-fadeEdge, 1.0, progress)), smoothstep(0.0, fadeEdge, progress)));\n}\n`;\n\nexport const CROSSHATCH_UNIFORMS: Record<string, { value: any; type: string }> = {\n threshold: { value: 3.0, type: \"f32\" },\n fadeEdge: { value: 0.1, type: \"f32\" },\n};\n\n/**\n * CircleOpen transition configuration\n * Custom fragment shader and uniforms for CircleOpen transition\n * Creates a circular opening/closing transition effect\n */\n\nexport const CIRCLEOPEN_FRAGMENT = `\nuniform float smoothness; // = 0.3\nuniform float opening; // = 1.0 (using float instead of bool for WebGPU: 1.0 = true, 0.0 = false)\n\n// Note: center is already defined as a uniform in the fragment wrapper\nconst float SQRT_2 = 1.414213562373;\n\nvec4 transition (vec2 uv) { \n float x = opening > 0.5 ? progress : 1.0 - progress; \n float m = smoothstep(-smoothness, 0.0, SQRT_2*distance(center, uv) - x*(1.0+smoothness)); \n return mix(getFromColor(uv), getToColor(uv), opening > 0.5 ? 1.0 - m : m);\n}\n`;\n\nexport const CIRCLEOPEN_UNIFORMS: Record<string, { value: any; type: string }> = {\n smoothness: { value: 0.3, type: \"f32\" },\n opening: { value: 1.0, type: \"f32\" }, // 1.0 = true (opening), 0.0 = false (closing)\n};\n\n/**\n * CannabisLeaf transition configuration\n * Custom fragment shader and uniforms for CannabisLeaf transition\n * Creates a cannabis leaf-shaped reveal effect\n */\n\nexport const CANNABISLEAF_FRAGMENT = `\nvec4 transition (vec2 uv) {\n if(progress == 0.0){\n return getFromColor(uv);\n }\n vec2 leaf_uv = (uv - vec2(0.5))/10.0/pow(progress,3.5);\n leaf_uv.y = -leaf_uv.y;\n leaf_uv.y += 0.35;\n float r = 0.18;\n float o = atan(leaf_uv.y, leaf_uv.x);\n return mix(getFromColor(uv), getToColor(uv), 1.0-step(1.0 - length(leaf_uv)+r*(1.0+sin(o))*(1.0+0.9 * cos(8.0*o))*(1.0+0.1*cos(24.0*o))*(0.9+0.05*cos(200.0*o)), 1.0));\n}\n`;\n\nexport const CANNABISLEAF_UNIFORMS: Record<string, { value: any; type: string }> = {\n // No custom uniforms needed\n};\n\n/**\n * StereoViewer transition configuration\n * Custom fragment shader and uniforms for StereoViewer transition\n * Creates a stereo viewer effect with rounded corners and cross rotation\n */\n\nexport const STEREOVIEWER_FRAGMENT = `\nuniform float zoom; // = 0.88\nuniform float corner_radius; // = 0.22\n\nconst vec4 black = vec4(0.0, 0.0, 0.0, 1.0);\nconst vec2 c00 = vec2(0.0, 0.0);\nconst vec2 c01 = vec2(0.0, 1.0);\nconst vec2 c11 = vec2(1.0, 1.0);\nconst vec2 c10 = vec2(1.0, 0.0);\n\nbool in_corner(vec2 p, vec2 corner, vec2 radius) { \n vec2 axis = (c11 - corner) - corner; \n p = p - (corner + axis * radius); \n p *= axis / radius; \n return (p.x > 0.0 && p.y > -1.0) || (p.y > 0.0 && p.x > -1.0) || dot(p, p) < 1.0;\n}\n\nbool test_rounded_mask(vec2 p, vec2 corner_size) { \n return \n in_corner(p, c00, corner_size) && \n in_corner(p, c01, corner_size) && \n in_corner(p, c10, corner_size) && \n in_corner(p, c11, corner_size);\n}\n\nvec4 screen(vec4 a, vec4 b) { \n return 1.0 - (1.0 - a) * (1.0 - b);\n}\n\nvec4 unscreen(vec4 c) { \n return 1.0 - sqrt(1.0 - c);\n}\n\nvec4 sample_with_corners_from(vec2 p, vec2 corner_size) { \n p = (p - 0.5) / zoom + 0.5; \n if (!test_rounded_mask(p, corner_size)) { \n return black; \n } \n return unscreen(getFromColor(p));\n}\n\nvec4 sample_with_corners_to(vec2 p, vec2 corner_size) { \n p = (p - 0.5) / zoom + 0.5; \n if (!test_rounded_mask(p, corner_size)) { \n return black; \n } \n return unscreen(getToColor(p));\n}\n\nvec4 simple_sample_with_corners_from(vec2 p, vec2 corner_size, float zoom_amt) { \n p = (p - 0.5) / (1.0 - zoom_amt + zoom * zoom_amt) + 0.5; \n if (!test_rounded_mask(p, corner_size)) { \n return black; \n } \n return getFromColor(p);\n}\n\nvec4 simple_sample_with_corners_to(vec2 p, vec2 corner_size, float zoom_amt) { \n p = (p - 0.5) / (1.0 - zoom_amt + zoom * zoom_amt) + 0.5; \n if (!test_rounded_mask(p, corner_size)) { \n return black; \n } \n return getToColor(p);\n}\n\nmat3 rotate2d(float angle, float ratio) { \n float s = sin(angle); \n float c = cos(angle); \n return mat3( \n c, s, 0.0, \n -s, c, 0.0, \n 0.0, 0.0, 1.0);\n}\n\nmat3 translate2d(float x, float y) { \n return mat3( \n 1.0, 0.0, 0.0, \n 0.0, 1.0, 0.0, \n -x, -y, 1.0);\n}\n\nmat3 scale2d(float x, float y) { \n return mat3( \n x, 0.0, 0.0, \n 0.0, y, 0.0, \n 0.0, 0.0, 1.0);\n}\n\n// Split an image and rotate one up and one down along off screen pivot points\nvec4 get_cross_rotated(vec3 p3, float angle, vec2 corner_size, float ratio) { \n angle = angle * angle; // easing \n angle /= 2.4; // works out to be a good number of radians \n\n mat3 center_and_scale = translate2d(-0.5, -0.5) * scale2d(1.0, ratio); \n mat3 unscale_and_uncenter = scale2d(1.0, 1.0/ratio) * translate2d(0.5, 0.5); \n mat3 slide_left = translate2d(-2.0, 0.0); \n mat3 slide_right = translate2d(2.0, 0.0); \n mat3 rotate = rotate2d(angle, ratio); \n\n mat3 op_a = center_and_scale * slide_right * rotate * slide_left * unscale_and_uncenter; \n mat3 op_b = center_and_scale * slide_left * rotate * slide_right * unscale_and_uncenter; \n\n vec4 a = sample_with_corners_from((op_a * p3).xy, corner_size); \n vec4 b = sample_with_corners_from((op_b * p3).xy, corner_size); \n\n return screen(a, b);\n}\n\n// Image stays put, but this time moves two masks\nvec4 get_cross_masked(vec3 p3, float angle, vec2 corner_size, float ratio) { \n angle = 1.0 - angle; \n angle = angle * angle; // easing \n angle /= 2.4; \n\n vec4 img; \n\n mat3 center_and_scale = translate2d(-0.5, -0.5) * scale2d(1.0, ratio); \n mat3 unscale_and_uncenter = scale2d(1.0 / zoom, 1.0 / (zoom * ratio)) * translate2d(0.5, 0.5); \n mat3 slide_left = translate2d(-2.0, 0.0); \n mat3 slide_right = translate2d(2.0, 0.0); \n mat3 rotate = rotate2d(angle, ratio); \n\n mat3 op_a = center_and_scale * slide_right * rotate * slide_left * unscale_and_uncenter; \n mat3 op_b = center_and_scale * slide_left * rotate * slide_right * unscale_and_uncenter; \n\n bool mask_a = test_rounded_mask((op_a * p3).xy, corner_size); \n bool mask_b = test_rounded_mask((op_b * p3).xy, corner_size); \n\n if (mask_a || mask_b) { \n img = sample_with_corners_to(p3.xy, corner_size); \n return screen(mask_a ? img : black, mask_b ? img : black); \n } else { \n return black; \n }\n}\n\nvec4 transition(vec2 uv) { \n float a; \n vec2 p = uv.xy / vec2(1.0).xy; \n vec3 p3 = vec3(p.xy, 1.0); \n\n vec2 corner_size = vec2(corner_radius / ratio, corner_radius); \n\n if (progress <= 0.0) { \n return getFromColor(p); \n } else if (progress < 0.1) { \n a = progress / 0.1; \n return simple_sample_with_corners_from(p, corner_size * a, a); \n } else if (progress < 0.48) { \n a = (progress - 0.1) / 0.38; \n return get_cross_rotated(p3, a, corner_size, ratio); \n } else if (progress < 0.9) { \n return get_cross_masked(p3, (progress - 0.52) / 0.38, corner_size, ratio); \n } else if (progress < 1.0) { \n a = (1.0 - progress) / 0.1; \n return simple_sample_with_corners_to(p, corner_size * a, a); \n } else { \n return getToColor(p); \n }\n}\n`;\n\nexport const STEREOVIEWER_UNIFORMS: Record<string, { value: any; type: string }> = {\n zoom: { value: 0.88, type: \"f32\" },\n corner_radius: { value: 0.22, type: \"f32\" },\n};\n\n/**\n * GlitchDisplace transition configuration\n * Custom fragment shader for GlitchDisplace transition\n */\n\nexport const GLITCH_DISPLACE_FRAGMENT = `\nfloat random(vec2 co) { \n float a = 12.9898; \n float b = 78.233; \n float c = 43758.5453; \n float dt = dot(co.xy, vec2(a, b)); \n float sn = mod(dt, 3.14); \n return fract(sin(sn) * c);\n}\n\nfloat voronoi(vec2 x) { \n vec2 p = floor(x); \n vec2 f = fract(x); \n float res = 8.0; \n for(float j = -1.; j <= 1.; j++) \n for(float i = -1.; i <= 1.; i++) { \n vec2 b = vec2(i, j); \n vec2 r = b - f + random(p + b); \n float d = dot(r, r); \n res = min(res, d); \n } \n return sqrt(res);\n}\n\nvec2 displace(vec4 tex, vec2 texCoord, float dotDepth, float textureDepth, float strength) { \n float b = voronoi(.003 * texCoord + 2.0); \n float g = voronoi(0.2 * texCoord); \n float r = voronoi(texCoord - 1.0); \n vec4 dt = tex * 1.0; \n vec4 dis = dt * dotDepth + 1.0 - tex * textureDepth; \n\n dis.x = dis.x - 1.0 + textureDepth * dotDepth; \n dis.y = dis.y - 1.0 + textureDepth * dotDepth; \n dis.x *= strength; \n dis.y *= strength; \n vec2 res_uv = texCoord; \n res_uv.x = res_uv.x + dis.x - 0.0; \n res_uv.y = res_uv.y + dis.y; \n return res_uv;\n}\n\nfloat ease1(float t) { \n return t == 0.0 || t == 1.0 \n ? t \n : t < 0.5 \n ? +0.5 * pow(2.0, (20.0 * t) - 10.0) \n : -0.5 * pow(2.0, 10.0 - (t * 20.0)) + 1.0;\n}\n\nfloat ease2(float t) { \n return t == 1.0 ? t : 1.0 - pow(2.0, -10.0 * t);\n}\n\nvec4 transition(vec2 uv) { \n vec2 p = uv.xy / vec2(1.0).xy; \n vec4 color1 = getFromColor(p); \n vec4 color2 = getToColor(p); \n vec2 disp = displace(color1, p, 0.33, 0.7, 1.0 - ease1(progress)); \n vec2 disp2 = displace(color2, p, 0.33, 0.5, ease2(progress)); \n vec4 dColor1 = getToColor(disp); \n vec4 dColor2 = getFromColor(disp2); \n float val = ease1(progress); \n vec3 gray = vec3(dot(min(dColor2, dColor1).rgb, vec3(0.299, 0.587, 0.114))); \n dColor2 = vec4(gray, 1.0); \n dColor2 *= 2.0; \n color1 = mix(color1, dColor2, smoothstep(0.0, 0.5, progress)); \n color2 = mix(color2, dColor1, smoothstep(1.0, 0.5, progress)); \n return mix(color1, color2, val); \n}\n`;\n\n/**\n * CrossZoom transition configuration\n * Custom fragment shader and uniforms for CrossZoom transition\n */\n\nexport const CROSSZOOM_FRAGMENT = `\nuniform float strength; // = 0.4\n\nconst float PI = 3.141592653589793;\n\nfloat Linear_ease(float begin, float change, float duration, float time) { \n return change * time / duration + begin;\n}\n\nfloat Exponential_easeInOut(float begin, float change, float duration, float time) { \n if (time == 0.0) \n return begin; \n else if (time == duration) \n return begin + change; \n time = time / (duration / 2.0); \n if (time < 1.0) \n return change / 2.0 * pow(2.0, 10.0 * (time - 1.0)) + begin; \n return change / 2.0 * (-pow(2.0, -10.0 * (time - 1.0)) + 2.0) + begin;\n}\n\nfloat Sine_easeInOut(float begin, float change, float duration, float time) { \n return -change / 2.0 * (cos(PI * time / duration) - 1.0) + begin;\n}\n\nfloat rand(vec2 co) { \n return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\nvec3 crossFade(vec2 uv, float dissolve) { \n return mix(getFromColor(uv).rgb, getToColor(uv).rgb, dissolve);\n}\n\nvec4 transition(vec2 uv) { \n vec2 texCoord = uv.xy / vec2(1.0).xy; \n\n // Linear interpolate center across center half of the image \n vec2 center = vec2(Linear_ease(0.25, 0.5, 1.0, progress), 0.5); \n float dissolve = Exponential_easeInOut(0.0, 1.0, 1.0, progress); \n\n // Mirrored sine loop. 0->strength then strength->0 \n float strengthValue = Sine_easeInOut(0.0, strength, 0.5, progress); \n\n vec3 color = vec3(0.0); \n float total = 0.0; \n vec2 toCenter = center - texCoord; \n\n /* randomize the lookup values to hide the fixed number of samples */ \n float offset = rand(uv); \n\n for (float t = 0.0; t <= 40.0; t++) { \n float percent = (t + offset) / 40.0; \n float weight = 4.0 * (percent - percent * percent); \n color += crossFade(texCoord + toCenter * percent * strengthValue, dissolve) * weight; \n total += weight; \n } \n return vec4(color / total, 1.0);\n}\n`;\n\nexport const CROSSZOOM_UNIFORMS: Record<string, { value: any; type: string }> = {\n strength: { value: 0.4, type: \"f32\" },\n};\n\n/**\n * CrazyParametricFun transition configuration\n * Custom fragment shader and uniforms for CrazyParametricFun transition\n */\n\nexport const CRAZY_PARAMETRIC_FUN_FRAGMENT = `\nuniform float a; // = 4\nuniform float b; // = 1\nuniform float amplitude; // = 120\nuniform float smoothness; // = 0.1\n\nvec4 transition(vec2 uv) { \n vec2 p = uv.xy / vec2(1.0).xy; \n vec2 dir = p - vec2(.5); \n float dist = length(dir); \n float x = (a - b) * cos(progress) + b * cos(progress * ((a / b) - 1.)); \n float y = (a - b) * sin(progress) - b * sin(progress * ((a / b) - 1.)); \n vec2 offset = dir * vec2(sin(progress * dist * amplitude * x), sin(progress * dist * amplitude * y)) / smoothness; \n return mix(getFromColor(p + offset), getToColor(p), smoothstep(0.2, 1.0, progress));\n}\n`;\n\nexport const CRAZY_PARAMETRIC_FUN_UNIFORMS: Record<string, { value: any; type: string }> = {\n a: { value: 4.0, type: \"f32\" },\n b: { value: 1.0, type: \"f32\" },\n amplitude: { value: 120.0, type: \"f32\" },\n smoothness: { value: 0.1, type: \"f32\" },\n};\n\n/**\n * ColourDistance transition configuration\n * Custom fragment shader and uniforms for ColourDistance transition\n */\n\nexport const COLOUR_DISTANCE_FRAGMENT = `\nuniform float power; // = 5.0\n\nvec4 transition(vec2 p) { \n vec4 fTex = getFromColor(p); \n vec4 tTex = getToColor(p); \n float m = step(distance(fTex, tTex), progress); \n return mix( \n mix(fTex, tTex, m), \n tTex, \n pow(progress, power) \n );\n}\n`;\n\nexport const COLOUR_DISTANCE_UNIFORMS: Record<string, { value: any; type: string }> = {\n power: { value: 5.0, type: \"f32\" },\n};\n\nexport const BOW_TIE_HORIZONTAL_FRAGMENT = `\n// License: MIT\n\nvec2 bottom_left = vec2(0.0, 1.0);\nvec2 bottom_right = vec2(1.0, 1.0);\nvec2 top_left = vec2(0.0, 0.0);\nvec2 top_right = vec2(1.0, 0.0);\n\nfloat check(vec2 p1, vec2 p2, vec2 p3)\n{\n return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y);\n}\n\nbool PointInTriangle (vec2 pt, vec2 p1, vec2 p2, vec2 p3)\n{\n bool b1, b2, b3;\n b1 = check(pt, p1, p2) < 0.0;\n b2 = check(pt, p2, p3) < 0.0;\n b3 = check(pt, p3, p1) < 0.0;\n return ((b1 == b2) && (b2 == b3));\n}\n\nbool in_left_triangle(vec2 p){\n vec2 vertex1, vertex2, vertex3;\n vertex1 = vec2(progress, 0.5);\n vertex2 = vec2(0.0, 0.5-progress);\n vertex3 = vec2(0.0, 0.5+progress);\n if (PointInTriangle(p, vertex1, vertex2, vertex3))\n {\n return true;\n }\n return false;\n}\n\nbool in_right_triangle(vec2 p){\n vec2 vertex1, vertex2, vertex3;\n vertex1 = vec2(1.0-progress, 0.5);\n vertex2 = vec2(1.0, 0.5-progress);\n vertex3 = vec2(1.0, 0.5+progress);\n if (PointInTriangle(p, vertex1, vertex2, vertex3))\n {\n return true;\n }\n return false;\n}\n\nfloat blur_edge(vec2 bot1, vec2 bot2, vec2 top, vec2 testPt)\n{\n vec2 lineDir = bot1 - top;\n vec2 perpDir = vec2(lineDir.y, -lineDir.x);\n vec2 dirToPt1 = bot1 - testPt;\n float dist1 = abs(dot(normalize(perpDir), dirToPt1));\n \n lineDir = bot2 - top;\n perpDir = vec2(lineDir.y, -lineDir.x);\n dirToPt1 = bot2 - testPt;\n float min_dist = min(abs(dot(normalize(perpDir), dirToPt1)), dist1);\n \n if (min_dist < 0.005) {\n return min_dist / 0.005;\n }\n else {\n return 1.0;\n };\n}\n\n\nvec4 transition (vec2 uv) {\n if (in_left_triangle(uv))\n {\n if (progress < 0.1)\n {\n return getFromColor(uv);\n }\n if (uv.x < 0.5)\n {\n vec2 vertex1 = vec2(progress, 0.5);\n vec2 vertex2 = vec2(0.0, 0.5-progress);\n vec2 vertex3 = vec2(0.0, 0.5+progress);\n return mix(\n getFromColor(uv),\n getToColor(uv),\n blur_edge(vertex2, vertex3, vertex1, uv)\n );\n }\n else\n {\n if (progress > 0.0)\n {\n return getToColor(uv);\n }\n else\n {\n return getFromColor(uv);\n }\n } \n }\n else if (in_right_triangle(uv))\n {\n if (uv.x >= 0.5)\n {\n vec2 vertex1 = vec2(1.0-progress, 0.5);\n vec2 vertex2 = vec2(1.0, 0.5-progress);\n vec2 vertex3 = vec2(1.0, 0.5+progress);\n return mix(\n getFromColor(uv),\n getToColor(uv),\n blur_edge(vertex2, vertex3, vertex1, uv)\n ); \n }\n else\n {\n return getFromColor(uv);\n }\n }\n else {\n return getFromColor(uv);\n }\n}\n`;\n\nexport const POLKA_DOTS_CURTAIN_FRAGMENT = `\n\nconst float SQRT_2 = 1.414213562373;\nuniform float dots;// = 20.0;\n\nvec4 transition(vec2 uv) {\n bool nextImage = distance(fract(uv * dots), vec2(0.5, 0.5)) < ( progress / distance(uv, center));\n return nextImage ? getToColor(uv) : getFromColor(uv);\n}\n`;\n","//@ts-ignore\nimport glTransitions from \"gl-transitions\";\nimport { getTransitionByKey } from \"@agrhub/core\";\nimport { RADIAL_SWIPE_FRAGMENT } from \"./custom-glsl\";\n\nexport interface GlTransition {\n label: string;\n fragment: string;\n uniforms?: Record<string, { value: any; type: string }>;\n previewDynamic?: string;\n previewStatic?: string;\n}\n\n// Custom transitions that override or extend the library\nconst STATIC_CUSTOM_TRANSITIONS = {\n radialSwipe: {\n label: \"Radial Swipe\",\n fragment: RADIAL_SWIPE_FRAGMENT,\n },\n} as const satisfies Record<string, GlTransition>;\n\n// Registry for runtime custom transitions\nconst REGISTERED_TRANSITIONS: Record<string, GlTransition> = {};\n\n/**\n * Register a custom transition at runtime\n */\nexport function registerCustomTransition(name: string, transition: GlTransition) {\n REGISTERED_TRANSITIONS[name] = transition;\n}\n\n/**\n * Unregister a custom transition at runtime\n */\nexport function unregisterCustomTransition(name: string) {\n delete REGISTERED_TRANSITIONS[name];\n}\n\n/**\n * Get all available transitions, including library, static custom, and runtime registered ones\n */\nexport function getAllTransitions(): Record<string, GlTransition> {\n return {\n ...glTransitions.reduce((acc: Record<string, any>, t: any) => {\n acc[t.name] = {\n label: t.name,\n fragment: t.glsl,\n uniforms: t.defaultParams,\n previewDynamic: \"\",\n };\n return acc;\n }, {}),\n ...STATIC_CUSTOM_TRANSITIONS,\n ...REGISTERED_TRANSITIONS,\n };\n}\n\n// Keep GL_TRANSITIONS for backward compatibility, but it will only contain initial ones\nexport const GL_TRANSITIONS = getAllTransitions();\n\nexport type TransitionKey = string;\n\nexport function getTransitionOptions() {\n const registeredKeys = Object.keys(REGISTERED_TRANSITIONS);\n return Object.entries(getAllTransitions()).map(([key, value]) => {\n const catalogEntry = getTransitionByKey(key);\n return {\n key: key as TransitionKey,\n label: catalogEntry?.name ?? value.label,\n description: catalogEntry?.description,\n category: catalogEntry?.category,\n isCustom: registeredKeys.includes(key) || (catalogEntry?.isCustom ?? false),\n previewStatic:\n value.previewStatic ||\n `https://cdn.subgen.co/previews/static/transition_${key}_static.webp`,\n previewDynamic:\n value.previewDynamic ||\n `https://cdn.subgen.co/previews/dynamic/transition_${key}_dynamic.webp`,\n };\n });\n}\n\n// Keep GL_TRANSITION_OPTIONS for backward compatibility\nexport const GL_TRANSITION_OPTIONS = getTransitionOptions();\n","import transitions from \"gl-transitions\";\nimport { Filter, GlProgram, Sprite, Texture, ImageSource, RenderTexture } from \"pixi.js\";\n\nimport { vertex } from \"./vertex\";\nimport { uniforms } from \"./uniforms\";\nimport { fragment } from \"./fragment\";\n\nimport { getAllTransitions } from \"./glsl/gl-transition\";\nimport type { GLTransition, TransitionOptions, TransitionRendererOptions } from \"./types\";\nimport {\n BOW_TIE_HORIZONTAL_FRAGMENT,\n CANNABISLEAF_FRAGMENT,\n CANNABISLEAF_UNIFORMS,\n CIRCLE_FRAGMENT,\n CIRCLEOPEN_FRAGMENT,\n CIRCLEOPEN_UNIFORMS,\n CRAZY_PARAMETRIC_FUN_FRAGMENT,\n CRAZY_PARAMETRIC_FUN_UNIFORMS,\n CROSSHATCH_FRAGMENT,\n CROSSHATCH_UNIFORMS,\n CROSSZOOM_FRAGMENT,\n CROSSZOOM_UNIFORMS,\n DIRECTIONAL_FRAGMENT,\n DIRECTIONAL_UNIFORMS,\n DIRECTIONALWARP_FRAGMENT,\n DIRECTIONALWARP_UNIFORMS,\n DIRECTIONALWIPE_FRAGMENT,\n DIRECTIONALWIPE_UNIFORMS,\n DISPLACEMENT_FRAGMENT,\n DISPLACEMENT_UNIFORMS,\n GLITCH_DISPLACE_FRAGMENT,\n GRIDFLIP_FRAGMENT,\n GRIDFLIP_UNIFORMS,\n HEART_FRAGMENT,\n HEART_UNIFORMS,\n HEXAGONALIZE_FRAGMENT,\n HEXAGONALIZE_UNIFORMS,\n LUMA_FRAGMENT,\n LUMA_UNIFORMS,\n LUMINANCE_MELT_FRAGMENT,\n LUMINANCE_MELT_UNIFORMS,\n PERLIN_FRAGMENT,\n PERLIN_UNIFORMS,\n PIXELIZE_FRAGMENT,\n PIXELIZE_UNIFORMS,\n POLAR_FUNCTION_FRAGMENT,\n POLAR_FUNCTION_UNIFORMS,\n POLKA_DOTS_CURTAIN_FRAGMENT,\n RANDOMSQUARES_FRAGMENT,\n RANDOMSQUARES_UNIFORMS,\n ROTATE_SCALE_FADE_FRAGMENT,\n ROTATE_SCALE_FADE_UNIFORMS,\n SQUARESWIRE_FRAGMENT,\n SQUARESWIRE_UNIFORMS,\n STEREOVIEWER_FRAGMENT,\n STEREOVIEWER_UNIFORMS,\n UNDULATING_BURN_OUT_FRAGMENT,\n UNDULATING_BURN_OUT_UNIFORMS,\n} from \"./glsl/custom-glsl\";\nimport { PIXELATE_FRAGMENT, PIXELATE_UNIFORMS } from \"../effect/glsl/custom-glsl\";\n\nexport function makeTransition({ name, renderer }: TransitionOptions) {\n let transition: GLTransition | undefined = transitions.find((t: GLTransition) => t.name === name);\n\n if (!transition) {\n const allLocal = getAllTransitions();\n const localKey = Object.keys(allLocal).find((key) => key.toLowerCase() === name.toLowerCase());\n if (localKey) {\n transition = allLocal[localKey] as unknown as GLTransition;\n }\n }\n\n if (!transition) {\n transition = transitions.find((t: GLTransition) => t.name.toLowerCase() === name.toLowerCase());\n }\n\n if (!transition) {\n const variants = [\n name,\n name.toLowerCase(),\n name.charAt(0).toUpperCase() + name.slice(1).toLowerCase(),\n name\n .replace(/([A-Z])/g, \"_$1\")\n .toLowerCase()\n .replace(/^_/, \"\"),\n name.replace(/_/g, \"\"),\n ];\n\n const allLocal = getAllTransitions();\n for (const variant of variants) {\n transition = transitions.find(\n (t: GLTransition) => t.name.toLowerCase() === variant.toLowerCase(),\n );\n if (transition) break;\n\n // Also check local definitions with variants\n const localKey = Object.keys(allLocal).find(\n (key) => key.toLowerCase() === variant.toLowerCase(),\n );\n if (localKey) {\n transition = allLocal[localKey] as unknown as GLTransition;\n break;\n }\n }\n }\n\n if (!transition) {\n const availableCount = transitions.length;\n const availableNames = transitions\n .slice(0, 5)\n .map((t: GLTransition) => t.name)\n .join(\", \");\n const allLocal = getAllTransitions();\n const localNames = Object.keys(allLocal).slice(0, 3).join(\", \");\n console.error(\n `Transition not found: \"${name}\". Available in gl-transitions (${availableCount} total):`,\n availableNames + \"...\",\n );\n\n console.error(`Available locally:`, localNames + \"...\");\n throw new Error(\n `Transition \"${name}\" not found in gl-transitions library or local definitions`,\n );\n }\n\n const transitionSprite = new Sprite(Texture.WHITE);\n const transitionTexture = RenderTexture.create({\n width: renderer.width,\n height: renderer.height,\n });\n const sourceFrom = new ImageSource({});\n const sourceTo = new ImageSource({});\n const isDisplacementTransition =\n transition.name === \"displacement\" ||\n name.toLowerCase() === \"displacement\" ||\n transition.label === \"displacement\";\n\n const sourceDisplacement = isDisplacementTransition ? new ImageSource({}) : undefined;\n let defaultDisplacementTexture: HTMLCanvasElement | null = null;\n\n if (isDisplacementTransition) {\n defaultDisplacementTexture = document.createElement(\"canvas\");\n defaultDisplacementTexture.width = 256;\n defaultDisplacementTexture.height = 256;\n const ctx = defaultDisplacementTexture.getContext(\"2d\");\n if (ctx) {\n const imageData = ctx.createImageData(256, 256);\n for (let i = 0; i < imageData.data.length; i += 4) {\n const noise = Math.random();\n imageData.data[i] = noise * 255; // R\n imageData.data[i + 1] = noise * 255; // G\n imageData.data[i + 2] = noise * 255; // B\n imageData.data[i + 3] = 255; // A\n }\n ctx.putImageData(imageData, 0, 0);\n }\n }\n\n let transitionGlsl = transition.glsl || transition.fragment;\n\n if (!transitionGlsl) {\n throw new Error(`Transition \"${name}\" has no glsl or fragment code`);\n }\n\n let transitionUniforms: Record<string, { value: any; type: string }> = {\n ...uniforms.basics,\n ...uniforms.custom(transition),\n };\n\n Object.entries(transitionUniforms).forEach(([, uniform]) => {\n if (uniform.type === \"int<f32>\") {\n uniform.type = \"i32\";\n\n if (typeof uniform.value === \"number\") {\n uniform.value = Math.trunc(uniform.value);\n }\n }\n if (uniform.type === \"ivec2<f32>\") {\n uniform.type = \"vec2<f32>\";\n }\n });\n\n const transitionGridFlip =\n transition.name === \"GridFlip\" ||\n name.toLowerCase() === \"gridflip\" ||\n transition.label === \"gridflip\";\n\n const transitionCircle =\n transition.name === \"circle\" ||\n name.toLowerCase() === \"circle\" ||\n transition.label === \"circle\";\n\n const transitionDirectional =\n transition.name === \"directional\" ||\n name.toLowerCase() === \"directional\" ||\n transition.label === \"directional\";\n\n const transitionUndulatingBurnOut =\n transition.name === \"UndulatingBurnOut\" ||\n name.toLowerCase() === \"undulatingburnout\" ||\n transition.label === \"undulatingBurnOut\";\n\n const transitionSquaresWire =\n transition.name === \"SquaresWire\" ||\n name.toLowerCase() === \"squareswire\" ||\n transition.label === \"squaresWire\";\n\n const transitionRotateScaleFade =\n transition.name === \"rotate_scale_fade\" ||\n name.toLowerCase() === \"rotatescalefade\" ||\n transition.label === \"rotateScaleFade\";\n\n const transitionRandomSquares =\n transition.name === \"RandomSquares\" ||\n name.toLowerCase() === \"randomsquares\" ||\n transition.label === \"randomSquares\";\n\n const transitionPolarFunction =\n transition.name === \"polar_function\" ||\n name.toLowerCase() === \"polar_function\" ||\n transition.label === \"polar_function\";\n\n const transitionPixelate =\n transition.name === \"pixelate\" ||\n name.toLowerCase() === \"pixelate\" ||\n transition.label === \"pixelate\";\n\n const transitionPerlin =\n transition.name === \"perlin\" ||\n name.toLowerCase() === \"perlin\" ||\n transition.label === \"perlin\";\n\n const transitionLuma =\n transition.name === \"luma\" || name.toLowerCase() === \"luma\" || transition.label === \"luma\";\n\n const transitionLuminanceMelt =\n transition.name === \"luminance_melt\" ||\n name.toLowerCase() === \"luminance_melt\" ||\n name.toLowerCase() === \"luminancemelt\" ||\n transition.label === \"luminance_melt\";\n\n const transitionHexagonalize =\n transition.name === \"hexagonalize\" ||\n name.toLowerCase() === \"hexagonalize\" ||\n transition.label === \"hexagonalize\";\n\n const transitionHeart =\n transition.name === \"heart\" || name.toLowerCase() === \"heart\" || transition.label === \"heart\";\n\n const transitionDisplacement =\n transition.name === \"displacement\" ||\n name.toLowerCase() === \"displacement\" ||\n transition.label === \"displacement\";\n\n const transitionDirectionalWipe =\n transition.name === \"directionalwipe\" ||\n name.toLowerCase() === \"directionalwipe\" ||\n name.toLowerCase() === \"directional_wipe\" ||\n transition.label === \"directionalwipe\";\n\n const transitionDirectionalWarp =\n transition.name === \"directionalwarp\" ||\n name.toLowerCase() === \"directionalwarp\" ||\n name.toLowerCase() === \"directional_warp\" ||\n transition.label === \"directionalwarp\";\n\n const transitionCrosshatch =\n transition.name === \"crosshatch\" ||\n name.toLowerCase() === \"crosshatch\" ||\n transition.label === \"crosshatch\";\n\n const transitionCircleOpen =\n transition.name === \"circleopen\" ||\n name.toLowerCase() === \"circleopen\" ||\n name.toLowerCase() === \"circle_open\" ||\n transition.label === \"circleopen\";\n\n const transitionCannabisLeaf =\n transition.name === \"cannabisleaf\" ||\n name.toLowerCase() === \"cannabisleaf\" ||\n name.toLowerCase() === \"cannabis_leaf\" ||\n transition.label === \"cannabisleaf\";\n\n const transitionStereoViewer =\n transition.name === \"StereoViewer\" ||\n name.toLowerCase() === \"stereoviewer\" ||\n name.toLowerCase() === \"stereo_viewer\" ||\n transition.label === \"StereoViewer\";\n\n const transitionGlitchDisplace =\n transition.name === \"GlitchDisplace\" ||\n name.toLowerCase() === \"glitchDisplace\" ||\n transition.label === \"GlitchDisplace\";\n\n const transitionCrossZoom =\n transition.name === \"CrossZoom\" ||\n name.toLowerCase() === \"crosszoom\" ||\n transition.label === \"CrossZoom\";\n\n const transitionCrazyParametricFun =\n transition.name === \"CrazyParametricFun\" ||\n name.toLowerCase() === \"crazyparametricfun\" ||\n transition.label === \"CrazyParametricFun\";\n\n const transitionBowTieHorizontal =\n transition.name === \"BowTieHorizontal\" ||\n name.toLowerCase() === \"bowtiehorizontal\" ||\n transition.label === \"BowTieHorizontal\";\n\n const transitionPolkaDotsCurtain =\n transition.name === \"PolkaDotsCurtain\" ||\n name.toLowerCase() === \"polkadotscurtain\" ||\n transition.label === \"PolkaDotsCurtain\";\n\n const transitionPixelize =\n transition.name === \"Pixelize\" ||\n name.toLowerCase() === \"pixelize\" ||\n transition.label === \"Pixelize\";\n\n if (transitionGridFlip) {\n transitionGlsl = GRIDFLIP_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...GRIDFLIP_UNIFORMS,\n };\n }\n\n if (transitionCircle) {\n transitionGlsl = CIRCLE_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...CIRCLEOPEN_UNIFORMS,\n };\n }\n if (transitionDirectional) {\n transitionGlsl = DIRECTIONAL_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...DIRECTIONAL_UNIFORMS,\n };\n }\n if (transitionUndulatingBurnOut) {\n transitionGlsl = UNDULATING_BURN_OUT_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...UNDULATING_BURN_OUT_UNIFORMS,\n };\n }\n if (transitionSquaresWire) {\n transitionGlsl = SQUARESWIRE_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...SQUARESWIRE_UNIFORMS,\n };\n }\n if (transitionRotateScaleFade) {\n transitionGlsl = ROTATE_SCALE_FADE_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...ROTATE_SCALE_FADE_UNIFORMS,\n };\n }\n if (transitionRandomSquares) {\n transitionGlsl = RANDOMSQUARES_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...RANDOMSQUARES_UNIFORMS,\n };\n }\n if (transitionPolarFunction) {\n transitionGlsl = POLAR_FUNCTION_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...POLAR_FUNCTION_UNIFORMS,\n };\n }\n\n if (transitionPixelate) {\n transitionGlsl = PIXELATE_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...PIXELATE_UNIFORMS,\n };\n }\n\n if (transitionPerlin) {\n transitionGlsl = PERLIN_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...PERLIN_UNIFORMS,\n };\n }\n\n if (transitionLuma) {\n transitionGlsl = LUMA_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...LUMA_UNIFORMS,\n };\n }\n\n if (transitionLuminanceMelt) {\n transitionGlsl = LUMINANCE_MELT_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...LUMINANCE_MELT_UNIFORMS,\n };\n }\n\n if (transitionHexagonalize) {\n transitionGlsl = HEXAGONALIZE_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...HEXAGONALIZE_UNIFORMS,\n };\n }\n\n if (transitionHeart) {\n transitionGlsl = HEART_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...HEART_UNIFORMS,\n };\n }\n\n if (transitionDisplacement) {\n transitionGlsl = DISPLACEMENT_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...DISPLACEMENT_UNIFORMS,\n };\n }\n\n if (transitionDirectionalWipe) {\n transitionGlsl = DIRECTIONALWIPE_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...DIRECTIONALWIPE_UNIFORMS,\n };\n }\n\n if (transitionDirectionalWarp) {\n transitionGlsl = DIRECTIONALWARP_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...DIRECTIONALWARP_UNIFORMS,\n };\n }\n\n if (transitionCrosshatch) {\n transitionGlsl = CROSSHATCH_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...CROSSHATCH_UNIFORMS,\n };\n }\n\n if (transitionCircleOpen) {\n transitionGlsl = CIRCLEOPEN_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...CIRCLEOPEN_UNIFORMS,\n };\n }\n\n if (transitionCannabisLeaf) {\n transitionGlsl = CANNABISLEAF_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...CANNABISLEAF_UNIFORMS,\n };\n }\n\n if (transitionStereoViewer) {\n transitionGlsl = STEREOVIEWER_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...STEREOVIEWER_UNIFORMS,\n };\n }\n\n if (transitionGlitchDisplace) {\n transitionGlsl = GLITCH_DISPLACE_FRAGMENT;\n }\n\n if (transitionCrossZoom) {\n transitionGlsl = CROSSZOOM_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...CROSSZOOM_UNIFORMS,\n };\n }\n\n if (transitionCrazyParametricFun) {\n transitionGlsl = CRAZY_PARAMETRIC_FUN_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...CRAZY_PARAMETRIC_FUN_UNIFORMS,\n };\n }\n if (transitionBowTieHorizontal) {\n transitionGlsl = BOW_TIE_HORIZONTAL_FRAGMENT;\n }\n if (transitionPolkaDotsCurtain) {\n transitionGlsl = POLKA_DOTS_CURTAIN_FRAGMENT;\n }\n if (transitionPixelize) {\n transitionGlsl = PIXELIZE_FRAGMENT;\n transitionUniforms = {\n ...uniforms.basics,\n ...PIXELIZE_UNIFORMS,\n };\n }\n // Prepare resources\n const filterResources: any = {\n from: sourceFrom,\n to: sourceTo,\n uniforms: transitionUniforms,\n };\n\n // Add displacement map texture as resource for displacement transition\n if (isDisplacementTransition && sourceDisplacement) {\n filterResources.displacementMap = sourceDisplacement;\n // Set default displacement texture\n if (defaultDisplacementTexture) {\n sourceDisplacement.resource = defaultDisplacementTexture;\n sourceDisplacement.update();\n }\n }\n\n const filter = new Filter({\n glProgram: new GlProgram({\n vertex,\n fragment: fragment(transitionGlsl),\n }),\n resources: filterResources,\n });\n\n transitionSprite.filters = [filter];\n\n return {\n render({ width, height, from, to, progress, values }: TransitionRendererOptions) {\n if (transitionSprite.width !== width || transitionSprite.height !== height) {\n transitionSprite.setSize({ width, height });\n transitionTexture.resize(width, height);\n }\n\n if (values) {\n const shaderUniforms = filter.resources.uniforms.uniforms;\n for (const [key, value] of Object.entries(values)) {\n if (key !== \"progress\" && shaderUniforms[key] !== undefined) shaderUniforms[key] = value;\n }\n }\n\n if (from instanceof Texture) {\n filter.resources.from = from.source;\n } else {\n sourceFrom.resource = from;\n sourceFrom.update();\n filter.resources.from = sourceFrom;\n }\n\n if (to instanceof Texture) {\n filter.resources.to = to.source;\n } else {\n sourceTo.resource = to;\n sourceTo.update();\n filter.resources.to = sourceTo;\n }\n\n // Update displacement texture if it exists (resize default texture if needed)\n if (isDisplacementTransition && sourceDisplacement && defaultDisplacementTexture) {\n if (\n defaultDisplacementTexture.width !== width ||\n defaultDisplacementTexture.height !== height\n ) {\n defaultDisplacementTexture.width = width;\n defaultDisplacementTexture.height = height;\n const ctx = defaultDisplacementTexture.getContext(\"2d\");\n if (ctx) {\n // Create a simple noise pattern for displacement\n const imageData = ctx.createImageData(width, height);\n for (let i = 0; i < imageData.data.length; i += 4) {\n const noise = Math.random();\n imageData.data[i] = noise * 255; // R\n imageData.data[i + 1] = noise * 255; // G\n imageData.data[i + 2] = noise * 255; // B\n imageData.data[i + 3] = 255; // A\n }\n ctx.putImageData(imageData, 0, 0);\n }\n }\n sourceDisplacement.resource = defaultDisplacementTexture;\n sourceDisplacement.update();\n }\n\n filter.resources.uniforms.uniforms.progress = progress;\n\n renderer.render({\n container: transitionSprite,\n target: transitionTexture,\n clear: true,\n width,\n height,\n });\n\n return transitionTexture;\n },\n destroy() {\n transitionTexture.destroy();\n transitionSprite.destroy({ children: true });\n },\n };\n}\n","import {\n Container,\n Sprite,\n Texture,\n Graphics,\n BlurFilter,\n ColorMatrixFilter,\n UniformGroup,\n Filter,\n GlProgram,\n} from \"pixi.js\";\nimport { type IClip } from \"../clips\";\nimport { parseColor, hexToRgb } from \"../utils/color\";\nimport { vertex } from \"../effect/vertex\";\nimport { CHROMA_KEY_FRAGMENT, SELECTIVE_HSL_FRAGMENT } from \"../effect/glsl/custom-glsl\";\nimport {\n applyColorAdjustmentToMatrix,\n getAllSelectiveHsl,\n hasColorAdjustment,\n} from \"../utils/color-adjustment\";\n\nexport interface IPooledClipObjects {\n root: Container;\n mainSprite: Sprite;\n mirrors: Sprite[];\n maskGfx: Graphics | null;\n strokeGfx: Graphics | null;\n shadowGfx: Graphics | null;\n}\n\n/**\n * Applies layout transforms, mirrors, filters (blur, adjustments, chroma, hsl), and decoration styles\n * (border radius, strokes, drop shadows) to a set of PixiJS containers and sprites representing a clip.\n */\nexport function applyClipStylesAndFilters(opts: {\n clip: IClip;\n tex: Texture;\n rootContainer: Container;\n tempSprite: Sprite;\n pooled: IPooledClipObjects;\n scaleX: number;\n scaleY: number;\n}): void {\n const { clip, tex, rootContainer, tempSprite, pooled, scaleX, scaleY } = opts;\n\n const style = (clip as any).style || {};\n const { renderTransform } = clip;\n const isMirrored = (renderTransform?.mirror ?? 0) > 0.5;\n\n const xOffset = renderTransform?.x ?? 0;\n const yOffset = renderTransform?.y ?? 0;\n const angleOffset = renderTransform?.angle ?? 0;\n const scaleMultiplier = renderTransform?.scale ?? 1;\n const scaleXMultiplier = renderTransform?.scaleX ?? 1;\n const scaleYMultiplier = renderTransform?.scaleY ?? 1;\n const opacityMultiplier = renderTransform?.opacity ?? 1;\n const blurOffset = renderTransform?.blur ?? 0;\n const brightnessMultiplier = renderTransform?.brightness ?? 1;\n\n const textureWidth = tex.width || 1;\n const textureHeight = tex.height || 1;\n\n const isCaption = (clip as any).type === \"Caption\";\n\n const baseScaleX =\n !isCaption && clip.width && clip.width !== 0 ? Math.abs(clip.width) / textureWidth : 1;\n const baseScaleY =\n !isCaption && clip.height && clip.height !== 0 ? Math.abs(clip.height) / textureHeight : 1;\n\n // Multiply by export scale so the sprite fills the correct fraction of the\n // full-resolution render target (the rootContainer has no parent container scale).\n const combinedScaleX = baseScaleX * scaleMultiplier * scaleXMultiplier * scaleX;\n const combinedScaleY = baseScaleY * scaleMultiplier * scaleYMultiplier * scaleY;\n\n // Scale positions from original project dimensions to export dimensions\n rootContainer.x = (clip.center.x + xOffset) * scaleX;\n rootContainer.y = (clip.center.y + yOffset) * scaleY;\n rootContainer.rotation =\n ((clip.flip == null ? 1 : -1) * ((clip.angle + angleOffset) * Math.PI)) / 180;\n rootContainer.alpha = clip.opacity * opacityMultiplier;\n\n tempSprite.texture = tex;\n\n if (isMirrored) {\n const sX = combinedScaleX;\n const sY = combinedScaleY;\n const scaledW = textureWidth * sX;\n const scaledH = textureHeight * sY;\n\n tempSprite.position.set(0, 0);\n tempSprite.scale.set(sX, sY);\n\n const mirrorLayout: [number, number, number, number][] = [\n [scaledW, 0, -sX, sY],\n [-scaledW, 0, -sX, sY],\n [0, scaledH, sX, -sY],\n [0, -scaledH, sX, -sY],\n [scaledW, scaledH, -sX, -sY],\n [-scaledW, scaledH, -sX, -sY],\n [scaledW, -scaledH, -sX, -sY],\n [-scaledW, -scaledH, -sX, -sY],\n ];\n\n // Ensure we have 8 mirror sprites (create on first use, reuse after)\n while (pooled.mirrors.length < 8) {\n const ms = new Sprite();\n ms.anchor.set(0.5, 0.5);\n rootContainer.addChild(ms);\n pooled.mirrors.push(ms);\n }\n\n for (let i = 0; i < 8; i++) {\n const [dx, dy, sx, sy] = mirrorLayout[i];\n const ms = pooled.mirrors[i];\n ms.texture = tex;\n ms.visible = true;\n ms.position.set(dx, dy);\n ms.scale.set(sx, sy);\n }\n\n if (clip.flip?.x) {\n tempSprite.scale.x = -sX;\n for (let i = 0; i < 8; i++) {\n pooled.mirrors[i].scale.x = -mirrorLayout[i][2];\n }\n }\n if (clip.flip?.y) {\n tempSprite.scale.y = -sY;\n for (let i = 0; i < 8; i++) {\n pooled.mirrors[i].scale.y = -mirrorLayout[i][3];\n }\n }\n } else {\n // Hide mirror sprites if they exist\n for (const ms of pooled.mirrors) ms.visible = false;\n\n if (clip.flip?.x) {\n tempSprite.scale.x = -combinedScaleX;\n tempSprite.scale.y = combinedScaleY;\n } else if (clip.flip?.y) {\n tempSprite.scale.x = combinedScaleX;\n tempSprite.scale.y = -combinedScaleY;\n } else {\n tempSprite.scale.x = combinedScaleX;\n tempSprite.scale.y = combinedScaleY;\n }\n }\n\n // Apply Filters\n const filters: any[] = [];\n if (blurOffset > 0) {\n const blurFilter = new BlurFilter();\n blurFilter.strength = blurOffset;\n blurFilter.quality = 4;\n (blurFilter as any).repeatEdgePixels = true;\n filters.push(blurFilter);\n }\n\n const hasClipColorAdjustment = hasColorAdjustment((clip as any).colorAdjustment);\n if (brightnessMultiplier !== 1 || hasClipColorAdjustment) {\n const brightnessFilter = new ColorMatrixFilter();\n applyColorAdjustmentToMatrix(\n brightnessFilter,\n (clip as any).colorAdjustment,\n brightnessMultiplier,\n );\n filters.push(brightnessFilter);\n }\n\n const activeSelectiveHslList = getAllSelectiveHsl((clip as any).colorAdjustment);\n for (let i = 0; i < activeSelectiveHslList.length; i++) {\n const activeSelectiveHsl = activeSelectiveHslList[i];\n const hslUniforms = new UniformGroup({\n uTargetColor: { value: [1, 1, 0], type: \"vec3<f32>\" },\n uHueShift: { value: activeSelectiveHsl.hue, type: \"f32\" },\n uSatShift: { value: activeSelectiveHsl.saturation / 100, type: \"f32\" },\n uLightShift: { value: activeSelectiveHsl.lightness / 100, type: \"f32\" },\n uTolerance: { value: 0.22, type: \"f32\" },\n uSoftness: { value: 0.12, type: \"f32\" },\n });\n const rgb = hexToRgb(activeSelectiveHsl.targetColor);\n if (rgb) {\n hslUniforms.uniforms.uTargetColor[0] = rgb.r / 255;\n hslUniforms.uniforms.uTargetColor[1] = rgb.g / 255;\n hslUniforms.uniforms.uTargetColor[2] = rgb.b / 255;\n }\n const selectiveHslFilter = new Filter({\n glProgram: new GlProgram({\n vertex,\n fragment: SELECTIVE_HSL_FRAGMENT,\n name: `SelectiveHslShader_${i}`,\n }),\n resources: { hslUniforms },\n });\n filters.push(selectiveHslFilter);\n }\n\n if (clip.chromaKey && clip.chromaKey.enabled) {\n const chromaUniforms = new UniformGroup({\n uKeyColor: { value: [0, 1, 0], type: \"vec3<f32>\" },\n uSimilarity: { value: 0.1, type: \"f32\" },\n uSpill: { value: 0.0, type: \"f32\" },\n });\n\n const rgb = hexToRgb(clip.chromaKey.color);\n if (rgb) {\n chromaUniforms.uniforms.uKeyColor[0] = rgb.r / 255;\n chromaUniforms.uniforms.uKeyColor[1] = rgb.g / 255;\n chromaUniforms.uniforms.uKeyColor[2] = rgb.b / 255;\n }\n chromaUniforms.uniforms.uSimilarity = clip.chromaKey.similarity;\n chromaUniforms.uniforms.uSpill = clip.chromaKey.spill;\n\n const chromaFilter = new Filter({\n glProgram: new GlProgram({\n vertex,\n fragment: CHROMA_KEY_FRAGMENT,\n name: \"ChromaKeyShader\",\n }),\n resources: {\n chromaUniforms,\n },\n });\n filters.push(chromaFilter);\n }\n\n rootContainer.filters = filters;\n\n // Apply Styles (Border Radius, Stroke, Shadow)\n const borderRadius = style.borderRadius || 0;\n if (borderRadius > 0) {\n if (pooled.maskGfx == null) {\n pooled.maskGfx = new Graphics();\n tempSprite.addChild(pooled.maskGfx);\n }\n pooled.maskGfx.clear();\n pooled.maskGfx.roundRect(\n -textureWidth / 2,\n -textureHeight / 2,\n textureWidth,\n textureHeight,\n Math.min(borderRadius, textureWidth / 2, textureHeight / 2),\n );\n pooled.maskGfx.fill({ color: 0xffffff, alpha: 1 });\n\n // Force mask update by resetting the mask property\n tempSprite.mask = null;\n tempSprite.mask = pooled.maskGfx;\n } else if (pooled.maskGfx != null) {\n tempSprite.mask = null;\n }\n\n const stroke = style.stroke;\n if (stroke && stroke.width > 0) {\n if (pooled.strokeGfx == null) {\n pooled.strokeGfx = new Graphics();\n tempSprite.addChild(pooled.strokeGfx);\n }\n pooled.strokeGfx.clear();\n const color = parseColor(stroke.color) ?? 0xffffff;\n let alignment = 1;\n if (stroke.alignment !== undefined) {\n if (typeof stroke.alignment === \"number\") {\n alignment = stroke.alignment;\n } else if (stroke.alignment === \"center\" || stroke.alignment === \"middle\") {\n alignment = 0.5;\n } else if (stroke.alignment === \"inside\") {\n alignment = 0;\n } else if (stroke.alignment === \"outside\") {\n alignment = 1;\n }\n }\n pooled.strokeGfx.setStrokeStyle({\n width: stroke.width,\n color: color,\n alignment: alignment,\n });\n\n if (borderRadius > 0) {\n const r = Math.min(borderRadius, textureWidth / 2, textureHeight / 2);\n pooled.strokeGfx.roundRect(\n -textureWidth / 2,\n -textureHeight / 2,\n textureWidth,\n textureHeight,\n r,\n );\n } else {\n pooled.strokeGfx.rect(-textureWidth / 2, -textureHeight / 2, textureWidth, textureHeight);\n }\n pooled.strokeGfx.stroke();\n pooled.strokeGfx.visible = true;\n } else if (pooled.strokeGfx != null) {\n pooled.strokeGfx.visible = false;\n }\n\n const shadow = style.shadow;\n if (shadow && (shadow.blur > 0 || (shadow.offsetX ?? 0) !== 0 || (shadow.offsetY ?? 0) !== 0)) {\n if (pooled.shadowGfx == null) {\n pooled.shadowGfx = new Graphics();\n rootContainer.addChildAt(pooled.shadowGfx, 0);\n }\n pooled.shadowGfx.clear();\n const color = parseColor(shadow.color) ?? 0x000000;\n const alpha = shadow.alpha ?? 0.5;\n const dx = shadow.offsetX ?? 0;\n const dy = shadow.offsetY ?? 0;\n\n if (borderRadius > 0) {\n const r = Math.min(borderRadius, textureWidth / 2, textureHeight / 2);\n pooled.shadowGfx.roundRect(\n -textureWidth / 2 + dx,\n -textureHeight / 2 + dy,\n textureWidth,\n textureHeight,\n r,\n );\n } else {\n pooled.shadowGfx.rect(\n -textureWidth / 2 + dx,\n -textureHeight / 2 + dy,\n textureWidth,\n textureHeight,\n );\n }\n pooled.shadowGfx.fill({ color, alpha });\n pooled.shadowGfx.visible = true;\n } else if (pooled.shadowGfx != null) {\n pooled.shadowGfx.visible = false;\n }\n}\n","import { Application, Container, RenderTexture, Sprite, Graphics, Texture } from \"pixi.js\";\nimport { type IClip, Transition } from \"../clips\";\nimport { makeTransition } from \"../transition/transition\";\nimport { applyClipStylesAndFilters, type IPooledClipObjects } from \"./clip-style-renderer\";\n\nexport class TransitionManager {\n private pixiApp: Application;\n private scaleX: number;\n private scaleY: number;\n\n private transitionRenderers = new Map<string, ReturnType<typeof makeTransition>>();\n private transitionSprites = new Map<string, Sprite>();\n private transFromTexture: RenderTexture;\n private transToTexture: RenderTexture;\n private transBgGraphics: Graphics;\n\n // Pooled scene objects for renderClipToTransitionTexture, keyed by clip ID.\n // Avoids creating+destroying Container/Sprite/Graphics on every frame during transitions.\n private transClipPool = new Map<string, IPooledClipObjects>();\n\n constructor(pixiApp: Application, scaleX: number, scaleY: number) {\n this.pixiApp = pixiApp;\n this.scaleX = scaleX;\n this.scaleY = scaleY;\n\n this.transFromTexture = RenderTexture.create({\n width: pixiApp.renderer.width,\n height: pixiApp.renderer.height,\n });\n this.transToTexture = RenderTexture.create({\n width: pixiApp.renderer.width,\n height: pixiApp.renderer.height,\n });\n\n this.transBgGraphics = new Graphics()\n .rect(0, 0, pixiApp.renderer.width / scaleX, pixiApp.renderer.height / scaleY)\n .fill({ color: 0x000000 });\n }\n\n /**\n * Reset the visibility of all transition sprites at the start of a frame.\n */\n public resetFrame(): void {\n for (const sprite of this.transitionSprites.values()) {\n sprite.visible = false;\n }\n }\n\n /**\n * Checks if a transition sprite has been created for a given ID.\n */\n public getTransitionSprite(id: string): Sprite | undefined {\n return this.transitionSprites.get(id);\n }\n\n /**\n * Retrieve pool container/sprite elements for a given clip to avoid allocations.\n */\n private getTransClipObjects(clipId: string): IPooledClipObjects {\n let entry = this.transClipPool.get(clipId);\n if (entry == null) {\n const root = new Container();\n const mainSprite = new Sprite();\n mainSprite.anchor.set(0.5, 0.5);\n root.addChild(mainSprite);\n entry = {\n root,\n mainSprite,\n mirrors: [],\n maskGfx: null,\n strokeGfx: null,\n shadowGfx: null,\n };\n this.transClipPool.set(clipId, entry);\n }\n return entry;\n }\n\n private async getClipFrameAtTimestamp(\n clip: IClip,\n timestamp: number,\n getFrameCached: (clip: IClip, timestamp: number) => Promise<any>,\n ): Promise<any> {\n const relTime = Math.max(0, Math.min(timestamp - clip.display.from, clip.duration));\n // Ensure animation state is updated for the sampled timestamp\n clip.animate(relTime * clip.playbackRate);\n\n const { video } = await getFrameCached(clip, relTime);\n return video;\n }\n\n private renderClipToTransitionTexture(\n clip: IClip,\n frame: VideoFrame | ImageBitmap | Texture,\n target: RenderTexture,\n ): void {\n const isFrameTexture = frame instanceof Texture;\n const tex = isFrameTexture ? frame : Texture.from(frame as any);\n\n const pooled = this.getTransClipObjects(clip.id);\n const { root: rootContainer, mainSprite: tempSprite } = pooled;\n\n applyClipStylesAndFilters({\n clip,\n tex,\n rootContainer,\n tempSprite,\n pooled,\n scaleX: this.scaleX,\n scaleY: this.scaleY,\n });\n\n this.pixiApp.renderer.render({\n container: rootContainer,\n target: target,\n clear: true,\n });\n\n if (!isFrameTexture) {\n tex.destroy(true);\n }\n }\n\n /**\n * Render transition between two clips at a given timeline timestamp.\n * Modifies target claimed set and updates internal transition sprite.\n */\n public async renderTransition(opts: {\n sprite: Transition & { expired?: boolean };\n timestamp: number;\n fromClip: IClip;\n toClip: IClip;\n getFrameCached: (clip: IClip, timestamp: number) => Promise<any>;\n clipsNormalContainer: Container;\n clipsClaimedByTransition: Set<string>;\n onVideoState: () => void;\n }): Promise<boolean> {\n const {\n sprite,\n timestamp,\n fromClip,\n toClip,\n getFrameCached,\n clipsNormalContainer,\n clipsClaimedByTransition,\n onVideoState,\n } = opts;\n\n const relativeTime = timestamp - sprite.display.from;\n\n if (relativeTime >= sprite.duration) {\n sprite.expired = true;\n const transSprite = this.transitionSprites.get(sprite.id);\n if (transSprite) {\n transSprite.visible = false;\n }\n return false;\n }\n\n const fromFrame = await this.getClipFrameAtTimestamp(fromClip, timestamp, getFrameCached);\n const toFrame = await this.getClipFrameAtTimestamp(toClip, timestamp, getFrameCached);\n\n if (!fromFrame || !toFrame) {\n return false;\n }\n\n const progress = Math.min(Math.max(relativeTime / sprite.duration, 0), 1);\n\n this.renderClipToTransitionTexture(fromClip, fromFrame, this.transFromTexture);\n this.renderClipToTransitionTexture(toClip, toFrame, this.transToTexture);\n\n let transRenderer = this.transitionRenderers.get(sprite.id);\n if (!transRenderer) {\n transRenderer = makeTransition({\n name: sprite.transitionKey,\n renderer: this.pixiApp.renderer,\n });\n this.transitionRenderers.set(sprite.id, transRenderer);\n }\n\n const transTexture = transRenderer.render({\n width: this.pixiApp.renderer.width,\n height: this.pixiApp.renderer.height,\n from: this.transFromTexture,\n to: this.transToTexture,\n progress,\n values: sprite.values,\n });\n\n let transSprite = this.transitionSprites.get(sprite.id);\n if (!transSprite) {\n transSprite = new Sprite();\n transSprite.label = `TransitionSprite_${sprite.id}`;\n this.transitionSprites.set(sprite.id, transSprite);\n clipsNormalContainer.addChild(transSprite);\n }\n\n // Size the sprite in project-space units because clipsNormalContainer has\n // scale.set(scaleX, scaleY) applied — dividing undoes the double-scaling.\n const projectW = this.pixiApp.renderer.width / this.scaleX;\n const projectH = this.pixiApp.renderer.height / this.scaleY;\n\n transSprite.texture = transTexture;\n transSprite.visible = true;\n transSprite.x = 0;\n transSprite.y = 0;\n transSprite.width = projectW;\n transSprite.height = projectH;\n transSprite.anchor.set(0, 0);\n transSprite.zIndex = sprite.zIndex;\n\n onVideoState();\n\n clipsClaimedByTransition.add(fromClip.id);\n clipsClaimedByTransition.add(toClip.id);\n\n return true;\n }\n\n public cleanup(): void {\n if (this.transFromTexture) this.transFromTexture.destroy(true);\n if (this.transToTexture) this.transToTexture.destroy(true);\n if (this.transBgGraphics) this.transBgGraphics.destroy(true);\n\n for (const sprite of this.transitionSprites.values()) {\n sprite.destroy();\n }\n this.transitionSprites.clear();\n this.transitionRenderers.clear();\n\n for (const entry of this.transClipPool.values()) {\n entry.root.destroy({ children: true });\n }\n this.transClipPool.clear();\n }\n}\n","//@ts-ignore\nimport {\n BLACK_FLASH_FRAGMENT,\n BLACK_FLASH_UNIFORMS,\n BLINK_FRAGMENT,\n BLINK_UNIFORMS,\n BRIGHT_PULSE_FRAGMENT,\n BRIGHT_PULSE_UNIFORMS,\n CAMERA_MOVE_FRAGMENT,\n CAMERA_MOVE_UNIFORMS,\n CHROMATIC_FRAGMENT,\n CHROMATIC_UNIFORMS,\n CURTAIN_BLUR_FRAGMENT,\n CURTAIN_BLUR_UNIFORMS,\n CURTAIN_OPEN_FRAGMENT,\n CURTAIN_OPEN_UNIFORMS,\n DISTORT_EFFECT_FRAGMENT,\n DISTORT_GRID_FRAGMENT,\n DISTORT_GRID_UNIFORMS,\n DISTORT_SPIN_FRAGMENT,\n DISTORT_SPIN_UNIFORMS,\n DISTORT_UNIFORMS,\n DISTORT_V2_FRAGMENT,\n DISTORT_V2_UNIFORMS,\n DUOTONE_FRAGMENT,\n DUOTONE_UNIFORMS,\n FAST_ZOOM_FRAGMENT,\n FAST_ZOOM_UNIFORMS,\n FILM_STRIP_PRO_FRAGMENT,\n FILM_STRIP_PRO_UNIFORMS,\n FLASH_LOOP_FRAGMENT,\n FLASH_LOOP_UNIFORMS,\n FOCUS_TRANSITION_FRAGMENT,\n FOCUS_TRANSITION_UNIFORMS,\n GLITCH_FRAGMENT,\n GLITCH_UNIFORMS,\n GRAYSCALE_FRAGMENT,\n GRAYSCALE_UNIFORMS,\n HALFTONE_FRAGMENT,\n HALFTONE_UNIFORMS,\n HDR_FRAGMENT,\n HDR_UNIFORMS,\n HDR_V2_FRAGMENT,\n HDR_V2_UNIFORMS,\n HUE_SHIFT_FRAGMENT,\n HUE_SHIFT_UNIFORMS,\n INVERSE_APERTURE_FRAGMENT,\n INVERSE_APERTURE_UNIFORMS,\n INVERT_FRAGMENT,\n INVERT_UNIFORMS,\n LASER_FRAGMENT,\n LASER_UNIFORMS,\n MIRROR_TILE_FRAGMENT,\n MIRROR_TILE_UNIFORMS,\n NEON_FLASH_FRAGMENT,\n NEON_FLASH_UNIFORMS,\n PAPER_BREAK_REVEAL_FRAGMENT,\n PAPER_BREAK_REVEAL_UNIFORMS,\n PERSPECTIVE_SINGLE_FRAGMENT,\n PERSPECTIVE_SINGLE_UNIFORMS,\n PIXELATE_FRAGMENT,\n PIXELATE_TRANSITION_FRAGMENT,\n PIXELATE_TRANSITION_UNIFORMS,\n PIXELATE_UNIFORMS,\n RGB_GLITCH_FRAGMENT,\n RGB_GLITCH_UNIFORMS,\n RGB_SHIFT_FRAGMENT,\n RGB_SHIFT_UNIFORMS,\n ROTATION_MOVEMENT_FRAGMENT,\n ROTATION_MOVEMENT_UNIFORMS,\n SCALE_MOVE_BLUR_FRAGMENT,\n SCALE_MOVE_BLUR_UNIFORMS,\n SEPIA_FRAGMENT,\n SEPIA_UNIFORMS,\n SHINE_FRAGMENT,\n SHINE_UNIFORMS,\n SINEWAVE_FRAGMENT,\n SINEWAVE_UNIFORMS,\n SLIT_SCAN_FRAGMENT,\n SLIT_SCAN_GLITCH_FRAGMENT,\n SLIT_SCAN_GLITCH_UNIFORMS,\n SLIT_SCAN_UNIFORMS,\n SPARKS_FRAGMENT,\n SPARKS_UNIFORMS,\n SPRING_FRAGMENT,\n SPRING_UNIFORMS,\n SWIRL_MOVEMENT_FRAGMENT,\n SWIRL_MOVEMENT_UNIFORMS,\n TRITONE_FRAGMENT,\n TRITONE_UNIFORMS,\n TV_SCANLINES_FRAGMENT,\n TV_SCANLINES_UNIFORMS,\n VIGNETTE_FRAGMENT,\n VIGNETTE_UNIFORMS,\n WARP_TRANSITION_FRAGMENT,\n WARP_TRANSITION_UNIFORMS,\n WAVE_DISTORT_FRAGMENT,\n WAVE_DISTORT_UNIFORMS,\n WAVE_FRAGMENT,\n WAVE_UNIFORMS,\n FADE_IN_FRAGMENT,\n FADE_IN_UNIFORMS,\n FADE_OUT_FRAGMENT,\n FADE_OUT_UNIFORMS,\n} from \"./custom-glsl\";\n\nexport interface GlEffect {\n label: string;\n fragment: string;\n uniforms?: Record<string, { value: any; type: string }>;\n previewStatic?: string;\n previewDynamic?: string;\n}\n\n// Registry for runtime custom effects\nconst REGISTERED_EFFECTS: Record<string, GlEffect> = {};\n\n/**\n * Register a custom effect at runtime\n */\nexport function registerCustomEffect(name: string, effect: GlEffect) {\n REGISTERED_EFFECTS[name] = effect;\n}\n\n/**\n * Unregister a custom effect at runtime\n */\nexport function unregisterCustomEffect(name: string) {\n delete REGISTERED_EFFECTS[name];\n}\n\nconst STATIC_EFFECTS = {\n rotationMovement: {\n label: \"Rotation Movement\",\n fragment: ROTATION_MOVEMENT_FRAGMENT,\n uniforms: ROTATION_MOVEMENT_UNIFORMS,\n },\n sepia: {\n label: \"Sepia\",\n fragment: SEPIA_FRAGMENT,\n uniforms: SEPIA_UNIFORMS,\n },\n glitch: {\n label: \"Glitch\",\n fragment: GLITCH_FRAGMENT,\n uniforms: GLITCH_UNIFORMS,\n },\n pixelate: {\n label: \"Pixelate\",\n fragment: PIXELATE_FRAGMENT,\n uniforms: PIXELATE_UNIFORMS,\n },\n rgbGlitch: {\n label: \"RGB Glitch\",\n fragment: RGB_GLITCH_FRAGMENT,\n uniforms: RGB_GLITCH_UNIFORMS,\n },\n rgbShift: {\n label: \"RGB Shift\",\n fragment: RGB_SHIFT_FRAGMENT,\n uniforms: RGB_SHIFT_UNIFORMS,\n },\n halftone: {\n label: \"Halftone\",\n fragment: HALFTONE_FRAGMENT,\n uniforms: HALFTONE_UNIFORMS,\n },\n sinewave: {\n label: \"Sinewave\",\n fragment: SINEWAVE_FRAGMENT,\n uniforms: SINEWAVE_UNIFORMS,\n },\n shine: {\n label: \"Shine\",\n fragment: SHINE_FRAGMENT,\n uniforms: SHINE_UNIFORMS,\n },\n blink: {\n label: \"Blink\",\n fragment: BLINK_FRAGMENT,\n uniforms: BLINK_UNIFORMS,\n },\n spring: {\n label: \"Spring\",\n fragment: SPRING_FRAGMENT,\n uniforms: SPRING_UNIFORMS,\n },\n duotone: {\n label: \"Duotone\",\n fragment: DUOTONE_FRAGMENT,\n uniforms: DUOTONE_UNIFORMS,\n },\n tritone: {\n label: \"Tritone\",\n fragment: TRITONE_FRAGMENT,\n uniforms: TRITONE_UNIFORMS,\n },\n hueShift: {\n label: \"Hue Shift\",\n fragment: HUE_SHIFT_FRAGMENT,\n uniforms: HUE_SHIFT_UNIFORMS,\n },\n warpTransition: {\n label: \"Warp Transition\",\n fragment: WARP_TRANSITION_FRAGMENT,\n uniforms: WARP_TRANSITION_UNIFORMS,\n },\n slitScan: {\n label: \"Slit Scan\",\n fragment: SLIT_SCAN_FRAGMENT,\n uniforms: SLIT_SCAN_UNIFORMS,\n },\n slitScanGlitch: {\n label: \"Slit Scan Glitch\",\n fragment: SLIT_SCAN_GLITCH_FRAGMENT,\n uniforms: SLIT_SCAN_GLITCH_UNIFORMS,\n },\n pixelateTransition: {\n label: \"Pixelate Transition\",\n fragment: PIXELATE_TRANSITION_FRAGMENT,\n uniforms: PIXELATE_TRANSITION_UNIFORMS,\n },\n focusTransition: {\n label: \"Focus Transition\",\n fragment: FOCUS_TRANSITION_FRAGMENT,\n uniforms: FOCUS_TRANSITION_UNIFORMS,\n },\n invert: {\n label: \"Invert\",\n fragment: INVERT_FRAGMENT,\n uniforms: INVERT_UNIFORMS,\n },\n grayscale: {\n label: \"Grayscale\",\n fragment: GRAYSCALE_FRAGMENT,\n uniforms: GRAYSCALE_UNIFORMS,\n },\n vignette: {\n label: \"Vignette\",\n fragment: VIGNETTE_FRAGMENT,\n uniforms: VIGNETTE_UNIFORMS,\n },\n chromatic: {\n label: \"Chromatic\",\n fragment: CHROMATIC_FRAGMENT,\n uniforms: CHROMATIC_UNIFORMS,\n },\n swirlMovement: {\n label: \"Swirl Movement\",\n fragment: SWIRL_MOVEMENT_FRAGMENT,\n uniforms: SWIRL_MOVEMENT_UNIFORMS,\n },\n distort: {\n label: \"Distort\",\n fragment: DISTORT_EFFECT_FRAGMENT,\n uniforms: DISTORT_UNIFORMS,\n },\n perspectiveSingle: {\n label: \"Perspective Single\",\n fragment: PERSPECTIVE_SINGLE_FRAGMENT,\n uniforms: PERSPECTIVE_SINGLE_UNIFORMS,\n },\n distortSpin: {\n label: \"Distort Spin\",\n fragment: DISTORT_SPIN_FRAGMENT,\n uniforms: DISTORT_SPIN_UNIFORMS,\n },\n distortGrid: {\n label: \"Distort Grid\",\n fragment: DISTORT_GRID_FRAGMENT,\n uniforms: DISTORT_GRID_UNIFORMS,\n },\n mirrorTile: {\n label: \"Mirror Tile\",\n fragment: MIRROR_TILE_FRAGMENT,\n uniforms: MIRROR_TILE_UNIFORMS,\n },\n flashLoop: {\n label: \"Flash Loop\",\n fragment: FLASH_LOOP_FRAGMENT,\n uniforms: FLASH_LOOP_UNIFORMS,\n },\n filmStripPro: {\n label: \"Film Strip Pro\",\n fragment: FILM_STRIP_PRO_FRAGMENT,\n uniforms: FILM_STRIP_PRO_UNIFORMS,\n },\n inverseAperture: {\n label: \"Inverse Aperture\",\n fragment: INVERSE_APERTURE_FRAGMENT,\n uniforms: INVERSE_APERTURE_UNIFORMS,\n },\n curtainOpen: {\n label: \"Curtain Open\",\n fragment: CURTAIN_OPEN_FRAGMENT,\n uniforms: CURTAIN_OPEN_UNIFORMS,\n },\n curtainBlur: {\n label: \"Curtain Blur\",\n fragment: CURTAIN_BLUR_FRAGMENT,\n uniforms: CURTAIN_BLUR_UNIFORMS,\n },\n distortV2: {\n label: \"Distort V2\",\n fragment: DISTORT_V2_FRAGMENT,\n uniforms: DISTORT_V2_UNIFORMS,\n },\n neonFlash: {\n label: \"Neon Flash\",\n fragment: NEON_FLASH_FRAGMENT,\n uniforms: NEON_FLASH_UNIFORMS,\n },\n waveDistort: {\n label: \"Wave Distort\",\n fragment: WAVE_DISTORT_FRAGMENT,\n uniforms: WAVE_DISTORT_UNIFORMS,\n },\n scaleMoveBlur: {\n label: \"Scale Move Blur\",\n fragment: SCALE_MOVE_BLUR_FRAGMENT,\n uniforms: SCALE_MOVE_BLUR_UNIFORMS,\n },\n paperBreakReveal: {\n label: \"Paper Break Reveal\",\n fragment: PAPER_BREAK_REVEAL_FRAGMENT,\n uniforms: PAPER_BREAK_REVEAL_UNIFORMS,\n },\n laser: {\n label: \"Laser\",\n fragment: LASER_FRAGMENT,\n uniforms: LASER_UNIFORMS,\n },\n wave: {\n label: \"Wave\",\n fragment: WAVE_FRAGMENT,\n uniforms: WAVE_UNIFORMS,\n },\n sparks: {\n label: \"Sparks\",\n fragment: SPARKS_FRAGMENT,\n uniforms: SPARKS_UNIFORMS,\n },\n tvScanlines: {\n label: \"TV Scanlines\",\n fragment: TV_SCANLINES_FRAGMENT,\n uniforms: TV_SCANLINES_UNIFORMS,\n },\n hdr: {\n label: \"HDR\",\n fragment: HDR_FRAGMENT,\n uniforms: HDR_UNIFORMS,\n },\n blackFlash: {\n label: \"Black Flash\",\n fragment: BLACK_FLASH_FRAGMENT,\n uniforms: BLACK_FLASH_UNIFORMS,\n },\n brightPulse: {\n label: \"Bright Pulse\",\n fragment: BRIGHT_PULSE_FRAGMENT,\n uniforms: BRIGHT_PULSE_UNIFORMS,\n },\n cameraMove: {\n label: \"Camera Move\",\n fragment: CAMERA_MOVE_FRAGMENT,\n uniforms: CAMERA_MOVE_UNIFORMS,\n },\n hdrV2: {\n label: \"HDR V2\",\n fragment: HDR_V2_FRAGMENT,\n uniforms: HDR_V2_UNIFORMS,\n },\n fastZoom: {\n label: \"Fast Zoom\",\n fragment: FAST_ZOOM_FRAGMENT,\n uniforms: FAST_ZOOM_UNIFORMS,\n },\n fadeIn: {\n label: \"Fade In\",\n fragment: FADE_IN_FRAGMENT,\n uniforms: FADE_IN_UNIFORMS,\n },\n fadeOut: {\n label: \"Fade Out\",\n fragment: FADE_OUT_FRAGMENT,\n uniforms: FADE_OUT_UNIFORMS,\n },\n} as const satisfies Record<string, GlEffect>;\n\n/**\n * Get all available effects, including library and runtime registered ones\n */\nexport function getAllEffects(): Record<string, GlEffect> {\n return {\n ...STATIC_EFFECTS,\n ...REGISTERED_EFFECTS,\n };\n}\n\n// Keep GL_EFFECTS for backward compatibility, but it will only contain initial ones\nexport const GL_EFFECTS = getAllEffects();\n\nexport type EffectKey = string;\n\nexport function getEffectOptions() {\n const registeredKeys = Object.keys(REGISTERED_EFFECTS);\n return Object.entries(getAllEffects()).map(([key, value]) => ({\n key: key as EffectKey,\n label: value.label,\n isCustom: registeredKeys.includes(key),\n previewStatic:\n value.previewStatic ||\n `https://cdn.subgen.co/previews/effects/static/effect_${key}_static.webp`,\n previewDynamic:\n value.previewDynamic ||\n `https://cdn.subgen.co/previews/effects/dynamic/effect_${key}_dynamic.webp`,\n }));\n}\n\n// Keep GL_EFFECT_OPTIONS for backward compatibility\nexport const GL_EFFECT_OPTIONS = getEffectOptions();\n","import {\n AdjustmentFilter,\n AdvancedBloomFilter,\n BackdropBlurFilter,\n BloomFilter,\n ColorMapFilter,\n ColorOverlayFilter,\n ConvolutionFilter,\n DotFilter,\n DropShadowFilter,\n GlitchFilter,\n GlowFilter,\n GodrayFilter,\n GrayscaleFilter,\n HslAdjustmentFilter,\n KawaseBlurFilter,\n MotionBlurFilter,\n OldFilmFilter,\n PixelateFilter,\n RadialBlurFilter,\n ReflectionFilter,\n RGBSplitFilter,\n TiltShiftFilter,\n} from \"pixi-filters\";\nimport { FilterOptionsMap } from \"../interface\";\n\nexport const FILTER_CLASSES: Record<string, any> = {\n adjustmentFilter: AdjustmentFilter,\n advancedBloomFilter: AdvancedBloomFilter,\n backdropBlurFilter: BackdropBlurFilter,\n bloomFilter: BloomFilter,\n colorMapFilter: ColorMapFilter,\n colorOverlayFilter: ColorOverlayFilter,\n convolutionFilter: ConvolutionFilter,\n dotFilter: DotFilter,\n dropShadowFilter: DropShadowFilter,\n glitchFilter: GlitchFilter,\n glowFilter: GlowFilter,\n godrayFilter: GodrayFilter,\n grayscaleFilter: GrayscaleFilter,\n hslAdjustmentFilter: HslAdjustmentFilter,\n kawaseBlurFilter: KawaseBlurFilter,\n motionBlurFilter: MotionBlurFilter,\n oldFilmFilter: OldFilmFilter,\n pixelateFilter: PixelateFilter,\n radialBlurFilter: RadialBlurFilter,\n reflectionFilter: ReflectionFilter,\n rgbSplitFilter: RGBSplitFilter,\n tiltShiftFilter: TiltShiftFilter,\n};\n\nexport const VALUES_FILTER_SPECIAL: FilterOptionsMap = {\n adjustmentFilter: {\n gamma: 1.5,\n saturation: 0.5,\n contrast: 1.2,\n brightness: 1.5,\n red: 1.5,\n green: 1.5,\n blue: 1.5,\n alpha: 1.0,\n },\n advancedBloomFilter: {\n threshold: 0.2,\n bloomScale: 1.0,\n brightness: 1.0,\n blur: 20.0,\n quality: 1.0,\n },\n backdropBlurFilter: {\n blur: 10,\n quality: 4,\n },\n bloomFilter: {\n kernelSize: 5,\n quality: 2,\n resolution: 3,\n strength: {\n x: 10.0,\n y: 10.0,\n },\n },\n colorMapFilter: {\n mix: 1,\n nearest: true,\n // colorMap\n },\n colorOverlayFilter: {\n color: \"#ffffff\",\n alpha: 1,\n },\n convolutionFilter: {\n width: 3,\n height: 3,\n matrix: [1, 0, 0, 0, 1, 0, 0, 0, 1],\n },\n dotFilter: {\n scale: 1,\n angle: 1,\n grayscale: true,\n },\n dropShadowFilter: {\n blur: 1,\n quality: 3,\n alpha: 0.5,\n offset: { x: 4, y: 4 },\n color: \"#000000\",\n shadowOnly: true,\n },\n glitchFilter: {\n seed: 0.5,\n slices: 10,\n offset: 0.1,\n direction: 0,\n fillMode: 0,\n red: { x: 2, y: 2 },\n green: { x: 10, y: -4 },\n blue: { x: -10, y: 4 },\n },\n glowFilter: {\n distance: 10,\n outerStrength: 2,\n innerStrength: 0,\n color: \"#ffffff\",\n quality: 1,\n alpha: 1,\n knockout: false,\n },\n godrayFilter: {\n time: 0,\n gain: 0.6,\n lacunarity: 2.75,\n alpha: 1,\n parallel: true,\n angle: 30,\n center: {\n x: 426,\n y: -100,\n },\n },\n grayscaleFilter: {},\n hslAdjustmentFilter: {\n hue: 100,\n saturation: 1,\n lightness: 0,\n colorize: false,\n alpha: 1,\n },\n kawaseBlurFilter: {\n strength: 4,\n quality: 3,\n pixelSize: {\n x: 1,\n y: 1,\n },\n },\n motionBlurFilter: {\n velocity: {\n x: 40,\n y: 40,\n },\n kernelSize: 5,\n offset: 0,\n },\n oldFilmFilter: {\n sepia: 0.3,\n noise: 0.3,\n noiseSize: 1,\n scratch: 0.5,\n scratchDensity: 0.5,\n scratchWidth: 1,\n vignetting: 0.3,\n vignettingAlpha: 1.0,\n vignettingBlur: 0.3,\n },\n pixelateFilter: {\n size: 10,\n },\n radialBlurFilter: {\n angle: 20,\n center: {\n x: 0,\n y: 0,\n },\n radius: 300,\n kernelSize: 15,\n },\n reflectionFilter: {\n mirror: true,\n boundary: 0.5,\n amplitude: [20, 50],\n waveLength: [30, 100],\n alpha: [1, 1],\n time: 0,\n },\n rgbSplitFilter: {\n red: { x: 2, y: 2 },\n green: { x: 10, y: -4 },\n blue: { x: -10, y: 4 },\n },\n tiltShiftFilter: {\n blur: 100,\n gradientBlur: 600,\n start: {\n x: 0,\n y: 0,\n },\n end: {\n x: 853,\n y: 414,\n },\n },\n};\n\nexport const VALUES_FILTER_SPECIAL_LIMITS = {\n adjustmentFilter: {\n gamma: { min: 0, max: 5, step: 0.07 },\n saturation: { min: 0, max: 5, step: 0.07 },\n contrast: { min: 0, max: 5, step: 0.07 },\n brightness: { min: 0, max: 5, step: 0.07 },\n red: { min: 0, max: 5, step: 0.07 },\n green: { min: 0, max: 5, step: 0.07 },\n blue: { min: 0, max: 5, step: 0.07 },\n alpha: { min: 0, max: 5, step: 0.07 },\n },\n advancedBloomFilter: {\n threshold: { min: 0.1, max: 0.9, step: 0.009 },\n bloomScale: { min: 0.5, max: 1.5, step: 0.015 },\n brightness: { min: 0.5, max: 1.5, step: 0.015 },\n blur: { min: 0, max: 20, step: 0.2 },\n quality: { min: 1, max: 20, step: 1 },\n },\n backdropBlurFilter: {\n blur: { min: 0, max: 100, step: 2.3 },\n quality: { min: 1, max: 10, step: 0.1 },\n },\n bloomFilter: {\n kernelSize: { min: 0, max: 15, step: 1 },\n quality: { min: 0, max: 10, step: 1 },\n resolution: { min: 0, max: 10, step: 1 },\n strength: {\n x: { min: 0, max: 20, step: 0.5 },\n y: { min: 0, max: 20, step: 0.5 },\n },\n },\n colorMapFilter: {\n mix: { min: 0, max: 1, step: 0.013 },\n },\n colorOverlayFilter: {\n alpha: { min: 0, max: 1, step: 0.013 },\n },\n convolutionFilter: {\n width: { min: 0, max: 500, step: 1.0 },\n height: { min: 0, max: 500, step: 1.0 },\n matrix: [\n {\n max: 0,\n min: 1,\n step: 0.01,\n },\n {\n max: 0,\n min: 1,\n step: 0.01,\n },\n {\n max: 0,\n min: 1,\n step: 0.01,\n },\n {\n max: 0,\n min: 1,\n step: 0.01,\n },\n {\n max: 0,\n min: 1,\n step: 0.01,\n },\n {\n max: 0,\n min: 1,\n step: 0.01,\n },\n {\n max: 0,\n min: 1,\n step: 0.01,\n },\n {\n max: 0,\n min: 1,\n step: 0.01,\n },\n ],\n },\n dotFilter: {\n scale: { min: 0.3, max: 1, step: 0.01 },\n angle: { min: 0, max: 5, step: 0.01 },\n },\n dropShadowFilter: {\n blur: { min: 0, max: 20, step: 0.5 },\n quality: { min: 1, max: 20, step: 1 },\n alpha: { min: 0, max: 1, step: 0.013 },\n offset: {\n x: { min: -50, max: 50, step: 2.5 },\n y: { min: -50, max: 50, step: 2.5 },\n },\n },\n glitchFilter: {\n seed: { min: 0, max: 1, step: 0.01 },\n slices: { min: 2, max: 20, step: 0.01 },\n offset: { min: -400, max: 400, step: 0.1 },\n direction: { min: -180, max: 180, step: 0.1 },\n red: {\n x: { min: -50, max: 50, step: 1 },\n y: { min: -50, max: 50, step: 1 },\n },\n green: {\n x: { min: -50, max: 50, step: 1 },\n y: { min: -50, max: 50, step: 1 },\n },\n blue: {\n x: { min: -50, max: 50, step: 1 },\n y: { min: -50, max: 50, step: 1 },\n },\n },\n glowFilter: {\n distance: { min: 0, max: 20, step: 0.013 },\n outerStrength: { min: 0, max: 20, step: 0.013 },\n innerStrength: { min: 0, max: 20, step: 0.013 },\n quality: { min: 0, max: 1, step: 0.013 },\n alpha: { min: 0, max: 1, step: 0.013 },\n },\n godrayFilter: {\n time: { min: 0, max: 1, step: 0.013 },\n gain: { min: 0, max: 1, step: 0.013 },\n lacunarity: { min: 0, max: 5, step: 0.013 },\n alpha: { min: 0, max: 1, step: 0.013 },\n\n angle: { min: -60, max: 60, step: 0.1 },\n center: {\n x: { min: -100, max: 960, step: 14 },\n y: { min: -1000, max: -100, step: 14 },\n },\n },\n grayscaleFilter: {},\n hslAdjustmentFilter: {\n hue: { min: -180, max: 180, step: 0.013 },\n saturation: { min: -1, max: 1, step: 0.013 },\n lightness: { min: -1, max: 1, step: 0.013 },\n alpha: { min: 0, max: 1, step: 0.013 },\n },\n kawaseBlurFilter: {\n strength: { min: 0, max: 20, step: 0.013 },\n quality: { min: 1, max: 20, step: 0.013 },\n pixelSize: {\n x: { min: 0, max: 10, step: 0.013 },\n y: { min: 0, max: 10, step: 0.013 },\n },\n },\n motionBlurFilter: {\n velocity: {\n x: { min: -90, max: 90, step: 0.013 },\n y: { min: -90, max: 90, step: 0.013 },\n },\n kernelSize: { min: 0, max: 25, step: 3 },\n offset: { min: -150, max: 150, step: 0.1 },\n },\n oldFilmFilter: {\n sepia: { min: 0, max: 1, step: 0.01 },\n noise: { min: 0, max: 1, step: 0.01 },\n noiseSize: { min: 1, max: 20, step: 1 },\n scratch: { min: -1, max: 1, step: 0.01 },\n scratchDensity: { min: 0, max: 1, step: 0.01 },\n scratchWidth: { min: 1, max: 20, step: 1 },\n vignetting: { min: 0, max: 1, step: 0.01 },\n vignettingAlpha: { min: 0, max: 1, step: 0.01 },\n vignettingBlur: { min: 0, max: 1, step: 0.01 },\n },\n pixelateFilter: {\n size: { min: 4, max: 40, step: 0.013 },\n },\n radialBlurFilter: {\n angle: { min: -180, max: 180, step: 0.1 },\n center: {\n x: { min: 0, max: 2000, step: 0.1 },\n y: { min: 0, max: 2000, step: 0.1 },\n },\n radius: { min: -1, max: 860, step: 0.1 },\n kernelSize: { min: 0, max: 25, step: 3 },\n },\n reflectionFilter: {\n boundary: { min: 0, max: 1, step: 0.01 },\n amplitude: [\n {\n min: 0,\n max: 50,\n step: 0.013,\n },\n {\n min: 0,\n max: 50,\n step: 0.013,\n },\n ],\n waveLength: [\n {\n min: 0,\n max: 200,\n step: 0.013,\n },\n {\n min: 0,\n max: 200,\n step: 0.013,\n },\n ],\n alpha: [\n {\n min: 0,\n max: 1,\n step: 0.01,\n },\n {\n min: 0,\n max: 1,\n step: 0.01,\n },\n ],\n time: { min: 0, max: 20, step: 0.01 },\n },\n rgbSplitFilter: {\n red: {\n x: { min: -20, max: 20, step: 0.013 },\n y: { min: -20, max: 20, step: 0.013 },\n },\n green: {\n x: { min: -20, max: 20, step: 0.013 },\n y: { min: -20, max: 20, step: 0.013 },\n },\n blue: {\n x: { min: -20, max: 20, step: 0.013 },\n y: { min: -20, max: 20, step: 0.013 },\n },\n },\n tiltShiftFilter: {\n blur: { min: 0, max: 200, step: 0.1 },\n gradientBlur: { min: 0, max: 1000, step: 1 },\n start: {\n x: { min: 0, max: 2000, step: 0.1 },\n y: { min: 0, max: 2000, step: 0.1 },\n },\n end: {\n x: { min: 0, max: 2000, step: 0.1 },\n y: { min: 0, max: 2000, step: 0.1 },\n },\n },\n};\n","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAQCAIAAAB2sTYeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF6GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDAgNzkuMTYwNDUxLCAyMDE3LzA1LzA2LTAxOjA4OjIxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIiB4bXA6Q3JlYXRlRGF0ZT0iMjAxOC0wMS0yM1QwMjo0NToyMSswODowMCIgeG1wOk1vZGlmeURhdGU9IjIwMTgtMDEtMjNUMDQ6MzQ6NTUrMDg6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMTgtMDEtMjNUMDQ6MzQ6NTUrMDg6MDAiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDk0MTcyNTUtZDRlNS00YjRiLTlhNGUtYjVhOGQ4MjIzMDgzIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkQ2NDI4MEY0RjY2MjExRTdCOTdGOENCMTc0MEREQUYxIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6RDY0MjgwRjRGNjYyMTFFN0I5N0Y4Q0IxNzQwRERBRjEiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpENjQyODBGMUY2NjIxMUU3Qjk3RjhDQjE3NDBEREFGMSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpENjQyODBGMkY2NjIxMUU3Qjk3RjhDQjE3NDBEREFGMSIvPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDowOTQxNzI1NS1kNGU1LTRiNGItOWE0ZS1iNWE4ZDgyMjMwODMiIHN0RXZ0OndoZW49IjIwMTgtMDEtMjNUMDQ6MzQ6NTUrMDg6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoTWFjaW50b3NoKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz51hjvPAAAUu0lEQVRogYXa648dd5oX8M+vqk6dW1/cbXe7Hd+SOL52fIkvncsk2SwZRoM0I8QiVgjBCiHBSxDafwFerMQ7VghegIS0aHeE0CAYwTIww04SPEwymcQza09uTuIkdtqXbruvp/v0qVO8qKru0207PDq2+pz61q9+l+9zrSfYkieY4Vtc4AjjNIibQpMGw+BDYTv+Rc5zbBNvC1DIIP45XuUST7Hn0fjxANmQhZFq/EuD89mJfyVI2Zi08Iwvxyy/pnvhm8b/w+LrAS764ohrk9YvWT6iM67T0H0I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\"","export default \"data:image/png;base64,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\"","import { Assets, Filter, GlProgram, Sprite, Texture, RenderTexture, UniformGroup } from \"pixi.js\";\nimport type { EffectOptions, EffectRendererOptions } from \"./types\";\nimport { vertex } from \"./vertex\";\nimport { getAllEffects } from \"./glsl/gl-effect\";\nimport { FILTER_CLASSES, VALUES_FILTER_SPECIAL } from \"./constant\";\nimport type { FilterOptionsMap } from \"./interface\";\nimport textureUrl from \"../assets/texture1.png\";\nimport textureUrl2 from \"../assets/texture2.png\";\n\nexport async function makeEffect({ name, renderer, values }: EffectOptions) {\n let filter: any = null;\n\n const specialEffects = name in VALUES_FILTER_SPECIAL;\n let options: any = {};\n if (specialEffects) {\n const FilterClass = FILTER_CLASSES[name];\n const defaults = VALUES_FILTER_SPECIAL[name as keyof FilterOptionsMap];\n options = { ...defaults, ...values };\n\n if (name === \"colorMapFilter\") {\n options.colorMap = await Assets.load(textureUrl);\n }\n\n if (name === \"simpleLightmapFilter\") {\n options.lightMap = await Assets.load(textureUrl2);\n }\n filter = new FilterClass(options);\n } else {\n const effects = getAllEffects();\n const localKey = Object.keys(effects).find(\n (key) => key.toLowerCase() === name.toLowerCase(),\n ) as string | undefined;\n\n if (!localKey) {\n console.warn(`Effect ${name} not found`);\n // No result: callers skip the effect. (Returning the input texture made callers composite and\n // then destroy a texture they didn't own.)\n return {\n filter: null,\n render(_opts: EffectRendererOptions): RenderTexture | null {\n return null;\n },\n };\n }\n\n const { fragment, uniforms, label } = effects[localKey];\n const program = new GlProgram({\n vertex,\n fragment,\n name: `${label}-shader`,\n });\n\n const effectUniforms = new UniformGroup({\n uTime: { value: 0, type: \"f32\" },\n ...uniforms,\n });\n\n filter = new Filter({\n glProgram: program,\n resources: { effectUniforms },\n });\n }\n\n const effectSprite = new Sprite();\n const effectTexture = RenderTexture.create({\n width: renderer.width,\n height: renderer.height,\n });\n\n effectSprite.filters = [filter];\n\n return {\n filter,\n render({\n width,\n height,\n canvasTexture,\n progress,\n values: runtimeValues,\n }: EffectRendererOptions) {\n if (effectTexture.width !== width || effectTexture.height !== height) {\n effectTexture.resize(width, height);\n }\n\n const tex =\n canvasTexture instanceof RenderTexture\n ? canvasTexture\n : Texture.from(canvasTexture as HTMLCanvasElement);\n\n effectSprite.texture = tex;\n effectSprite.width = width;\n effectSprite.height = height;\n\n const finalValues = { ...options, ...runtimeValues };\n\n if (specialEffects) {\n if (runtimeValues) {\n Object.assign(filter, finalValues);\n }\n } else if (filter.resources?.effectUniforms) {\n filter.resources.effectUniforms.uniforms.uTime = progress;\n if (runtimeValues) {\n for (const [key, val] of Object.entries(runtimeValues)) {\n if (filter.resources.effectUniforms.uniforms[key]) {\n filter.resources.effectUniforms.uniforms[key] = val;\n }\n }\n }\n }\n\n renderer.render({\n container: effectSprite,\n target: effectTexture,\n clear: true,\n });\n\n return effectTexture;\n },\n };\n}\n","import { Application, Container, RenderTexture, Sprite, Filter, Texture } from \"pixi.js\";\nimport { type IClip, Effect } from \"../clips\";\nimport { makeEffect } from \"../effect/effect\";\nimport { PixiSpriteRenderer } from \"../sprite/pixi-sprite-renderer\";\n\nexport class EffectManager {\n private pixiApp: Application;\n private effectCache = new Map<string, { filter: Filter; render: (opts: any) => Texture | null }>();\n private effectInputTexture: RenderTexture | null = null;\n\n // The effect/post-process containers are scaled by the export scale; sprites placed in them\n // must be sized in project units or they end up scaled twice.\n private scaleX: number;\n private scaleY: number;\n\n constructor(pixiApp: Application, hasVideoTrack: boolean, scaleX = 1, scaleY = 1) {\n this.scaleX = scaleX > 0 ? scaleX : 1;\n this.scaleY = scaleY > 0 ? scaleY : 1;\n this.pixiApp = pixiApp;\n this.effectInputTexture = hasVideoTrack\n ? RenderTexture.create({\n width: pixiApp.renderer.width,\n height: pixiApp.renderer.height,\n })\n : null;\n }\n\n /**\n * Processes all active global and adjustment layer effects at the given timestamp.\n */\n public async processEffects(opts: {\n timestamp: number;\n sprites: Array<IClip & { expired?: boolean }>;\n spriteById: Map<string, IClip>;\n spriteIndexById: Map<string, number>;\n spriteRenderers: Map<IClip & { expired?: boolean }, PixiSpriteRenderer>;\n transitionSprites: Map<string, Sprite>;\n clipsEffectContainer: Container;\n clipsNormalContainer: Container;\n postProcessContainer: Container;\n }): Promise<void> {\n const {\n timestamp,\n sprites,\n spriteById,\n spriteIndexById,\n spriteRenderers,\n transitionSprites,\n clipsEffectContainer,\n clipsNormalContainer,\n postProcessContainer,\n } = opts;\n\n if (!this.effectInputTexture) return;\n\n // 1. Collect all active global and adjustment layer effects\n const activeGlobalEffects: Array<{\n id: string;\n key: string;\n startTime: number;\n duration: number;\n zIndex: number;\n values?: Record<string, any>;\n }> = [];\n\n for (const sprite of sprites) {\n if (sprite instanceof Effect) {\n if (timestamp >= sprite.display.from && timestamp < sprite.display.from + sprite.duration) {\n activeGlobalEffects.push({\n id: sprite.id,\n key: (sprite as Effect).effectKey,\n startTime: sprite.display.from,\n duration: sprite.duration,\n zIndex: sprite.zIndex,\n values: (sprite as Effect).values,\n });\n }\n }\n\n // Check for attached effects (legacy)\n if (sprite.effects && sprite.effects.length > 0) {\n for (const effect of sprite.effects) {\n if (timestamp >= effect.startTime && timestamp < effect.startTime + effect.duration) {\n // Attached effects use the clip's zIndex for sorting\n activeGlobalEffects.push({\n ...effect,\n zIndex: sprite.zIndex,\n });\n }\n }\n }\n }\n\n // 2. Sort effects bottom-up by zIndex\n activeGlobalEffects.sort((a, b) => a.zIndex - b.zIndex);\n\n // Clean post process container\n postProcessContainer.removeChildren();\n\n // Reset all clips to normal container first\n for (const renderer of spriteRenderers.values()) {\n const root = renderer.getRoot();\n if (root && root.parent !== clipsNormalContainer) {\n if (root.parent) (root.parent as Container).removeChild(root);\n clipsNormalContainer.addChild(root);\n }\n }\n\n if (activeGlobalEffects.length > 0) {\n const width = this.pixiApp.renderer.width;\n const height = this.pixiApp.renderer.height;\n const projectW = width / this.scaleX;\n const projectH = height / this.scaleY;\n\n let lastResultTexture: Texture | null = null;\n const processedClips = new Set<string>();\n\n for (const effect of activeGlobalEffects) {\n const { key, startTime, duration, id, zIndex } = effect;\n const elapsed = timestamp - startTime;\n const progress = duration > 0 ? Math.min(Math.max(elapsed / duration, 0), 1) : 0;\n\n // Check if this is an Adjustment Layer Effect\n const adjSprite = spriteById.get(id);\n const isAdjustmentLayer = adjSprite != null && adjSprite instanceof Effect;\n\n clipsEffectContainer.removeChildren();\n\n // If we have a previous result, add it bottom-most\n if (lastResultTexture) {\n const prevSprite = new Sprite(lastResultTexture);\n prevSprite.width = projectW;\n prevSprite.height = projectH;\n clipsEffectContainer.addChild(prevSprite);\n }\n\n // Move affected clips that are BELOW this effect layer\n const effectIdx = spriteIndexById.get(id) ?? -1;\n\n for (const sprite of sprites) {\n if (processedClips.has(sprite.id)) continue;\n\n let shouldApply = false;\n if (isAdjustmentLayer) {\n if (sprite.id === id) continue;\n const sprIdx = spriteIndexById.get(sprite.id) ?? -1;\n shouldApply =\n sprite.zIndex < zIndex || (sprite.zIndex === zIndex && sprIdx > effectIdx);\n } else {\n // Legacy attached effect\n shouldApply = !!sprite.effects && sprite.effects.some((e) => e.id === id);\n }\n\n if (shouldApply) {\n const renderer = spriteRenderers.get(sprite);\n if (renderer) {\n const root = renderer.getRoot();\n if (root) {\n if (root.parent) (root.parent as Container).removeChild(root);\n clipsEffectContainer.addChild(root);\n processedClips.add(sprite.id);\n }\n }\n\n // Also check for Transition Sprite\n const transSprite = transitionSprites.get(sprite.id);\n if (transSprite) {\n if (transSprite.parent) (transSprite.parent as Container).removeChild(transSprite);\n clipsEffectContainer.addChild(transSprite);\n processedClips.add(sprite.id);\n }\n }\n }\n\n if (clipsEffectContainer.children.length > 0) {\n let effectCached = this.effectCache.get(id);\n if (!effectCached) {\n try {\n const res = await makeEffect({\n name: key as any,\n renderer: this.pixiApp.renderer,\n values: effect.values,\n });\n if (res && res.filter) {\n effectCached = { filter: res.filter as Filter, render: res.render };\n this.effectCache.set(id, effectCached);\n }\n } catch (e) {\n console.warn(\"Failed to create effect\", key, e);\n }\n }\n\n if (effectCached) {\n const { filter, render: effectRenderFunc } = effectCached;\n if (filter.resources && filter.resources.effectUniforms) {\n filter.resources.effectUniforms.uniforms.uTime = progress;\n }\n\n clipsEffectContainer.visible = true;\n this.pixiApp.renderer.render({\n container: clipsEffectContainer,\n target: this.effectInputTexture!,\n clear: true,\n });\n clipsEffectContainer.visible = false;\n\n if (effectRenderFunc) {\n const resultTexture = effectRenderFunc({\n canvasTexture: this.effectInputTexture!,\n progress,\n width,\n height,\n });\n lastResultTexture = resultTexture;\n }\n }\n }\n }\n\n if (lastResultTexture) {\n const resultSprite = new Sprite(lastResultTexture);\n resultSprite.width = projectW;\n resultSprite.height = projectH;\n postProcessContainer.addChild(resultSprite);\n\n // Move clips that are ABOVE all effects into postProcessContainer\n for (const sprite of sprites) {\n if (processedClips.has(sprite.id)) continue;\n if (sprite instanceof Effect) continue;\n if (sprite.expired) continue;\n\n const renderer = spriteRenderers.get(sprite);\n if (renderer) {\n const root = renderer.getRoot();\n if (root && root.visible) {\n if (root.parent) (root.parent as Container).removeChild(root);\n postProcessContainer.addChild(root);\n }\n }\n }\n }\n }\n }\n\n public cleanup(): void {\n if (this.effectInputTexture) {\n this.effectInputTexture.destroy(true);\n }\n this.effectCache.clear();\n }\n}\n","import { Application, Container } from \"pixi.js\";\nimport { type IClip, Transition, DEFAULT_AUDIO_CONF } from \"../clips\";\nimport { PixiSpriteRenderer } from \"../sprite/pixi-sprite-renderer\";\nimport { TransitionManager } from \"./transition-manager\";\nimport { EffectManager } from \"./effect-manager\";\nimport { applyAudioFade } from \"../utils\";\n\nexport interface ISpritesRenderOpts {\n pixiApp: Application | null;\n backgroundColor: string;\n sprites: Array<IClip & { main: boolean; expired: boolean }>;\n aborter: { aborted: boolean };\n scaleX: number;\n scaleY: number;\n}\n\nexport interface ISpritesRenderResult {\n render: (timestamp: number) => Promise<{\n audios: Float32Array[][];\n mainSprDone: boolean;\n hasVideo: boolean;\n }>;\n cleanup: () => void;\n}\n\n/**\n * Creates the renderer pipeline for compositor frames.\n * Delegates actual transition handling, asset transformations, styles/filters,\n * and global effects pipeline execution to separate managers.\n */\nexport function createSpritesRender(opts: ISpritesRenderOpts): ISpritesRenderResult {\n const { pixiApp, sprites, aborter, scaleX, scaleY } = opts;\n const hasVideoTrack = pixiApp != null;\n\n // Map to store PixiSpriteRenderer instances for each clip (only for video)\n const spriteRenderers = new Map<\n IClip & { main: boolean; expired: boolean },\n PixiSpriteRenderer\n >();\n\n const transitionManager =\n hasVideoTrack && pixiApp ? new TransitionManager(pixiApp, scaleX, scaleY) : null;\n const effectManager = hasVideoTrack && pixiApp ? new EffectManager(pixiApp, hasVideoTrack, scaleX, scaleY) : null;\n\n // Containers for global effect rendering and transitions\n let clipsEffectContainer: Container | null = null;\n let clipsNormalContainer: Container | null = null;\n let postProcessContainer: Container | null = null;\n\n if (hasVideoTrack && pixiApp != null) {\n clipsEffectContainer = new Container();\n clipsNormalContainer = new Container();\n postProcessContainer = new Container();\n\n // Apply scale to map from original project dimensions to export dimensions\n clipsNormalContainer.scale.set(scaleX, scaleY);\n clipsEffectContainer.scale.set(scaleX, scaleY);\n postProcessContainer.scale.set(scaleX, scaleY);\n\n clipsNormalContainer.sortableChildren = true;\n postProcessContainer.sortableChildren = true;\n\n pixiApp.stage.addChild(clipsNormalContainer);\n pixiApp.stage.addChild(postProcessContainer);\n clipsEffectContainer.visible = false;\n pixiApp.stage.addChild(clipsEffectContainer);\n }\n\n // Pre-sort sprites once as they don't change during encoding\n const sortedSprites = [...sprites].sort((a, b) => a.zIndex - b.zIndex);\n\n // Pre-build ID→sprite lookup map to avoid O(n) .find() scans per frame\n const spriteById = new Map<string, (typeof sprites)[number]>();\n // Pre-build index map for track-order comparisons in effects pipeline\n const spriteIndexById = new Map<string, number>();\n for (let i = 0; i < sprites.length; i++) {\n spriteById.set(sprites[i].id, sprites[i]);\n spriteIndexById.set(sprites[i].id, i);\n }\n\n const render = async (timestamp: number) => {\n const audios: Float32Array[][] = [];\n let mainSprDone = false;\n let hasVideo = false;\n\n // Cache to store getFrame results for each clip at the current timestamp\n const frameCache = new Map<IClip, { video: any; audio: Float32Array[]; done: boolean }>();\n\n const getFrameCached = async (sprite: IClip, relTime: number) => {\n if (frameCache.has(sprite)) return frameCache.get(sprite)!;\n const res = await sprite.getFrame(relTime);\n frameCache.set(sprite, res);\n return res;\n };\n\n // Reset all transition sprites for each frame\n if (transitionManager) {\n transitionManager.resetFrame();\n }\n\n // Track clip IDs claimed by active transitions this frame\n const clipsClaimedByTransition = new Set<string>();\n\n for (const sprite of sortedSprites) {\n if (aborter.aborted) break;\n\n const exceededDisplayTo = sprite.display.to > 0 && timestamp >= sprite.display.to;\n if (exceededDisplayTo) {\n sprite.expired = true;\n }\n\n if (timestamp < sprite.display.from || sprite.expired) {\n // Even if expired, we might need to hide renderer\n if (hasVideoTrack && pixiApp != null) {\n const renderer = spriteRenderers.get(sprite);\n if (renderer) {\n await renderer.updateFrame(null);\n }\n }\n continue;\n }\n\n const relativeTime = timestamp - sprite.display.from;\n const spriteTime = relativeTime * sprite.playbackRate;\n\n // Update sprite animation properties FIRST\n sprite.animate(spriteTime);\n\n // ── Text / Caption fast-path ─────────────────────────────────────────────\n if (\n hasVideoTrack &&\n pixiApp != null &&\n clipsNormalContainer != null &&\n (sprite.type === \"Text\" || sprite.type === \"Caption\")\n ) {\n // Caption clips need their highlighting state updated before rendering\n if (sprite.type === \"Caption\" && typeof (sprite as any).updateState === \"function\") {\n (sprite as any).updateState(relativeTime * sprite.playbackRate);\n }\n\n // Ensure the clip renders into the compositor's WebGL context\n if (typeof (sprite as any).setRenderer === \"function\") {\n (sprite as any).setRenderer(pixiApp.renderer);\n }\n\n // Get or create a PixiSpriteRenderer for this clip\n let textRenderer = spriteRenderers.get(sprite);\n if (textRenderer == null) {\n textRenderer = new PixiSpriteRenderer(pixiApp, sprite, clipsNormalContainer);\n spriteRenderers.set(sprite, textRenderer);\n }\n\n const claimedByTransition = clipsClaimedByTransition.has(sprite.id);\n if (!claimedByTransition) {\n const textTexture = await (sprite as any).getTexture();\n if (textTexture != null) {\n hasVideo = true;\n const tRoot = textRenderer.getRoot();\n if (tRoot) tRoot.visible = true;\n await textRenderer.updateFrame(textTexture);\n }\n } else {\n const tRoot = textRenderer.getRoot();\n if (tRoot) tRoot.visible = false;\n await textRenderer.updateFrame(null);\n }\n textRenderer.updateTransforms();\n\n // Text/Caption clips carry no audio\n audios.push([]);\n\n // Handle expiry the same way as the generic path\n const exceededDuration = sprite.duration > 0 && relativeTime > sprite.duration;\n const exceededDisplayToAfter = sprite.display.to > 0 && timestamp >= sprite.display.to;\n if (exceededDuration || exceededDisplayToAfter) {\n if (sprite.main) mainSprDone = true;\n sprite.expired = true;\n const tRoot = textRenderer.getRoot();\n if (tRoot) tRoot.visible = false;\n }\n\n continue; // Skip the generic getFrame() / ImageBitmap path below\n }\n // ── End Text / Caption fast-path ─────────────────────────────────────────\n\n // Get video frame and audio from sprite (using cache)\n const { video, audio, done } = await getFrameCached(sprite, relativeTime);\n\n // Apply audio fade using precise clip-relative timing known at compositor level\n if (audio && audio.length > 0 && (sprite.timing?.fadeIn || sprite.timing?.fadeOut)) {\n const clipDurationMicro =\n sprite.duration && sprite.duration !== Infinity\n ? sprite.duration\n : sprite.display.to - sprite.display.from;\n const audioDurationMicro = (audio[0].length / DEFAULT_AUDIO_CONF.sampleRate) * 1e6;\n const endTimeMicro = relativeTime + audioDurationMicro;\n applyAudioFade(\n audio,\n endTimeMicro, // clip-relative END time of this chunk\n clipDurationMicro,\n DEFAULT_AUDIO_CONF.sampleRate,\n sprite.timing?.fadeIn,\n sprite.timing?.fadeOut,\n );\n }\n\n // Process audio\n audios.push(audio);\n\n const isTransitionable = sprite.type === \"Video\" || sprite.type === \"Image\";\n const transitionStartTime = sprite.transition ? sprite.transition.start! : 0;\n const transitionEndTime = sprite.transition ? sprite.transition.end! : 0;\n const inTransition =\n isTransitionable &&\n sprite.transition &&\n timestamp >= transitionStartTime &&\n timestamp < transitionEndTime;\n\n // Handle video rendering if we have a Pixi app\n if (\n hasVideoTrack &&\n pixiApp != null &&\n clipsNormalContainer != null &&\n transitionManager != null\n ) {\n if (sprite instanceof Transition) {\n const fromClip = spriteById.get(sprite.fromClipId ?? \"\");\n const toClip = spriteById.get(sprite.toClipId ?? \"\");\n\n if (fromClip && toClip) {\n const didRender = await transitionManager.renderTransition({\n sprite,\n timestamp,\n fromClip,\n toClip,\n getFrameCached,\n clipsNormalContainer,\n clipsClaimedByTransition,\n onVideoState: () => {\n hasVideo = true;\n },\n });\n\n if (didRender) {\n // Set the individual renderers of from/to clips to hidden\n const fromRenderer = spriteRenderers.get(fromClip as any);\n if (fromRenderer) {\n const root = fromRenderer.getRoot();\n if (root) root.visible = false;\n }\n\n const toRenderer = spriteRenderers.get(toClip as any);\n if (toRenderer) {\n const root = toRenderer.getRoot();\n if (root) root.visible = false;\n }\n continue;\n }\n }\n }\n\n let renderer = spriteRenderers.get(sprite);\n if (renderer == null && video != null) {\n renderer = new PixiSpriteRenderer(pixiApp, sprite, clipsNormalContainer);\n spriteRenderers.set(sprite, renderer);\n }\n\n if (renderer != null) {\n const root = renderer.getRoot();\n const claimedByTransition = clipsClaimedByTransition.has(sprite.id);\n if (video != null && !inTransition && !claimedByTransition) {\n hasVideo = true;\n if (root) root.visible = true;\n await renderer.updateFrame(video);\n } else {\n if (root) root.visible = false;\n await renderer.updateFrame(null);\n }\n\n renderer.updateTransforms();\n }\n }\n\n // Check if sprite is done or expired\n const exceededDuration = sprite.duration > 0 && relativeTime > sprite.duration;\n const exceededDisplayToAfter = sprite.display.to > 0 && timestamp >= sprite.display.to;\n if (exceededDuration || exceededDisplayToAfter || done) {\n if (sprite.main) mainSprDone = true;\n\n // Mark as expired but DON'T destroy yet\n sprite.expired = true;\n\n // Clean up renderer if it exists\n if (hasVideoTrack) {\n const renderer = spriteRenderers.get(sprite);\n if (renderer != null) {\n const root = renderer.getRoot();\n if (root) root.visible = false;\n }\n }\n }\n }\n\n // Handle Global Effects rendering\n if (\n hasVideoTrack &&\n pixiApp != null &&\n clipsEffectContainer != null &&\n clipsNormalContainer != null &&\n postProcessContainer != null &&\n effectManager != null\n ) {\n // Map transition sprites to transitionManager sprites Map\n const transitionSpritesMap = new Map();\n for (const sprite of sprites) {\n if (sprite instanceof Transition) {\n const transSprite = transitionManager?.getTransitionSprite(sprite.id);\n if (transSprite) {\n transitionSpritesMap.set(sprite.id, transSprite);\n }\n }\n }\n\n await effectManager.processEffects({\n timestamp,\n sprites,\n spriteById,\n spriteIndexById,\n spriteRenderers,\n transitionSprites: transitionSpritesMap,\n clipsEffectContainer,\n clipsNormalContainer,\n postProcessContainer,\n });\n }\n\n // Render the entire Pixi.js scene (only if we have video track and app is ready)\n if (hasVideoTrack && pixiApp != null) {\n pixiApp.render();\n }\n\n return {\n audios,\n mainSprDone,\n hasVideo,\n };\n };\n\n const cleanup = () => {\n if (transitionManager) {\n transitionManager.cleanup();\n }\n if (effectManager) {\n effectManager.cleanup();\n }\n\n // Clean up containers\n if (clipsEffectContainer) clipsEffectContainer.destroy({ children: true });\n if (clipsNormalContainer) clipsNormalContainer.destroy({ children: true });\n if (postProcessContainer) postProcessContainer.destroy({ children: true });\n\n // Clean up all sprite renderers\n spriteRenderers.forEach((renderer) => {\n renderer.destroy();\n });\n spriteRenderers.clear();\n };\n\n return { render, cleanup };\n}\n","import { DEFAULT_AUDIO_CONF } from \"../clips\";\n\n/**\n * Buffer input data and convert to AudioData with fixed frame count.\n * Matches the WebCodecs audio configuration.\n *\n * @param framesPerChunk Number of audio frames per AudioData instance\n * @param fps The video fps (used for calculating buffer limits)\n */\nexport function createAudioTrackBuf(framesPerChunk: number, fps: number = 30) {\n const dataSize = framesPerChunk * DEFAULT_AUDIO_CONF.channelCount;\n // Buffer must hold at least one full video frame worth of audio samples\n // (sampleRate / fps * channelCount) plus extra headroom for two audio chunks.\n const samplesPerVideoFrame =\n Math.ceil(DEFAULT_AUDIO_CONF.sampleRate / fps) * DEFAULT_AUDIO_CONF.channelCount;\n const minBufSize = samplesPerVideoFrame + dataSize * 2;\n\n // PCM data buffer - dynamically expandable\n let channelBuf = new Float32Array(Math.max(dataSize * 3, minBufSize));\n let writePos = 0;\n\n const ensureBufferCapacity = (neededSize: number) => {\n if (channelBuf.length < neededSize) {\n const newBuf = new Float32Array(neededSize);\n newBuf.set(channelBuf.subarray(0, writePos), 0);\n channelBuf = newBuf;\n }\n };\n\n let audioTimestamp = 0;\n const chunkDuration = (framesPerChunk / DEFAULT_AUDIO_CONF.sampleRate) * 1e6;\n\n // Placeholder when audio data is missing\n const placeholderData = new Float32Array(dataSize);\n\n const getAudioData = (timestamp: number, hasNewData: boolean): AudioData[] => {\n let readPos = 0;\n const chunkCount = Math.floor(writePos / dataSize);\n const results: AudioData[] = [];\n\n // Get data from buffer by specified frame count and construct AudioData\n for (let i = 0; i < chunkCount; i++) {\n results.push(\n new AudioData({\n timestamp: audioTimestamp,\n numberOfChannels: DEFAULT_AUDIO_CONF.channelCount,\n numberOfFrames: framesPerChunk,\n sampleRate: DEFAULT_AUDIO_CONF.sampleRate,\n format: \"f32\",\n data: channelBuf.subarray(readPos, readPos + dataSize),\n }),\n );\n readPos += dataSize;\n audioTimestamp += chunkDuration;\n }\n\n // Flush remaining partial chunk when no new data is coming (end of encoding)\n const remainingSamples = writePos - readPos;\n const remainingFrames = Math.floor(remainingSamples / DEFAULT_AUDIO_CONF.channelCount);\n if (!hasNewData && remainingFrames > 0) {\n results.push(\n new AudioData({\n timestamp: audioTimestamp,\n numberOfChannels: DEFAULT_AUDIO_CONF.channelCount,\n numberOfFrames: remainingFrames,\n sampleRate: DEFAULT_AUDIO_CONF.sampleRate,\n format: \"f32\",\n data: channelBuf.subarray(\n readPos,\n readPos + remainingFrames * DEFAULT_AUDIO_CONF.channelCount,\n ),\n }),\n );\n readPos += remainingFrames * DEFAULT_AUDIO_CONF.channelCount;\n audioTimestamp += (remainingFrames / DEFAULT_AUDIO_CONF.sampleRate) * 1e6;\n }\n\n channelBuf.set(channelBuf.subarray(readPos, writePos), 0);\n writePos -= readPos;\n\n // When existing audio data is insufficient, fill with placeholder\n while (timestamp - audioTimestamp > chunkDuration) {\n results.push(\n new AudioData({\n timestamp: audioTimestamp,\n numberOfChannels: DEFAULT_AUDIO_CONF.channelCount,\n numberOfFrames: framesPerChunk,\n sampleRate: DEFAULT_AUDIO_CONF.sampleRate,\n format: \"f32\",\n data: placeholderData,\n }),\n );\n audioTimestamp += chunkDuration;\n }\n return results;\n };\n\n return (timestamp: number, trackAudios: Float32Array[][]): AudioData[] => {\n const maxLen =\n trackAudios.length === 0 ? 0 : Math.max(...trackAudios.map((a) => a[0]?.length ?? 0));\n const hasNewData = maxLen > 0;\n\n // Ensure buffer can handle incoming audio data\n if (hasNewData) {\n ensureBufferCapacity(writePos + maxLen * DEFAULT_AUDIO_CONF.channelCount);\n }\n\n for (let bufIdx = 0; bufIdx < maxLen; bufIdx++) {\n let ch0 = 0;\n let ch1 = 0;\n for (let trackIdx = 0; trackIdx < trackAudios.length; trackIdx++) {\n const c0 = trackAudios[trackIdx][0]?.[bufIdx] ?? 0;\n // If mono PCM, duplicate first channel to second channel\n const c1 = trackAudios[trackIdx][1]?.[bufIdx] ?? c0;\n ch0 += c0;\n ch1 += c1;\n }\n // Mix multiple track audio data and write to buffer\n channelBuf[writePos] = ch0;\n channelBuf[writePos + 1] = ch1;\n writePos += 2;\n }\n // Consume buffer data and generate AudioData\n return getAudioData(timestamp, hasNewData);\n };\n}\n","import { recodemux } from \"wrapbox\";\nimport { createAudioTrackBuf } from \"./audio-mixer\";\n\n/**\n * Resolve the WebGL/WebGL2 context already held by an OffscreenCanvas.\n * Returns null if no WebGL context is attached (e.g. canvas not yet used).\n */\nexport function getCanvasGl(\n canvas: OffscreenCanvas,\n): WebGLRenderingContext | WebGL2RenderingContext | null {\n try {\n // getContext() returns the *existing* context if one was already created,\n // so this never creates a new one — it just retrieves Pixi's context.\n return (\n (canvas.getContext(\"webgl2\") as WebGL2RenderingContext | null) ??\n (canvas.getContext(\"webgl\") as WebGLRenderingContext | null)\n );\n } catch {\n return null;\n }\n}\n\n/**\n * Creates an AV encoder function that queues and encodes both mixed AudioData and VideoFrames.\n */\nexport function createAVEncoder(opts: {\n muxer: ReturnType<typeof recodemux>;\n canvas: OffscreenCanvas;\n outputAudio?: boolean;\n hasVideoTrack: boolean;\n timeSlice: number;\n fps: number;\n}) {\n const { canvas, outputAudio, muxer, hasVideoTrack, timeSlice } = opts;\n let frameCnt = 0;\n // GOP size: 3 seconds\n const gopSize = Math.floor(3 * opts.fps);\n\n // Resolve the WebGL context once — reused every frame.\n const gl = hasVideoTrack ? getCanvasGl(canvas) : null;\n\n const audioTrackBuf = createAudioTrackBuf(1024, opts.fps);\n\n return async (timestamp: number, audios: Float32Array[][], hasVideo: boolean) => {\n if (outputAudio !== false) {\n for (const audioData of audioTrackBuf(timestamp, audios)) {\n await muxer.encodeAudio(audioData);\n }\n }\n\n // Only encode video if we have video track AND we actually have video frames\n if (hasVideoTrack && hasVideo) {\n // Ensure canvas is in a valid state before creating VideoFrame\n // The canvas must have been rendered to at least once\n try {\n // gl.finish() flushes all pending GPU commands and blocks until the GPU\n // has completed them. Without this, on an *active* browser tab the WebGL\n // driver defers GPU completion to the next vsync cycle (~16.6 ms), making\n // VideoFrame creation implicitly wait for vsync. gl.finish() removes that\n // dependency so every frame is captured at full GPU speed — the same\n // behaviour you get naturally when the tab is backgrounded (vsync stops).\n if (gl != null && !gl.isContextLost()) {\n gl.finish();\n }\n\n const frame = new VideoFrame(canvas, {\n duration: timeSlice,\n timestamp: timestamp,\n });\n\n await muxer.encodeVideo(frame, {\n keyFrame: frameCnt % gopSize === 0,\n });\n\n frameCnt += 1;\n } catch (err) {\n // If canvas is not ready, skip this frame\n // This can happen if the canvas hasn't been rendered to yet\n console.warn(\"Failed to create VideoFrame from canvas, skipping frame:\", err);\n }\n }\n };\n}\n","import { Application, RenderTexture } from \"pixi.js\";\nimport { DEFAULT_AUDIO_CONF, getDefaultAudioConf, type IClip, Transition } from \"./clips\";\nimport { resolveEncodableAudio, type EncodableAudio } from \"./utils/audio-codec-detector\";\nimport { recodemux } from \"wrapbox\";\nimport { Log } from \"./utils/log\";\nimport EventEmitter from \"./event-emitter\";\nimport {\n clipToJSON,\n jsonToClip,\n type ClipJSON,\n type ProjectJSON,\n type GlobalTransitionJSON as TransitionJSON,\n} from \"./json-serialization\";\nimport { Video } from \"./clips/video-clip\";\nimport { Image } from \"./clips/image-clip\";\nimport { yieldToScheduler, waitEncoderQueue } from \"./compositor/scheduler\";\nimport { createSpritesRender } from \"./compositor/compositor-renderer\";\nimport { createAVEncoder } from \"./compositor/av-encoder\";\n\nexport interface ICompositorOpts {\n width?: number;\n height?: number;\n bitrate?: number;\n fps?: number;\n backgroundColor?: string;\n format?: string;\n videoCodec?: string;\n /**\n * If false, exclude audio track from the output video\n */\n audio?: false;\n audioCodec?: string;\n audioSampleRate?: number;\n /**\n * Write metadata tags to the output video\n */\n metaDataTags?: Record<string, string>;\n /**\n * Unsafe, may be deprecated at any time\n */\n __unsafe_hardwareAcceleration__?: HardwarePreference;\n}\n\nlet COM_ID = 0;\n\n/**\n * Video compositor that can add multiple {@link OffscreenSprite} instances,\n * @example\n * const spr1 = new OffscreenSprite(\n * new Video((await fetch('<mp4 url>')).body),\n * );\n * const spr2 = new OffscreenSprite(\n * await Audio.fromUrl('<audio url>'),\n * );\n * const com = new Compositor({ width: 1280, height: 720, });\n \n * await com.addSprite(spr1);\n * await com.addSprite(spr2);\n \n * com.output(); // => ReadableStream\n *\n */\nexport class Compositor extends EventEmitter<{\n \"export:progress\": number;\n error: Error;\n}> {\n /**\n * Check compatibility with the current environment\n * @param args.videoCodec Specify video codec, default avc1.42E032\n * @param args.width Specify video width, default 1920\n * @param args.height Specify video height, default 1080\n * @param args.bitrate Specify video bitrate, default 5e6\n */\n static async isSupported(\n args: {\n videoCodec?: string;\n width?: number;\n height?: number;\n bitrate?: number;\n } = {},\n ): Promise<boolean> {\n return (\n (self.OffscreenCanvas != null &&\n self.VideoEncoder != null &&\n self.VideoDecoder != null &&\n self.VideoFrame != null &&\n self.AudioEncoder != null &&\n self.AudioDecoder != null &&\n self.AudioData != null &&\n ((\n await self.VideoEncoder.isConfigSupported({\n codec: args.videoCodec ?? \"avc1.42E032\",\n width: args.width ?? 1920,\n height: args.height ?? 1080,\n bitrate: args.bitrate ?? 7e6,\n })\n ).supported ??\n false) &&\n (\n await self.AudioEncoder.isConfigSupported({\n codec: (await getDefaultAudioConf()).codec,\n sampleRate: DEFAULT_AUDIO_CONF.sampleRate,\n numberOfChannels: DEFAULT_AUDIO_CONF.channelCount,\n })\n ).supported) ??\n false\n );\n }\n\n private logger = Log.create(`id:${COM_ID++},`);\n\n private destroyed = false;\n\n private sprites: Array<IClip & { main: boolean; expired: boolean }> = [];\n\n private canvas: OffscreenCanvas;\n\n private pixiApp: Application | null = null;\n\n // Stop output\n private stopOutput: (() => void) | null = null;\n\n private opts: Required<ICompositorOpts>;\n /** Encodable audio chosen for output (undefined = not resolved yet, null = audio must be skipped) */\n private resolvedAudio: EncodableAudio | null | undefined = undefined;\n\n private explicitOpts: ICompositorOpts;\n\n private hasVideoTrack: boolean;\n\n // Original project dimensions from JSON (for scaling clips to export dimensions)\n private jsonDimensions: { width: number; height: number } = { width: 0, height: 0 };\n\n /**\n * Create a compositor instance based on configuration\n * @param opts ICompositorOpts\n */\n constructor(opts: ICompositorOpts = {}) {\n super();\n const { width = 0, height = 0 } = opts;\n this.canvas = new OffscreenCanvas(width, height);\n\n this.opts = Object.assign(\n {\n backgroundColor: \"#000\",\n width: 0,\n height: 0,\n format: \"mp4\",\n videoCodec: \"avc1.42E032\",\n audio: true,\n audioCodec: \"aac\",\n audioSampleRate: 48000,\n bitrate: 5e6,\n fps: 30,\n metaDataTags: null,\n },\n opts,\n );\n\n this.explicitOpts = { ...opts };\n\n this.hasVideoTrack = width * height > 0;\n\n // Initialize codec detection early\n getDefaultAudioConf().catch((err) => {\n this.logger.warn(\"Failed to detect audio codec:\", err);\n });\n }\n\n public async initPixiApp(): Promise<void> {\n const { width, height } = this.opts;\n this.pixiApp = new Application();\n await this.pixiApp.init({\n canvas: this.canvas as any,\n width,\n height,\n backgroundColor: 0x000000,\n antialias: false,\n autoDensity: false,\n resolution: 1,\n preference: \"webgl\", // Force WebGL to avoid WebGPU overhead/failures in Docker\n });\n\n // Verify that the app is fully initialized\n if (this.pixiApp.renderer == null || this.pixiApp.stage == null) {\n throw new Error(\"Pixi.js Application failed to initialize properly\");\n }\n\n // Stop the ticker - we manually call render() in the compositor\n // This prevents the ticker from trying to render after cleanup\n try {\n const anyApp = this.pixiApp as any;\n if (anyApp.ticker && typeof anyApp.ticker.stop === \"function\") {\n anyApp.ticker.stop();\n }\n } catch (e) {\n // ignore if ticker doesn't exist or can't be stopped\n }\n await this.resolveAudioEncoding();\n }\n\n /**\n * Settles which audio codec/sample rate output() will use, falling back when the requested one\n * isn't encodable here (e.g. no AAC encoder in headless Chromium). Called by initPixiApp and\n * loadFromJSON, which callers await before output().\n */\n private async resolveAudioEncoding(): Promise<void> {\n if (this.opts.audio === false) {\n this.resolvedAudio = undefined;\n return;\n }\n this.resolvedAudio = await resolveEncodableAudio(\n this.opts.audioCodec || DEFAULT_AUDIO_CONF.codecType,\n this.opts.audioSampleRate || DEFAULT_AUDIO_CONF.sampleRate,\n DEFAULT_AUDIO_CONF.channelCount,\n );\n }\n\n /**\n * Add a clip for video composition. Video duration defaults to the maximum duration value from all clips\n * @param clip Clip (extends BaseSprite)\n * @param opts.main If main is true, the video duration uses this clip's duration value\n */\n async addSprite(clip: IClip, opts: { main?: boolean } = {}): Promise<void> {\n const logAttrs = {\n rect: {\n x: clip.left,\n y: clip.top,\n w: clip.width,\n h: clip.height,\n },\n display: { ...clip.display },\n duration: clip.duration,\n playbackRate: clip.playbackRate,\n zIndex: clip.zIndex,\n };\n this.logger.info(\"Compositor add clip\", logAttrs);\n\n const cloned = await clip.clone();\n\n // Provide renderer to cloned clip if Pixi App is ready\n if (\n this.pixiApp != null &&\n this.pixiApp.renderer != null &&\n typeof cloned.setRenderer === \"function\"\n ) {\n cloned.setRenderer(this.pixiApp.renderer);\n }\n\n this.logger.info(\"Compositor add clip ready\");\n this.sprites.push(\n Object.assign(cloned, {\n main: opts.main ?? false,\n expired: false,\n }),\n );\n this.sprites.sort((a, b) => a.zIndex - b.zIndex);\n }\n\n private initMuxer(duration: number) {\n const {\n fps,\n width,\n height,\n videoCodec,\n bitrate,\n audio,\n metaDataTags,\n format,\n audioCodec,\n audioSampleRate,\n } = this.opts;\n\n // Check if any sprites actually have video capabilities (width > 0 && height > 0)\n // This handles cases where width/height are set but all sprites are audio-only\n const hasVideoSprites = this.sprites.some((sprite) => sprite.width > 0 && sprite.height > 0);\n\n // Only create video track if we have video track configured AND we have video sprites\n const shouldCreateVideoTrack = this.hasVideoTrack && hasVideoSprites;\n\n const muxer = recodemux({\n format: format || \"mp4\",\n video: shouldCreateVideoTrack\n ? {\n width,\n height,\n expectFPS: fps,\n codec: videoCodec,\n bitrate,\n __unsafe_hardwareAcceleration__: this.opts.__unsafe_hardwareAcceleration__,\n }\n : null,\n audio:\n audio === false || this.resolvedAudio === null\n ? null\n : {\n codec: this.resolvedAudio?.codecType ?? (audioCodec || DEFAULT_AUDIO_CONF.codecType),\n sampleRate: this.resolvedAudio?.sampleRate ?? (audioSampleRate || DEFAULT_AUDIO_CONF.sampleRate),\n channelCount: DEFAULT_AUDIO_CONF.channelCount,\n },\n duration,\n metaDataTags: metaDataTags,\n });\n return muxer;\n }\n\n /**\n * Output video file binary stream\n * @param opts.maxTime Maximum duration allowed for output video, content exceeding this will be ignored\n */\n output(opts: { maxTime?: number } = {}): ReadableStream<Uint8Array> {\n if (this.sprites.length === 0) throw Error(\"No sprite added\");\n\n const mainSprite = this.sprites.find((it) => it.main);\n // Max time: prefer main sprite, otherwise use maximum value\n // Filter out Infinity durations to avoid issues\n const durations = this.sprites.map((it) =>\n it.display.to > 0 ? it.display.to : it.display.from + it.duration,\n );\n const finiteDurations = durations.filter((d) => d !== Infinity);\n\n const maxTime =\n opts.maxTime ??\n (mainSprite != null\n ? mainSprite.display.to > 0\n ? mainSprite.display.to\n : mainSprite.display.from + mainSprite.duration\n : finiteDurations.length > 0\n ? Math.max(...finiteDurations)\n : 0);\n\n if (maxTime === Infinity || maxTime <= 0) {\n throw Error(\n \"Unable to determine the end time, please specify a main sprite, or limit the duration of Image, Audio\",\n );\n }\n // Main video's (main) videoTrack duration value is 0\n if (maxTime === -1) {\n this.logger.warn(\"Unable to determine the end time, process value don't update\");\n }\n\n this.logger.info(`start combinate video, maxTime:${maxTime}`);\n const muxer = this.initMuxer(maxTime);\n const startTime = performance.now();\n const stopMuxer = this.runEncoding(muxer, maxTime, {\n onProgress: (prog) => {\n this.logger.debug(\"export:progress:\", prog);\n this.emit(\"export:progress\", prog);\n },\n onEnded: async () => {\n await muxer.flush();\n this.logger.info(\"===== output ended =====, cost:\", performance.now() - startTime);\n this.emit(\"export:progress\", 1);\n this.destroy();\n },\n onError: (err) => {\n this.emit(\"error\", err);\n muxer.close();\n this.destroy();\n },\n });\n\n this.stopOutput = () => {\n stopMuxer();\n muxer.close();\n };\n\n return muxer.stream;\n }\n\n /**\n * Destroy instance and release resources\n */\n destroy() {\n if (this.destroyed) return;\n this.destroyed = true;\n\n this.stopOutput?.();\n this.off(\"export:progress\");\n this.off(\"error\");\n\n // Clean up Pixi.js resources\n if (this.pixiApp != null) {\n try {\n const anyApp = this.pixiApp as any;\n // Check if already destroyed\n if (anyApp.destroyed === true) {\n this.pixiApp = null;\n return;\n }\n // Stop ticker if present\n if (anyApp.ticker && typeof anyApp.ticker.stop === \"function\") {\n try {\n anyApp.ticker.stop();\n } catch (e) {\n // ignore\n }\n }\n // Only destroy if renderer exists and context is not lost\n if (anyApp.renderer != null) {\n // Check if WebGL context is lost\n const gl = anyApp.renderer.gl;\n if (gl && gl.isContextLost()) {\n // Context already lost, just clear reference\n this.pixiApp = null;\n return;\n }\n this.pixiApp.destroy();\n }\n } catch (err) {\n // Swallow errors during destroy - context may be lost or already destroyed\n // eslint-disable-next-line no-console\n console.warn(\"Error while destroying Pixi application:\", err);\n } finally {\n this.pixiApp = null;\n }\n }\n }\n\n private runEncoding(\n muxer: ReturnType<typeof recodemux>,\n maxTime: number,\n {\n onProgress,\n onEnded,\n onError,\n }: {\n onProgress: (prog: number) => void;\n onEnded: () => Promise<void>;\n onError: (err: Error) => void;\n },\n ): () => void {\n let progress = 0;\n const aborter = { aborted: false };\n let err: Error | null = null;\n let renderSprites: ReturnType<typeof createSpritesRender> | null = null;\n\n const run = async () => {\n const { fps, backgroundColor, audio: outputAudio } = this.opts;\n const timeSlice = Math.round(1e6 / fps);\n\n // Check if any sprites actually have video capabilities\n const hasVideoSprites = this.sprites.some((sprite) => sprite.width > 0 && sprite.height > 0);\n\n // Calculate scale from original project dimensions to export dimensions\n const jsonWidth = this.jsonDimensions.width || this.opts.width || 1920;\n const jsonHeight = this.jsonDimensions.height || this.opts.height || 1080;\n const scaleX = this.opts.width > 0 ? this.opts.width / jsonWidth : 1;\n const scaleY = this.opts.height > 0 ? this.opts.height / jsonHeight : 1;\n\n renderSprites = createSpritesRender({\n pixiApp: this.pixiApp,\n backgroundColor,\n sprites: this.sprites,\n aborter,\n scaleX,\n scaleY,\n });\n const encodeFrame = createAVEncoder({\n muxer,\n canvas: this.canvas,\n outputAudio,\n hasVideoTrack: this.hasVideoTrack && hasVideoSprites,\n timeSlice,\n fps,\n });\n\n let timestamp = 0;\n // Batch multiple frames between yields to reduce browser rendering\n // pipeline overhead.\n const FRAMES_PER_YIELD = 4;\n let framesSinceYield = 0;\n\n while (true) {\n if (err != null) return;\n if (\n aborter.aborted ||\n (maxTime === -1 ? false : timestamp > maxTime) ||\n this.sprites.length === 0\n ) {\n // # watch out for cuts in audio\n // await encodeFrame(timestamp, [], false);\n exit();\n await onEnded();\n return;\n }\n progress = timestamp / maxTime;\n\n const { audios, mainSprDone, hasVideo } = await renderSprites.render(timestamp);\n if (mainSprDone) {\n // # watch out for cuts in audio\n // await encodeFrame(timestamp, audios, hasVideo);\n exit();\n await onEnded();\n return;\n }\n\n if (aborter.aborted) return;\n\n // Yield to the scheduler periodically so the page stays responsive\n // and the GPU can flush.\n if (this.hasVideoTrack && hasVideo) {\n if (timestamp === 0) {\n // For the very first frame use a real setTimeout so the GPU has\n // time to finish shader compilation before we capture the canvas.\n await new Promise((resolve) => setTimeout(resolve, 50));\n framesSinceYield = 0;\n } else {\n framesSinceYield++;\n if (framesSinceYield >= FRAMES_PER_YIELD) {\n await yieldToScheduler();\n framesSinceYield = 0;\n }\n }\n }\n\n await encodeFrame(timestamp, audios, hasVideo);\n\n timestamp += timeSlice;\n\n await waitEncoderQueue(muxer.getEncodeQueueSize);\n }\n };\n\n const exit = () => {\n if (aborter.aborted) return;\n aborter.aborted = true;\n clearInterval(progressTimer);\n // Clean up sprite renderers first (removes sprites from Pixi stage)\n if (renderSprites != null) {\n renderSprites.cleanup();\n }\n // Then destroy all sprites\n this.sprites.forEach((it) => {\n it.destroy();\n });\n };\n\n run().catch((e) => {\n err = e;\n this.logger.error(e);\n exit();\n onError(e);\n });\n\n const progressTimer = setInterval(() => {\n onProgress(progress);\n }, 500);\n\n return exit;\n }\n\n /**\n * Export current compositor state to JSON\n */\n exportToJSON(): ProjectJSON {\n const clips: Record<string, ClipJSON> = {};\n for (const sprite of this.sprites) {\n clips[sprite.id] = clipToJSON(sprite, sprite.main);\n }\n\n const transitions: TransitionJSON[] = [];\n\n this.sprites.forEach((clip) => {\n if (clip.transition) {\n // Find predecessor on the same \"track\" (same zIndex)\n const prevClip = this.sprites\n .filter(\n (c) =>\n c.id !== clip.id &&\n c.zIndex === clip.zIndex &&\n c.display.from < clip.display.from &&\n (c instanceof Video || c instanceof Image),\n )\n .sort((a, b) => b.display.to - a.display.to)[0];\n\n if (prevClip) {\n transitions.push({\n key: clip.transition.name,\n duration: clip.transition.duration,\n clips: [prevClip.id, clip.id],\n });\n }\n }\n });\n\n return {\n clips,\n settings: {\n width: this.opts.width,\n height: this.opts.height,\n fps: this.opts.fps,\n backgroundColor: this.opts.backgroundColor,\n format: this.opts.format,\n videoCodec: this.opts.videoCodec,\n bitrate: this.opts.bitrate,\n audio: this.opts.audio,\n audioCodec: this.opts.audioCodec,\n audioSampleRate: this.opts.audioSampleRate,\n metaDataTags: this.opts.metaDataTags,\n },\n };\n }\n\n /**\n * Load clips from JSON\n * @param json The JSON project data\n */\n async loadFromJSON(json: ProjectJSON): Promise<void> {\n // Clear existing sprites\n this.sprites.forEach((sprite) => {\n sprite.destroy();\n });\n this.sprites = [];\n\n // Update settings if provided, but never overwrite options that were\n // explicitly passed to the constructor (e.g. user-chosen export settings).\n let dimensionsChanged = false;\n if (json.settings) {\n if (json.settings.width !== undefined && this.explicitOpts.width === undefined) {\n if (this.opts.width !== json.settings.width) dimensionsChanged = true;\n this.opts.width = json.settings.width;\n }\n if (json.settings.height !== undefined && this.explicitOpts.height === undefined) {\n if (this.opts.height !== json.settings.height) dimensionsChanged = true;\n this.opts.height = json.settings.height;\n }\n\n // Resize canvas and renderer if dimensions changed\n if (dimensionsChanged && this.opts.width > 0 && this.opts.height > 0) {\n this.canvas.width = this.opts.width;\n this.canvas.height = this.opts.height;\n if (this.pixiApp?.renderer) {\n this.pixiApp.renderer.resize(this.opts.width, this.opts.height);\n }\n }\n\n // Store original JSON dimensions for scaling clips during render\n if (json.settings.width && json.settings.height) {\n this.jsonDimensions = { width: json.settings.width, height: json.settings.height };\n }\n if (json.settings.fps !== undefined && this.explicitOpts.fps === undefined)\n this.opts.fps = json.settings.fps;\n if (\n json.settings.backgroundColor !== undefined &&\n this.explicitOpts.backgroundColor === undefined\n )\n this.opts.backgroundColor = json.settings.backgroundColor;\n if (json.settings.format !== undefined && this.explicitOpts.format === undefined)\n this.opts.format = json.settings.format;\n if (json.settings.videoCodec !== undefined && this.explicitOpts.videoCodec === undefined)\n this.opts.videoCodec = json.settings.videoCodec;\n if (json.settings.bitrate !== undefined && this.explicitOpts.bitrate === undefined)\n this.opts.bitrate = json.settings.bitrate;\n if (json.settings.audio !== undefined && this.explicitOpts.audio === undefined) {\n this.opts.audio = json.settings.audio === false ? false : (undefined as any);\n }\n if (json.settings.audioCodec !== undefined && this.explicitOpts.audioCodec === undefined)\n this.opts.audioCodec = json.settings.audioCodec;\n if (\n json.settings.audioSampleRate !== undefined &&\n this.explicitOpts.audioSampleRate === undefined\n )\n this.opts.audioSampleRate = json.settings.audioSampleRate;\n if (json.settings.metaDataTags !== undefined && this.explicitOpts.metaDataTags === undefined)\n this.opts.metaDataTags = json.settings.metaDataTags;\n }\n\n // Build map of clipId -> zIndex based on tracks\n const clipZIndices = new Map<string, number>();\n const mutedTrackClipIds = new Set<string>();\n if (json.tracks) {\n const totalTracks = json.tracks.length;\n json.tracks.forEach((track, trackIndex) => {\n if (track.clipIds) {\n for (const cid of track.clipIds) {\n // Track 0 -> Highest Z-index\n clipZIndices.set(cid, (totalTracks - trackIndex) * 10);\n if (track.muted) mutedTrackClipIds.add(cid);\n }\n }\n });\n }\n\n // Load all clips\n const clipsArray = Object.values(json.clips ?? {});\n\n for (const clipJSON of clipsArray) {\n const clip = await jsonToClip(clipJSON);\n\n // Apply zIndex from track order if available\n if (clipZIndices.has(clip.id)) {\n clip.zIndex = clipZIndices.get(clip.id)!;\n }\n if (mutedTrackClipIds.has(clip.id)) clip.trackMuted = true;\n\n await this.addSprite(clip, { main: clipJSON.main || false });\n }\n\n // Restore transition links on target clips and recalculate timing\n for (const clip of this.sprites) {\n if (clip instanceof Transition) {\n const fromClip = clip.fromClipId\n ? this.sprites.find((s) => s.id === clip.fromClipId)\n : null;\n const toClip = clip.toClipId ? this.sprites.find((s) => s.id === clip.toClipId) : null;\n\n // Recalculate transition timing based on actual clip positions\n // Transition should be centered at the junction between fromClip ending and toClip starting\n if (fromClip && toClip) {\n const toStart = toClip.display.from;\n\n // Transition is centered at the junction (overlap between fromClip ending and toClip starting)\n const transitionStart = Math.max(0, toStart - clip.duration / 2);\n const transitionEnd = transitionStart + clip.duration;\n // Update transition clip timing\n clip.display.from = transitionStart;\n clip.display.to = transitionEnd;\n }\n\n const transitionMeta = {\n name: clip.transitionKey,\n key: clip.transitionKey,\n duration: clip.duration,\n fromClipId: clip.fromClipId,\n toClipId: clip.toClipId,\n start: clip.display.from,\n end: clip.display.to,\n };\n\n if (fromClip) {\n (fromClip as any).transition = { ...transitionMeta };\n }\n\n if (toClip) {\n (toClip as any).transition = { ...transitionMeta };\n }\n }\n }\n await this.resolveAudioEncoding();\n }\n\n /**\n * Renders the frame at the given time and returns it as a base64-encoded PNG.\n *\n * Initialises the internal Pixi application on demand (if not already\n * initialised), performs a single-frame render using the same sprite\n * pipeline as {@link output}, and returns the result without modifying\n * the compositor's encoding state.\n *\n * @param timeMs Time in milliseconds\n * @param options.transparent If true, the renderer background is made\n * transparent so the resulting PNG has a transparent background.\n * @returns Base64 data-URL string (e.g. \"data:image/png;base64,...\")\n *\n * @example\n * const compositor = new Compositor({ width: 1280, height: 720 });\n * await compositor.addSprite(videoClip);\n * const frame = await compositor.renderFrame(2000); // frame at 2 s\n * const transparent = await compositor.renderFrame(2000, { transparent: true });\n */\n public async renderFrame(timeMs: number, options?: { transparent?: boolean }): Promise<string> {\n if (this.destroyed) {\n throw new Error(\"Compositor has been destroyed.\");\n }\n\n // Lazily initialise Pixi so callers don't have to call initPixiApp() first\n if (this.pixiApp == null) {\n await this.initPixiApp();\n }\n\n if (this.pixiApp == null) {\n throw new Error(\n \"Compositor Pixi application could not be initialised. \" +\n \"Ensure width and height are greater than 0.\",\n );\n }\n\n // Convert milliseconds → microseconds (internal timeline unit)\n const timeUs = timeMs * 1000;\n\n // Use the same rendering pipeline as the encoder, but for a single frame.\n // Sprites must NOT be marked expired before this call — use a fresh aborter.\n const jsonWidth = this.jsonDimensions.width || this.opts.width || 1920;\n const jsonHeight = this.jsonDimensions.height || this.opts.height || 1080;\n const spriteRender = createSpritesRender({\n pixiApp: this.pixiApp,\n backgroundColor: this.opts.backgroundColor,\n sprites: this.sprites,\n aborter: { aborted: false },\n scaleX: this.opts.width > 0 ? this.opts.width / jsonWidth : 1,\n scaleY: this.opts.height > 0 ? this.opts.height / jsonHeight : 1,\n });\n\n let base64: string;\n try {\n await spriteRender.render(timeUs);\n\n // Make the renderer background transparent when requested.\n const transparent = options?.transparent ?? false;\n const prevBgAlpha = this.pixiApp.renderer.background.alpha;\n if (transparent) {\n this.pixiApp.renderer.background.alpha = 0;\n }\n\n // Render into a fixed-size texture so the output always matches the\n // configured width × height, even when the stage's visible bounds would\n // otherwise shrink to only the content.\n const renderTexture = RenderTexture.create({\n width: this.opts.width,\n height: this.opts.height,\n });\n\n try {\n this.pixiApp.renderer.render({\n container: this.pixiApp.stage,\n target: renderTexture,\n clear: true,\n });\n base64 = await (this.pixiApp.renderer.extract as any).base64(renderTexture, \"image/png\", 1);\n } finally {\n renderTexture.destroy();\n if (transparent) {\n this.pixiApp.renderer.background.alpha = prevBgAlpha;\n }\n }\n } finally {\n // Clean up temporary containers / renderers created by createSpritesRender\n spriteRender.cleanup();\n }\n\n return base64;\n }\n\n /**\n * Alias for {@link renderFrame} with an optional timestamp.\n * Captures a single frame as a base64-encoded PNG.\n *\n * @param timeMs Optional time in milliseconds, or an options object. If\n * omitted, the first frame at time 0 is captured.\n * @param options.transparent If true, the renderer background is made\n * transparent so the resulting PNG has a transparent background.\n * @returns Base64 data-URL string (e.g. \"data:image/png;base64,...\")\n *\n * @example\n * const compositor = new Compositor({ width: 1280, height: 720 });\n * await compositor.addSprite(videoClip);\n * const firstFrame = await compositor.snapshot(); // time 0\n * const frameAt2s = await compositor.snapshot(2000); // explicit timestamp\n * const transparent = await compositor.snapshot({ transparent: true }); // time 0, transparent\n */\n public async snapshot(timeMs?: number | { transparent?: boolean }): Promise<string>;\n public async snapshot(\n timeMs?: number | { transparent?: boolean },\n options?: { transparent?: boolean },\n ): Promise<string> {\n const opts = typeof timeMs === \"number\" ? options : timeMs;\n const ms = typeof timeMs === \"number\" ? timeMs : undefined;\n return this.renderFrame(ms ?? 0, opts);\n }\n}\n","import type { Core, AnyClip, Patch } from \"@agrhub/core\";\nimport type { Studio } from \"./studio\";\nimport type { IClip, TrackCaptionConfig, ClipContext } from \"./clips\";\nimport { jsonToClip } from \"./json-serialization\";\nimport { fontManager } from \"./utils/fonts\";\n\n/**\n * StudioBridge - The \"Reconciler\" between Core and Studio.\n * Driven by Core patches, applied strictly in order (see enqueue) so async clip creation from an\n * older patch can never land after a newer rebuild.\n */\nexport class StudioBridge {\n private core: Core;\n private studio: Studio;\n\n constructor(core: Core, studio: Studio) {\n this.core = core;\n this.studio = studio;\n\n this.init();\n }\n\n /** Set while applying Core -> Studio changes, so Studio events they cause aren't echoed back */\n private isSyncing = false;\n private disposed = false;\n /** Serialises all patch work (each step awaits the previous) */\n private queue: Promise<void> = Promise.resolve();\n /** Bumped on full rebuilds: queued granular work from before a rebuild is skipped */\n private generation = 0;\n /** A full rebuild is queued but hasn't started (further requests coalesce into it) */\n private resyncQueued = false;\n /** Latest requested seek while one is running (scrubbing: latest wins, nothing is dropped) */\n private pendingSeek: number | null = null;\n private seekRunning = false;\n private unsubscribers: Array<() => void> = [];\n\n private async init() {\n await this.studio.ready;\n if (this.disposed) return;\n\n const onCore = (event: string, handler: (...args: any[]) => void) => {\n this.core.on(event as any, handler as any);\n this.unsubscribers.push(() => this.core.off(event as any, handler as any));\n };\n const onStudio = (event: any, handler: any) => {\n const off = this.studio.on(event, handler);\n this.unsubscribers.push(typeof off === \"function\" ? off : () => this.studio.off(event, handler));\n };\n\n // 1. Sync Playback (external seeks/scrubbing take precedence even while playing)\n onCore(\"timeupdate\", (time: number) => this.requestSeek(time));\n onCore(\"play\", () => this.guarded(() => this.studio.play()));\n onCore(\"pause\", () => this.guarded(() => this.studio.pause()));\n\n // 2. Sync Back from Studio to Core (Source of Truth)\n onStudio(\"currentTime\", ({ currentTime }: { currentTime: number }) => {\n if (this.studio.isPlaying && !this.isSyncing) {\n this.isSyncing = true;\n try {\n this.core.seek(currentTime);\n } finally {\n this.isSyncing = false;\n }\n }\n });\n\n // 3. Play/pause started from the Studio (e.g. its own controls) is mirrored to Core\n onStudio(\"play\", () => this.guarded(() => this.core.play()));\n onStudio(\"pause\", () => this.guarded(() => this.core.pause()));\n\n // 4. Selection Sync (Studio -> Core)\n const handleSelectionFromStudio = (data: { selected: any[] }) => {\n if (this.isSyncing) return;\n this.isSyncing = true;\n try {\n const ids = data.selected.map((c: any) => c.id);\n const currentSelectedIds = this.core.store.getState().selectedIds;\n if (JSON.stringify(ids) !== JSON.stringify(currentSelectedIds)) {\n this.core.store.getState().select(ids);\n }\n } finally {\n this.isSyncing = false;\n }\n };\n\n onStudio(\"selection:created\", handleSelectionFromStudio);\n onStudio(\"selection:updated\", handleSelectionFromStudio);\n onStudio(\"selection:cleared\", () => handleSelectionFromStudio({ selected: [] }));\n\n // 5. Sync via Patches (in order)\n onCore(\"change\", (patches: Patch[]) => this.onCoreChange(patches));\n\n // 6. Initial Sync\n await this.requestResync();\n }\n\n /** Runs fn unless a sync is already in progress (prevents Core <-> Studio echo loops) */\n private guarded(fn: () => void) {\n if (this.isSyncing) return;\n this.isSyncing = true;\n try {\n fn();\n } finally {\n this.isSyncing = false;\n }\n }\n\n private enqueue(task: () => Promise<void>): Promise<void> {\n const run = this.queue.then(async () => {\n if (this.disposed) return;\n try {\n await task();\n } catch (err) {\n console.error(\"[StudioBridge] Failed to apply Core changes:\", err);\n }\n });\n this.queue = run;\n return run;\n }\n\n /** Full rebuild from Core state; requests made before it starts share that one rebuild */\n private requestResync(): Promise<void> {\n this.generation += 1;\n if (this.resyncQueued) return this.queue;\n this.resyncQueued = true;\n return this.enqueue(async () => {\n this.resyncQueued = false;\n await this.syncInitialState();\n });\n }\n\n private requestSeek(time: number) {\n this.pendingSeek = time;\n if (this.seekRunning) return;\n this.seekRunning = true;\n void (async () => {\n try {\n while (this.pendingSeek != null && !this.disposed) {\n const next = this.pendingSeek;\n this.pendingSeek = null;\n const wasSyncing = this.isSyncing;\n this.isSyncing = true;\n try {\n await this.studio.transport.seek(next);\n } finally {\n this.isSyncing = wasSyncing;\n }\n }\n } finally {\n this.seekRunning = false;\n }\n })();\n }\n\n private syncSelectionToStudio(ids: string[]) {\n const currentStudioSelection = this.studio.selection.getSelection().map((c: any) => c.id);\n if (JSON.stringify(ids) !== JSON.stringify(currentStudioSelection)) {\n this.studio.selectClipsByIds(ids);\n }\n }\n\n private onCoreChange(patches: Patch[]) {\n // Only a root replacement needs a full rebuild. Settings (size, background, fps...) are applied\n // in place: rebuilding every clip whenever settings were re-assigned (even unchanged) caused\n // repeated decoder/texture churn and blank frames on episode reloads.\n if (patches.some((patch) => patch.path === \"/\")) {\n void this.requestResync();\n return;\n }\n const generation = this.generation;\n void this.enqueue(async () => {\n if (generation !== this.generation) return; // superseded by a rebuild queued after us\n await this.handlePatches(patches);\n });\n }\n\n private async handlePatches(patches: Patch[]) {\n\n for (const patch of patches) {\n const parts = patch.path.split(\"/\").filter(Boolean);\n\n // Handle Clips\n if (parts[0] === \"clips\") {\n const clipId = parts[1];\n if (patch.op === \"add\" && !parts[2]) {\n await this.handleAddClip(patch.value);\n } else if (patch.op === \"remove\" && !parts[2]) {\n await this.handleRemoveClip(clipId);\n } else if (patch.op === \"update\") {\n await this.handleUpdateClip(clipId, parts.slice(2), patch.value);\n }\n }\n\n // Handle Tracks\n if (parts[0] === \"tracks\") {\n await this.studio.setTracks(this.core.store.getState().tracks as any);\n }\n\n // Handle Settings (root \"/settings\" replacement or a single field)\n if (parts[0] === \"settings\") {\n const settings = this.core.store.getState().settings;\n if (this.studio.opts.width !== settings.width || this.studio.opts.height !== settings.height) {\n this.studio.setSize(settings.width, settings.height);\n }\n this.studio.updateFrame(this.core.store.getState().currentTime);\n }\n\n // Handle Selection\n if (parts[0] === \"selectedIds\") {\n this.syncSelectionToStudio(this.core.store.getState().selectedIds);\n }\n }\n }\n\n private getTrackCaptionConfig(clipId: string): TrackCaptionConfig | undefined {\n const tracks = this.core.store.getState().tracks;\n const parentTrack = tracks.find((t) => t.clipIds.includes(clipId));\n return (parentTrack as any)?.config?.captions ?? undefined;\n }\n\n private buildClipContext(coreClip: AnyClip): ClipContext | undefined {\n if (coreClip.type !== \"Caption\") return undefined;\n const captionConfig = this.getTrackCaptionConfig(coreClip.id);\n return captionConfig ? { captionConfig } : undefined;\n }\n\n private async handleAddClip(coreClip: AnyClip) {\n if (coreClip.type === \"Transition\") {\n await this.studio.addTransition(\n coreClip.transitionKey || \"none\",\n coreClip.duration,\n coreClip.fromClipId,\n coreClip.toClipId,\n coreClip.id, // Preserve core clip ID so removal by that ID works\n );\n } else {\n // Pre-load any font referenced by this clip before constructing the Pixi clip.\n // This ensures document.fonts is ready when refreshText() runs.\n const context = this.buildClipContext(coreClip);\n await this.ensureFontForClip(coreClip, context?.captionConfig);\n const clip = await jsonToClip(coreClip as any, context);\n const trackId = this.findTrackIdForClip(coreClip.id);\n await this.studio.addClip(clip, { trackId });\n }\n }\n\n private async handleRemoveClip(clipId: string) {\n const clip = this.studio.timeline.getClipById(clipId);\n if (clip) {\n await this.studio.removeClip(clip);\n }\n }\n\n private async handleUpdateClip(clipId: string, pathParts: string[], value: any) {\n const clip = this.studio.timeline.getClipById(clipId);\n if (!clip) return;\n\n // Simple property update\n if (pathParts.length === 0) {\n // Full clip update\n const wasLocked = clip.locked;\n const changed = this.syncClipProperties(clip, value);\n\n if (changed) {\n // If lock status changed and it's selected, refresh transformer\n if (wasLocked !== clip.locked && this.studio.selection.selectedClips.has(clip)) {\n this.studio.selection.recreateTransformer();\n }\n await this.studio.timeline.recalculateMaxDuration();\n this.studio.updateFrame(this.studio.currentTime);\n }\n } else {\n // Granular update (e.g. /clips/c1/left or /clips/c1/timing)\n const prop = pathParts[0];\n let changed = false;\n\n if (prop === \"timing\") {\n if (pathParts.length === 1) {\n if (value) {\n if (value.display) {\n clip.display = { ...value.display };\n }\n if (value.trim) {\n clip.trim = { ...value.trim };\n }\n if (value.duration !== undefined) {\n clip.duration = value.duration;\n }\n if (value.playbackRate !== undefined) {\n clip.playbackRate = value.playbackRate;\n }\n if (value.fadeIn !== undefined) {\n clip.timing.fadeIn = value.fadeIn;\n } else {\n delete clip.timing.fadeIn;\n }\n if (value.fadeOut !== undefined) {\n clip.timing.fadeOut = value.fadeOut;\n } else {\n delete clip.timing.fadeOut;\n }\n changed = true;\n }\n } else {\n const subProp = pathParts[1];\n if (subProp === \"display\") {\n clip.display = { ...value };\n changed = true;\n } else if (subProp === \"trim\") {\n clip.trim = { ...value };\n changed = true;\n } else if (subProp === \"duration\") {\n clip.duration = value;\n changed = true;\n } else if (subProp === \"playbackRate\") {\n clip.playbackRate = value;\n changed = true;\n } else if (subProp === \"fadeIn\") {\n if (value !== undefined) {\n clip.timing.fadeIn = value;\n } else {\n delete clip.timing.fadeIn;\n }\n changed = true;\n } else if (subProp === \"fadeOut\") {\n if (value !== undefined) {\n clip.timing.fadeOut = value;\n } else {\n delete clip.timing.fadeOut;\n }\n changed = true;\n }\n }\n } else if (prop === \"display\") {\n if (!clip.display || clip.display.from !== value.from || clip.display.to !== value.to) {\n clip.display = { ...value };\n changed = true;\n }\n } else if (prop === \"transform\") {\n if (pathParts.length === 1) {\n if (value) {\n if (value.x !== undefined && clip.left !== value.x) {\n clip.left = value.x;\n changed = true;\n }\n if (value.y !== undefined && clip.top !== value.y) {\n clip.top = value.y;\n changed = true;\n }\n if (value.width !== undefined && clip.width !== value.width) {\n clip.width = value.width;\n changed = true;\n }\n if (value.height !== undefined && clip.height !== value.height) {\n clip.height = value.height;\n changed = true;\n }\n if (value.angle !== undefined && clip.angle !== value.angle) {\n clip.angle = value.angle;\n changed = true;\n }\n if (value.opacity !== undefined && clip.opacity !== value.opacity) {\n clip.opacity = value.opacity;\n changed = true;\n }\n if (value.zIndex !== undefined && clip.zIndex !== value.zIndex) {\n clip.zIndex = value.zIndex;\n changed = true;\n }\n if (\n value.flip !== undefined &&\n JSON.stringify(clip.flip) !== JSON.stringify(value.flip)\n ) {\n clip.flip = value.flip;\n changed = true;\n }\n }\n } else {\n const subProp = pathParts[1];\n if (subProp === \"x\" && clip.left !== value) {\n clip.left = value;\n changed = true;\n } else if (subProp === \"y\" && clip.top !== value) {\n clip.top = value;\n changed = true;\n } else if (subProp === \"width\" && clip.width !== value) {\n clip.width = value;\n changed = true;\n } else if (subProp === \"height\" && clip.height !== value) {\n clip.height = value;\n changed = true;\n } else if (subProp === \"angle\" && clip.angle !== value) {\n clip.angle = value;\n changed = true;\n } else if (subProp === \"opacity\" && clip.opacity !== value) {\n clip.opacity = value;\n changed = true;\n } else if (subProp === \"zIndex\" && clip.zIndex !== value) {\n clip.zIndex = value;\n changed = true;\n } else if (subProp === \"flip\" && JSON.stringify(clip.flip) !== JSON.stringify(value)) {\n clip.flip = value;\n changed = true;\n }\n }\n } else {\n const wasLocked = clip.locked;\n const currentValue = (clip as any)[prop];\n\n if (currentValue !== value) {\n Object.assign(clip, { [prop]: value });\n\n if (\n prop === \"locked\" &&\n wasLocked !== value &&\n this.studio.selection.selectedClips.has(clip)\n ) {\n this.studio.selection.recreateTransformer();\n }\n changed = true;\n }\n }\n\n if (changed) {\n await this.studio.timeline.recalculateMaxDuration();\n this.studio.updateFrame(this.studio.currentTime);\n }\n }\n }\n\n private async syncInitialState() {\n // Serialised through the queue, so it never overlaps another rebuild or patch batch\n this.isSyncing = true;\n\n try {\n await this.studio.clear();\n const state = this.core.store.getState();\n this.studio.setSize(state.settings.width, state.settings.height);\n for (const id in state.clips) {\n await this.handleAddClip(state.clips[id]);\n }\n\n this.studio.setTracks(state.tracks as any);\n this.syncSelectionToStudio(state.selectedIds);\n\n this.studio.updateFrame(state.currentTime);\n } finally {\n this.isSyncing = false;\n }\n }\n\n private findTrackIdForClip(clipId: string): string | undefined {\n return this.core.store.getState().tracks.find((t) => t.clipIds.includes(clipId))?.id;\n }\n\n /**\n * Pre-load a font referenced by a clip's style.fontUrl (or top-level fontUrl).\n * Must be called before jsonToClip() so document.fonts is populated when\n * the Text constructor calls refreshText().\n */\n private async ensureFontForClip(coreClip: AnyClip, trackCaptionConfig?: any): Promise<void> {\n const style = (coreClip as any).style;\n // Clip style takes priority; fall back to track config style for lean caption clips\n const fontUrl =\n style?.fontUrl || trackCaptionConfig?.style?.fontUrl || (coreClip as any).fontUrl;\n const fontFamily =\n style?.fontFamily || trackCaptionConfig?.style?.fontFamily || (coreClip as any).fontFamily;\n if (!fontUrl || !fontFamily) return;\n try {\n await fontManager.addFont({ name: fontFamily, url: fontUrl });\n } catch (err) {\n console.warn(`[StudioBridge] Failed to pre-load font \"${fontFamily}\":`, err);\n }\n }\n\n private syncClipProperties(clip: IClip, coreClip: AnyClip): boolean {\n let changed = false;\n\n // Sync transform properties (Phase 2 / Modernized)\n const trans = coreClip.transform;\n if (trans) {\n if (trans.x !== undefined && Math.abs((clip.left ?? 0) - trans.x) >= 0.01) {\n clip.left = trans.x;\n changed = true;\n }\n if (trans.y !== undefined && Math.abs((clip.top ?? 0) - trans.y) >= 0.01) {\n clip.top = trans.y;\n changed = true;\n }\n if (trans.width !== undefined && Math.abs((clip.width ?? 0) - trans.width) >= 0.01) {\n clip.width = trans.width;\n changed = true;\n }\n if (trans.height !== undefined && Math.abs((clip.height ?? 0) - trans.height) >= 0.01) {\n clip.height = trans.height;\n changed = true;\n }\n if (trans.angle !== undefined && Math.abs((clip.angle ?? 0) - trans.angle) >= 0.01) {\n clip.angle = trans.angle;\n changed = true;\n }\n if (trans.opacity !== undefined && Math.abs((clip.opacity ?? 1) - trans.opacity) >= 0.01) {\n clip.opacity = trans.opacity;\n changed = true;\n }\n if (trans.zIndex !== undefined && clip.zIndex !== trans.zIndex) {\n clip.zIndex = trans.zIndex;\n changed = true;\n }\n if (trans.flip !== undefined && JSON.stringify(clip.flip) !== JSON.stringify(trans.flip)) {\n clip.flip = trans.flip;\n changed = true;\n }\n }\n\n // Legacy sync logic for other/fallback properties\n const props: (\n | keyof AnyClip\n | \"text\"\n | \"words\"\n | \"caption\"\n | \"textBoxStyle\"\n | \"wordsPerLine\"\n | \"videoWidth\"\n | \"videoHeight\"\n | \"muted\"\n | \"fontUrl\"\n | \"mediaId\"\n | \"bottomOffset\"\n | \"transitionKey\"\n | \"effectKey\"\n | \"values\"\n )[] = [\n \"volume\",\n \"text\",\n \"words\",\n \"style\",\n \"chromaKey\",\n \"colorAdjustment\",\n \"animations\",\n \"locked\",\n \"muted\",\n \"caption\",\n \"textBoxStyle\",\n \"wordsPerLine\",\n \"videoWidth\",\n \"videoHeight\",\n \"fontUrl\",\n \"mediaId\",\n \"bottomOffset\",\n \"transitionKey\",\n \"effectKey\",\n \"values\",\n ];\n props.forEach((prop) => {\n let newValue = (coreClip as any)[prop];\n // Boolean flags are omitted from the clip once cleared (e.g. after undo), so absence means false\n if (newValue === undefined && (prop === \"locked\" || prop === \"muted\")) newValue = false;\n if (newValue === undefined) return;\n\n const currentValue = (clip as any)[prop];\n\n // Equality check to avoid triggering setters\n if (currentValue === newValue) return;\n\n // Handle numeric precision for position/size\n if (typeof currentValue === \"number\" && typeof newValue === \"number\") {\n if (Math.abs(currentValue - newValue) < 0.01) return;\n }\n\n // Handle style, values, and caption (JSON check)\n if (prop === \"style\" || prop === \"values\" || prop === \"caption\") {\n if (JSON.stringify(currentValue) === JSON.stringify(newValue)) return;\n }\n\n Object.assign(clip, { [prop]: newValue });\n changed = true;\n });\n\n // Timing synchronization (Phase 1 Refactoring)\n const t = coreClip.timing;\n if (t) {\n if (t.display) {\n if (\n !clip.display ||\n clip.display.from !== t.display.from ||\n clip.display.to !== t.display.to\n ) {\n clip.display = { ...t.display };\n changed = true;\n }\n }\n if (t.trim) {\n if (!clip.trim || clip.trim.from !== t.trim.from || clip.trim.to !== t.trim.to) {\n clip.trim = { ...t.trim };\n changed = true;\n }\n }\n if (t.duration !== undefined) {\n if (clip.duration !== t.duration) {\n clip.duration = t.duration;\n changed = true;\n }\n }\n if (t.playbackRate !== undefined) {\n if (clip.playbackRate !== t.playbackRate) {\n clip.playbackRate = t.playbackRate;\n changed = true;\n }\n }\n if (t.fadeIn !== undefined) {\n if (JSON.stringify(clip.timing.fadeIn) !== JSON.stringify(t.fadeIn)) {\n clip.timing.fadeIn = t.fadeIn;\n changed = true;\n }\n } else if (clip.timing.fadeIn !== undefined) {\n delete clip.timing.fadeIn;\n changed = true;\n }\n if (t.fadeOut !== undefined) {\n if (JSON.stringify(clip.timing.fadeOut) !== JSON.stringify(t.fadeOut)) {\n clip.timing.fadeOut = t.fadeOut;\n changed = true;\n }\n } else if (clip.timing.fadeOut !== undefined) {\n delete clip.timing.fadeOut;\n changed = true;\n }\n } else {\n // Fallback legacy support\n const d = coreClip.display;\n if (d && (!clip.display || clip.display.from !== d.from || clip.display.to !== d.to)) {\n clip.display = { ...d };\n changed = true;\n }\n const trim = (coreClip as any).trim;\n if (trim && (!clip.trim || clip.trim.from !== trim.from || clip.trim.to !== trim.to)) {\n clip.trim = { ...trim };\n changed = true;\n }\n const duration = (coreClip as any).duration;\n if (duration !== undefined && clip.duration !== duration) {\n clip.duration = duration;\n changed = true;\n }\n const playbackRate = (coreClip as any).playbackRate;\n if (playbackRate !== undefined && clip.playbackRate !== playbackRate) {\n clip.playbackRate = playbackRate;\n changed = true;\n }\n }\n\n return changed;\n }\n\n public dispose() {\n // Remove only our own listeners: Core is shared with the timeline bridge and app code\n this.disposed = true;\n this.unsubscribers.forEach((off) => off());\n this.unsubscribers = [];\n }\n}\n","import { Graphics, type Rectangle } from \"pixi.js\";\n\nexport class Wireframe extends Graphics {\n constructor() {\n super();\n this.eventMode = \"static\";\n this.cursor = \"move\";\n }\n\n draw(bounds: Rectangle, scale: number = 1) {\n const color = 0x0284c7;\n const thickness = 1.5 * scale;\n\n this.clear();\n this.setStrokeStyle({ width: thickness, color })\n .rect(bounds.x, bounds.y, bounds.width, bounds.height)\n .stroke();\n\n this.hitArea = bounds;\n }\n}\n","import { type FederatedPointerEvent, Graphics, type Point, Rectangle, Circle } from \"pixi.js\";\n\nexport type Side = \"ml\" | \"mr\" | \"mt\" | \"mb\";\ntype Corner = \"tl\" | \"tr\" | \"bl\" | \"br\" | \"rot\" | \"rot_tl\" | \"rot_tr\" | \"rot_bl\" | \"rot_br\";\nexport type HandleKind = Corner | Side;\ninterface Callbacks {\n beginDrag: (handle: HandleKind, start: Point) => void;\n updateDrag: (handle: HandleKind, pos: Point) => void;\n endDrag: () => void;\n}\n\nexport class Handle extends Graphics {\n #isDragging = false;\n private handle: HandleKind;\n public cursor: string;\n private callbacks: Callbacks;\n\n constructor(handle: HandleKind, cursor: string, callbacks: Callbacks) {\n super();\n this.handle = handle;\n this.cursor = cursor;\n this.callbacks = callbacks;\n this.eventMode = \"static\";\n this.#draw();\n\n this.on(\"pointerdown\", this.#onDown);\n this.on(\"globalpointermove\", this.#onMove);\n this.on(\"pointerup\", this.#onUp);\n this.on(\"pointerupoutside\", this.#onUp);\n }\n\n #draw() {\n this.clear();\n const primaryColor = 0x0284c7;\n\n if (this.handle === \"rot_tl\") {\n this.hitArea = new Rectangle(-22, -22, 24, 24);\n } else if (this.handle === \"rot_tr\") {\n this.hitArea = new Rectangle(-2, -22, 24, 24);\n } else if (this.handle === \"rot_bl\") {\n this.hitArea = new Rectangle(-22, -2, 24, 24);\n } else if (this.handle === \"rot_br\") {\n this.hitArea = new Rectangle(-2, -2, 24, 24);\n } else if (this.handle === \"rot\") {\n // Draw rotation handle (circle with arrow)\n this.circle(0, 0, 8);\n this.fill({ color: \"#ffffff\" });\n this.stroke({ width: 1, color: 0xcccccc }); // Light grey border\n\n // Draw arrow icon inside\n // Draw arrow icon inside\n // Simple circular arrow icon using lines\n this.moveTo(0, -4);\n this.arc(0, 0, 4, -Math.PI / 2, Math.PI, false); // Half circle\n this.stroke({ width: 1, color: 0x000000 });\n\n // Arrowhead\n // Arrowhead\n this.moveTo(0, -8);\n this.lineTo(-3, -5);\n this.lineTo(0, -2);\n this.stroke({ width: 1, color: 0x000000, cap: \"round\", join: \"round\" });\n\n this.hitArea = new Circle(0, 0, 24);\n } else if ([\"ml\", \"mr\", \"mt\", \"mb\"].includes(this.handle)) {\n // Draw pill shape for side handles\n const isVertical = this.handle === \"ml\" || this.handle === \"mr\";\n const width = isVertical ? 6 : 24;\n const height = isVertical ? 24 : 6;\n this.roundRect(-width / 2, -height / 2, width, height, 3);\n this.fill({ color: \"#ffffff\" });\n this.stroke({ width: 1, color: primaryColor });\n this.hitArea = new Rectangle(-10, -10, 20, 20);\n } else {\n // Draw centered rectangle (8x8) for resizing handles (corners)\n this.rect(-4, -4, 8, 8);\n this.fill({ color: \"#ffffff\" });\n this.stroke({ width: 1, color: primaryColor });\n // Hit area should be larger than visual representation for better UX\n this.hitArea = new Rectangle(-10, -10, 20, 20);\n }\n }\n\n #onDown = (e: FederatedPointerEvent) => {\n this.#isDragging = true;\n if (!this.handle.startsWith(\"rot\")) {\n this.cursor = \"grabbing\";\n }\n this.callbacks.beginDrag(this.handle, e.global);\n };\n\n #onMove = (e: FederatedPointerEvent) => {\n if (!this.#isDragging) return;\n this.callbacks.updateDrag(this.handle, e.global);\n };\n\n #onUp = (_e: FederatedPointerEvent) => {\n if (!this.#isDragging) return;\n this.#isDragging = false;\n if (!this.handle.startsWith(\"rot\")) {\n this.cursor = \"pointer\";\n }\n this.callbacks.endDrag();\n };\n}\n","import type { Point, Rectangle } from \"pixi.js\";\n\nexport interface SnapGuide {\n type: \"vertical\" | \"horizontal\";\n position: number;\n // The line segment to draw to visualize the snap\n start: number;\n end: number;\n}\n\nexport interface SnapResult {\n x: number | null; // null if no snap\n y: number | null; // null if no snap\n guides: SnapGuide[];\n}\n\nexport class SnappingManager {\n static SNAP_THRESHOLD = 5;\n\n constructor(\n private artboardWidth: number,\n private artboardHeight: number,\n private scale: number = 1,\n ) {}\n\n updateContext(width: number, height: number, scale: number) {\n this.artboardWidth = width;\n this.artboardHeight = height;\n this.scale = scale;\n }\n\n /**\n * Snap a rectangle (bounds of the object) to artboard edges and center, as well as other objects.\n * returns delta (adjustment) needed for x and y\n */\n snapMove(\n current: Rectangle,\n otherBounds?: Rectangle[],\n ): { dx: number; dy: number; guides: SnapGuide[] } {\n const guides: SnapGuide[] = [];\n let dx = 0;\n let dy = 0;\n\n const threshold = SnappingManager.SNAP_THRESHOLD / this.scale;\n\n // X Axis Snapping\n\n // Targets: Center (W/2), Left (0), Right (W) - Center prioritized\n const targetsX: { value: number; label: string; boundsY?: [number, number] }[] = [\n { value: this.artboardWidth / 2, label: \"center\", boundsY: [0, this.artboardHeight] },\n { value: 0, label: \"start\", boundsY: [0, this.artboardHeight] },\n { value: this.artboardWidth, label: \"end\", boundsY: [0, this.artboardHeight] },\n ];\n\n if (otherBounds) {\n for (const ob of otherBounds) {\n targetsX.push(\n { value: ob.x, label: \"other-start\", boundsY: [ob.y, ob.y + ob.height] },\n { value: ob.x + ob.width / 2, label: \"other-center\", boundsY: [ob.y, ob.y + ob.height] },\n { value: ob.x + ob.width, label: \"other-end\", boundsY: [ob.y, ob.y + ob.height] },\n );\n }\n }\n\n // Points on object: Left, Center, Right\n const objectPointsX = [\n { value: current.x, type: \"start\" },\n { value: current.x + current.width / 2, type: \"center\" },\n { value: current.x + current.width, type: \"end\" },\n ];\n\n let snappedX = false;\n\n // Check for closest snap\n for (const target of targetsX) {\n if (snappedX) break;\n for (const objP of objectPointsX) {\n const diff = target.value - objP.value;\n if (Math.abs(diff) < threshold) {\n dx = diff;\n snappedX = true;\n\n const minTargetY = target.boundsY ? target.boundsY[0] : 0;\n const maxTargetY = target.boundsY ? target.boundsY[1] : this.artboardHeight;\n\n guides.push({\n type: \"vertical\",\n position: target.value,\n start: Math.min(minTargetY, current.y),\n end: Math.max(maxTargetY, current.y + current.height),\n });\n break;\n }\n }\n }\n\n // Y Axis Snapping\n const targetsY: { value: number; label: string; boundsX?: [number, number] }[] = [\n { value: this.artboardHeight / 2, label: \"center\", boundsX: [0, this.artboardWidth] },\n { value: 0, label: \"start\", boundsX: [0, this.artboardWidth] },\n { value: this.artboardHeight, label: \"end\", boundsX: [0, this.artboardWidth] },\n ];\n\n if (otherBounds) {\n for (const ob of otherBounds) {\n targetsY.push(\n { value: ob.y, label: \"other-start\", boundsX: [ob.x, ob.x + ob.width] },\n { value: ob.y + ob.height / 2, label: \"other-center\", boundsX: [ob.x, ob.x + ob.width] },\n { value: ob.y + ob.height, label: \"other-end\", boundsX: [ob.x, ob.x + ob.width] },\n );\n }\n }\n\n const objectPointsY = [\n { value: current.y, type: \"start\" },\n { value: current.y + current.height / 2, type: \"center\" },\n { value: current.y + current.height, type: \"end\" },\n ];\n\n let snappedY = false;\n\n for (const target of targetsY) {\n if (snappedY) break;\n for (const objP of objectPointsY) {\n const diff = target.value - objP.value;\n if (Math.abs(diff) < threshold) {\n dy = diff;\n snappedY = true;\n\n const minTargetX = target.boundsX ? target.boundsX[0] : 0;\n const maxTargetX = target.boundsX ? target.boundsX[1] : this.artboardWidth;\n\n guides.push({\n type: \"horizontal\",\n position: target.value,\n start: Math.min(minTargetX, current.x),\n end: Math.max(maxTargetX, current.x + current.width),\n });\n break;\n }\n }\n }\n\n return { dx, dy, guides };\n }\n\n /**\n * Snap during scaling - only snaps the moving edges based on the handle.\n * This prevents false triggers when stationary edges align with artboard edges.\n * @param proposed - The proposed rectangle in local coordinates\n * @param proposedWorld - The world position of the proposed rect's origin (top-left)\n * @param handle - Which resize handle is being dragged\n * @param otherBounds - Optional other clip bounds in parent space to snap to\n */\n snapResize(\n proposed: Rectangle,\n proposedWorld: Point,\n handle: \"tl\" | \"tr\" | \"bl\" | \"br\" | \"ml\" | \"mr\" | \"mt\" | \"mb\",\n otherBounds?: Rectangle[],\n ): {\n corrected: Rectangle;\n guides: SnapGuide[];\n } {\n const rect = proposed.clone();\n const guides: SnapGuide[] = [];\n const threshold = SnappingManager.SNAP_THRESHOLD / this.scale;\n\n // Artboard targets (in world coordinates)\n const targetsX: { value: number; label: string; boundsY?: [number, number] }[] = [\n { value: 0, label: \"start\", boundsY: [0, this.artboardHeight] },\n { value: this.artboardWidth / 2, label: \"center\", boundsY: [0, this.artboardHeight] },\n { value: this.artboardWidth, label: \"end\", boundsY: [0, this.artboardHeight] },\n ];\n const targetsY: { value: number; label: string; boundsX?: [number, number] }[] = [\n { value: 0, label: \"start\", boundsX: [0, this.artboardWidth] },\n { value: this.artboardHeight / 2, label: \"center\", boundsX: [0, this.artboardWidth] },\n { value: this.artboardHeight, label: \"end\", boundsX: [0, this.artboardWidth] },\n ];\n\n if (otherBounds) {\n for (const ob of otherBounds) {\n targetsX.push(\n { value: ob.x, label: \"other-start\", boundsY: [ob.y, ob.y + ob.height] },\n { value: ob.x + ob.width / 2, label: \"other-center\", boundsY: [ob.y, ob.y + ob.height] },\n { value: ob.x + ob.width, label: \"other-end\", boundsY: [ob.y, ob.y + ob.height] },\n );\n targetsY.push(\n { value: ob.y, label: \"other-start\", boundsX: [ob.x, ob.x + ob.width] },\n { value: ob.y + ob.height / 2, label: \"other-center\", boundsX: [ob.x, ob.x + ob.width] },\n { value: ob.y + ob.height, label: \"other-end\", boundsX: [ob.x, ob.x + ob.width] },\n );\n }\n }\n\n // Determine which edges are moving based on handle\n const movingLeft = [\"tl\", \"ml\", \"bl\"].includes(handle);\n const movingRight = [\"tr\", \"mr\", \"br\"].includes(handle);\n const movingTop = [\"tl\", \"mt\", \"tr\"].includes(handle);\n const movingBottom = [\"bl\", \"mb\", \"br\"].includes(handle);\n\n // Calculate world coordinates of the edges\n // proposedWorld is now in parent/artboard space (from localTransform.apply)\n // The localTransform already includes scale, so proposedWorld accounts for position + scale\n // For dimensions, we need to convert local width/height to parent space by multiplying by scale\n const worldLeft = proposedWorld.x;\n const worldTop = proposedWorld.y;\n const worldWidth = rect.width * this.scale;\n const worldHeight = rect.height * this.scale;\n const worldRight = worldLeft + worldWidth;\n const worldBottom = worldTop + worldHeight;\n\n // Snap horizontal edges (X-axis) - check against world coordinates\n for (const target of targetsX) {\n // Check left edge if moving\n if (movingLeft) {\n const diffWorld = target.value - worldLeft;\n if (Math.abs(diffWorld) < threshold) {\n // Convert world diff to local diff\n const diffLocal = diffWorld / this.scale;\n rect.x += diffLocal;\n rect.width -= diffLocal; // Keep right edge stationary\n\n const minTargetY = target.boundsY ? target.boundsY[0] : 0;\n const maxTargetY = target.boundsY ? target.boundsY[1] : this.artboardHeight;\n\n guides.push({\n type: \"vertical\",\n position: target.value,\n start: Math.min(minTargetY, worldTop),\n end: Math.max(maxTargetY, worldBottom),\n });\n break;\n }\n }\n // Check right edge if moving\n if (movingRight) {\n const diffWorld = target.value - worldRight;\n if (Math.abs(diffWorld) < threshold) {\n // Convert world diff to local diff\n const diffLocal = diffWorld / this.scale;\n rect.width += diffLocal;\n\n const minTargetY = target.boundsY ? target.boundsY[0] : 0;\n const maxTargetY = target.boundsY ? target.boundsY[1] : this.artboardHeight;\n\n guides.push({\n type: \"vertical\",\n position: target.value,\n start: Math.min(minTargetY, worldTop),\n end: Math.max(maxTargetY, worldBottom),\n });\n break;\n }\n }\n }\n\n // Snap vertical edges (Y-axis) - check against world coordinates\n for (const target of targetsY) {\n // Check top edge if moving\n if (movingTop) {\n const diffWorld = target.value - worldTop;\n if (Math.abs(diffWorld) < threshold) {\n // Convert world diff to local diff\n const diffLocal = diffWorld / this.scale;\n rect.y += diffLocal;\n rect.height -= diffLocal; // Keep bottom edge stationary\n\n const minTargetX = target.boundsX ? target.boundsX[0] : 0;\n const maxTargetX = target.boundsX ? target.boundsX[1] : this.artboardWidth;\n\n guides.push({\n type: \"horizontal\",\n position: target.value,\n start: Math.min(minTargetX, worldLeft),\n end: Math.max(maxTargetX, worldRight),\n });\n break;\n }\n }\n // Check bottom edge if moving\n if (movingBottom) {\n const diffWorld = target.value - worldBottom;\n if (Math.abs(diffWorld) < threshold) {\n // Convert world diff to local diff\n const diffLocal = diffWorld / this.scale;\n rect.height += diffLocal;\n\n const minTargetX = target.boundsX ? target.boundsX[0] : 0;\n const maxTargetX = target.boundsX ? target.boundsX[1] : this.artboardWidth;\n\n guides.push({\n type: \"horizontal\",\n position: target.value,\n start: Math.min(minTargetX, worldLeft),\n end: Math.max(maxTargetX, worldRight),\n });\n break;\n }\n }\n }\n\n return { corrected: rect, guides };\n }\n\n // Specialized resize snap that checks individual edges\n snapPoint(point: Point): { p: Point; guides: SnapGuide[] } {\n const threshold = SnappingManager.SNAP_THRESHOLD / this.scale;\n\n const guides: SnapGuide[] = [];\n const res = point.clone();\n\n // X\n const targetsX = [0, this.artboardWidth / 2, this.artboardWidth];\n for (const tx of targetsX) {\n if (Math.abs(tx - point.x) < threshold) {\n res.x = tx;\n guides.push({\n type: \"vertical\",\n position: tx,\n start: 0, // Simplified\n end: this.artboardHeight,\n });\n break;\n }\n }\n\n // Y\n const targetsY = [0, this.artboardHeight / 2, this.artboardHeight];\n for (const ty of targetsY) {\n if (Math.abs(ty - point.y) < threshold) {\n res.y = ty;\n guides.push({\n type: \"horizontal\",\n position: ty,\n start: 0,\n end: this.artboardWidth,\n });\n break;\n }\n }\n\n return { p: res, guides };\n }\n}\n","import {\n Container,\n Point,\n type FederatedPointerEvent,\n Rectangle,\n Matrix,\n Ticker,\n Graphics,\n Sprite,\n} from \"pixi.js\";\n\nimport { Wireframe } from \"./wireframe\";\nimport { type HandleKind, Handle } from \"./handle\";\nimport { SnappingManager, type SnapGuide } from \"./snapping\";\n\nconst TMP = {\n delta: new Matrix(),\n newLocal: new Matrix(),\n};\n\nexport class Transformer extends Container {\n group: Container[];\n wireframe = new Wireframe();\n selectionOutlines = new Graphics();\n isDragging = false;\n lastPointer = new Point();\n activeHandle: HandleKind | null = null;\n\n #handles: Record<string, Handle>;\n #childStart = new Map<Container, Matrix>();\n #pivotWorld = new Point();\n #angle = 0;\n #startAngle = 0;\n\n #opBounds = new Rectangle();\n #scalePivotLocal = new Point();\n #localBounds = new Rectangle();\n\n // Reusable points for selection bounds calculation to avoid GC\n #tmpQuad = [new Point(), new Point(), new Point(), new Point()];\n\n // Mid-point handle initial state to prevent jump at drag start\n #midHandleStartDist = 0;\n #midHandleStartDim = 0;\n\n #minW = 1;\n #minH = 1;\n\n #snappingManager: SnappingManager;\n #guidelines = new Graphics();\n #unsnappedPivotWorld = new Point();\n\n opts: {\n group: Container[];\n centeredScaling?: boolean;\n clip?: any;\n artboardWidth?: number;\n artboardHeight?: number;\n locked?: boolean;\n };\n\n constructor(opts: {\n group: Container[];\n centeredScaling?: boolean;\n clip?: any;\n artboardWidth?: number;\n artboardHeight?: number;\n locked?: boolean;\n }) {\n super();\n this.opts = opts;\n this.group = opts.group;\n this.eventMode = \"static\";\n\n this.#snappingManager = new SnappingManager(\n opts.artboardWidth ?? 1920,\n opts.artboardHeight ?? 1080,\n );\n this.addChild(this.#guidelines);\n\n const cb = {\n beginDrag: (h: HandleKind, s: Point) => this.#beginHandleDrag(h, s),\n updateDrag: (h: HandleKind, p: Point) => this.#updateDrag(h, p),\n endDrag: () => this.#endDrag(),\n };\n\n this.#handles = {\n tl: new Handle(\"tl\", \"nwse-resize\", cb),\n tr: new Handle(\"tr\", \"nesw-resize\", cb),\n bl: new Handle(\"bl\", \"nesw-resize\", cb),\n br: new Handle(\"br\", \"nwse-resize\", cb),\n ml: new Handle(\"ml\", \"ew-resize\", cb),\n mr: new Handle(\"mr\", \"ew-resize\", cb),\n mt: new Handle(\"mt\", \"ns-resize\", cb),\n mb: new Handle(\"mb\", \"ns-resize\", cb),\n rot_tl: new Handle(\"rot_tl\", \"crosshair\", {\n beginDrag: (_c, s) => this.#beginRotateDrag(s),\n updateDrag: (_c, p) => this.#rotate(p),\n endDrag: () => this.#endDrag(),\n }),\n rot_tr: new Handle(\"rot_tr\", \"crosshair\", {\n beginDrag: (_c, s) => this.#beginRotateDrag(s),\n updateDrag: (_c, p) => this.#rotate(p),\n endDrag: () => this.#endDrag(),\n }),\n rot_bl: new Handle(\"rot_bl\", \"crosshair\", {\n beginDrag: (_c, s) => this.#beginRotateDrag(s),\n updateDrag: (_c, p) => this.#rotate(p),\n endDrag: () => this.#endDrag(),\n }),\n rot_br: new Handle(\"rot_br\", \"crosshair\", {\n beginDrag: (_c, s) => this.#beginRotateDrag(s),\n updateDrag: (_c, p) => this.#rotate(p),\n endDrag: () => this.#endDrag(),\n }),\n };\n\n this.addChild(\n this.selectionOutlines,\n this.wireframe,\n this.#handles.rot_tl,\n this.#handles.rot_tr,\n this.#handles.rot_bl,\n this.#handles.rot_br,\n this.#handles.tl,\n this.#handles.tr,\n this.#handles.bl,\n this.#handles.br,\n this.#handles.ml,\n this.#handles.mr,\n this.#handles.mt,\n this.#handles.mb,\n );\n this.#bindEvents();\n\n // Hide initially to prevent FOUC (Flash of Unpositioned Content)\n this.visible = false;\n\n Ticker.shared.addOnce(() => {\n this.showImmediate();\n });\n }\n\n #initialized = false;\n /**\n * Immediately initialize bounds and show transformer.\n * Useful when we want to show it without waiting for the next tick.\n */\n public showImmediate() {\n if (this.#initialized || this.destroyed || !this.parent) return;\n this.#initBounds();\n this.visible = true;\n this.#initialized = true;\n }\n\n #bindEvents() {\n this.on(\"pointerdown\", this.#onDown);\n this.on(\"pointerup\", this.#onUp);\n this.on(\"pointerupoutside\", this.#onUp);\n this.on(\"globalpointermove\", this.#onMove);\n }\n\n #initBounds() {\n // Check if we have a single object - if so, use its transform directly\n if (this.group.length === 1) {\n const obj = this.group[0];\n\n // Use object's rotation\n this.#angle = obj.rotation;\n\n // Get \"content\" bounds (excluding shadows)\n const contentBounds = this.#getContentBounds(obj);\n\n // Set transformer's local bounds to match object's content dimensions\n // If we have a clip, it's safer to use its dimensions directly for the handles\n let width: number, height: number;\n if (this.opts.clip) {\n width = this.opts.clip.width;\n height = this.opts.clip.height;\n } else {\n width = contentBounds.width;\n height = contentBounds.height;\n }\n\n // Calculate global pivot based on the TRUE center of the object (ignoring shadow offset)\n // Since object's pivot is (0,0) (centered root), its global position is its center.\n const globalPos = obj.toGlobal(new Point(0, 0));\n this.#pivotWorld.set(globalPos.x, globalPos.y);\n\n // Set transformer's local bounds to be centered at origin\n this.#localBounds.copyFrom(new Rectangle(-width / 2, -height / 2, width, height));\n } else {\n // Multiple objects - use Local AABB relative to current transformer rotation\n // This preserves the tight bounding box even if the group is rotated\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n if (this.parent) {\n for (const item of this.group) {\n const b = this.#getContentBounds(item);\n\n this.#tmpQuad[0].set(b.x, b.y);\n this.#tmpQuad[1].set(b.x + b.width, b.y);\n this.#tmpQuad[2].set(b.x + b.width, b.y + b.height);\n this.#tmpQuad[3].set(b.x, b.y + b.height);\n\n for (const p of this.#tmpQuad) {\n // item local -> global -> transformer local\n item.toGlobal(p, p);\n this.toLocal(p, undefined, p);\n\n minX = Math.min(minX, p.x);\n minY = Math.min(minY, p.y);\n maxX = Math.max(maxX, p.x);\n maxY = Math.max(maxY, p.y);\n }\n }\n }\n\n const w = maxX - minX;\n const h = maxY - minY;\n const localCenterX = minX + w / 2;\n const localCenterY = minY + h / 2;\n\n // Center the local bounds\n this.#localBounds.copyFrom(new Rectangle(-w / 2, -h / 2, w, h));\n\n // Update Pivot to match the new center (converted to World space)\n if (this.parent) {\n const newGlobalPivot = this.toGlobal(new Point(localCenterX, localCenterY));\n this.#pivotWorld.set(newGlobalPivot.x, newGlobalPivot.y);\n }\n }\n\n this.#refresh();\n }\n\n /**\n * Helper to compute bounds of a container excluding children labeled \"ShadowContainer\"\n */\n /**\n * Helper to compute bounds of a container excluding children labeled \"ShadowContainer\"\n * Modified to handle nested AnimationContainer for stable wireframe rendering\n */\n #getContentBounds(container: Container): Rectangle {\n // 1. Try to find the MainSprite recursively or in known locations\n let mainSprite: Sprite | null = null;\n\n const findMainSprite = (c: Container): Sprite | null => {\n if (c.label === \"MainSprite\" && c instanceof Sprite) return c;\n for (const child of c.children) {\n if (child instanceof Container) {\n const found = findMainSprite(child);\n if (found) return found;\n }\n }\n return null;\n };\n\n mainSprite = findMainSprite(container);\n\n if (mainSprite) {\n const rawBounds = mainSprite.getLocalBounds();\n\n // If the clip uses animation padding (oversized texture for slide/zoom room),\n // the texture is larger than the logical clip bounds by 2*pad on each axis.\n // Shrink the bounds back to the logical size so the wireframe/handles stay correct.\n // Read from the container itself (mirrored there by PixiSpriteRenderer) so this\n // works correctly for both single and multi-selection without needing opts.clip.\n const animPad: number = (container as any).renderTexturePadding ?? 0;\n const b: { x: number; y: number; width: number; height: number } =\n animPad > 0\n ? new Rectangle(\n -(rawBounds.width - animPad * 2) / 2,\n -(rawBounds.height - animPad * 2) / 2,\n rawBounds.width - animPad * 2,\n rawBounds.height - animPad * 2,\n )\n : rawBounds;\n\n const t = mainSprite.localTransform.clone();\n\n const p1 = t.apply(new Point(b.x, b.y));\n const p2 = t.apply(new Point(b.x + b.width, b.y));\n const p3 = t.apply(new Point(b.x + b.width, b.y + b.height));\n const p4 = t.apply(new Point(b.x, b.y + b.height));\n\n const minX = Math.min(p1.x, p2.x, p3.x, p4.x);\n const maxX = Math.max(p1.x, p2.x, p3.x, p4.x);\n const minY = Math.min(p1.y, p2.y, p3.y, p4.y);\n const maxY = Math.max(p1.y, p2.y, p3.y, p4.y);\n\n return new Rectangle(minX, minY, maxX - minX, maxY - minY);\n }\n\n // Fallback: manual calculation for remaining content children, ignoring containers specifically\n let minX = Infinity,\n minY = Infinity,\n maxX = -Infinity,\n maxY = -Infinity;\n\n const contentChildren = container.children.filter(\n (child) => child.label !== \"ShadowContainer\" && child.label !== \"AnimationContainer\",\n );\n\n if (contentChildren.length === 0 && container.children.length > 0) {\n // If all filtered out, look inside AnimationContainer for raw bounds\n const animContainer = container.children.find(\n (c) => c.label === \"AnimationContainer\",\n ) as Container;\n if (animContainer) {\n const b = animContainer.getLocalBounds();\n return new Rectangle(b.minX, b.minY, b.maxX - b.minX, b.maxY - b.minY);\n }\n }\n\n for (const child of contentChildren) {\n const b = child.getBounds();\n const tl = container.toLocal(new Point(b.minX, b.minY));\n const br = container.toLocal(new Point(b.maxX, b.maxY));\n\n minX = Math.min(minX, tl.x, br.x);\n minY = Math.min(minY, tl.y, br.y);\n maxX = Math.max(maxX, tl.x, br.x);\n maxY = Math.max(maxY, tl.y, br.y);\n }\n\n if (minX === Infinity) {\n const b = container.getLocalBounds();\n return new Rectangle(b.minX, b.minY, b.maxX - b.minX, b.maxY - b.minY);\n }\n\n return new Rectangle(minX, minY, maxX - minX, maxY - minY);\n }\n\n /**\n * Public method to update transformer bounds without recreating it\n * Useful for updating bounds after clip dimensions change\n */\n updateBounds(): void {\n this.#initBounds();\n }\n\n #onDown = (e: FederatedPointerEvent) => {\n if (e.button !== 0) return; // Ignore right-clicks\n if (this.opts.locked) return; // Locked clips cannot be dragged\n // Refresh bounds/pivot to ensure we have the latest global position\n // (in case Artboard moved/zoomed since selection)\n this.#initBounds();\n this.#unsnappedPivotWorld.copyFrom(this.#pivotWorld);\n\n this.isDragging = true;\n this.lastPointer.copyFrom(e.global);\n this.cursor = \"grabbing\";\n };\n\n #onUp = () => {\n if (this.isDragging) {\n this.#endDrag();\n }\n this.cursor = \"default\";\n };\n\n #onMove = (e: FederatedPointerEvent) => {\n if (!this.isDragging || this.activeHandle || !this.parent) return;\n\n const { moveDx, moveDy, newPivotWorld } = this.#calculateSnappedMove(e);\n\n // Apply to objects\n for (const obj of this.group) {\n obj.x += moveDx;\n obj.y += moveDy;\n }\n\n this.#pivotWorld.copyFrom(newPivotWorld);\n this.lastPointer.copyFrom(e.global);\n this.#refresh();\n this.emit(\"transforming\");\n };\n\n #getOtherClipsBounds(): Rectangle[] {\n const boundsList: Rectangle[] = [];\n if (!this.parent) return boundsList;\n\n // Find ClipContainer\n const clipContainer = this.parent.children.find(\n (c) => c.label === \"ClipContainer\",\n ) as Container;\n if (!clipContainer) return boundsList;\n\n // Inside ClipContainer, find ClipsNormal and ClipsEffect\n const normalContainer = clipContainer.children.find(\n (c) => c.label === \"ClipsNormal\",\n ) as Container;\n const effectContainer = clipContainer.children.find(\n (c) => c.label === \"ClipsEffect\",\n ) as Container;\n\n const containers = [normalContainer, effectContainer].filter(Boolean);\n\n for (const container of containers) {\n for (const child of container.children) {\n if (this.group.includes(child) || !child.visible) {\n continue;\n }\n\n const b = this.#getContentBounds(child);\n\n // Convert local bounds of child to parent space\n const p1 = this.parent.toLocal(new Point(b.x, b.y), child);\n const p2 = this.parent.toLocal(new Point(b.x + b.width, b.y), child);\n const p3 = this.parent.toLocal(new Point(b.x + b.width, b.y + b.height), child);\n const p4 = this.parent.toLocal(new Point(b.x, b.y + b.height), child);\n\n const minX = Math.min(p1.x, p2.x, p3.x, p4.x);\n const maxX = Math.max(p1.x, p2.x, p3.x, p4.x);\n const minY = Math.min(p1.y, p2.y, p3.y, p4.y);\n const maxY = Math.max(p1.y, p2.y, p3.y, p4.y);\n\n boundsList.push(new Rectangle(minX, minY, maxX - minX, maxY - minY));\n }\n }\n\n return boundsList;\n }\n\n #calculateSnappedMove(e: FederatedPointerEvent) {\n const parentScale = Math.abs(this.parent!.worldTransform.a);\n\n // Update context\n this.#snappingManager.updateContext(\n this.opts.artboardWidth ?? 1920,\n this.opts.artboardHeight ?? 1080,\n parentScale,\n );\n\n // Calculate pure global mouse delta\n const dxGlobalMouse = e.global.x - this.lastPointer.x;\n const dyGlobalMouse = e.global.y - this.lastPointer.y;\n\n // Update the Virtual (Unsnapped) Pivot\n this.#unsnappedPivotWorld.x += dxGlobalMouse;\n this.#unsnappedPivotWorld.y += dyGlobalMouse;\n\n // Calculate Proposed Parent Position from Virtual Pivot\n const proposedParentPos = this.parent!.toLocal(this.#unsnappedPivotWorld);\n\n // Construct Proposed Bounds (centered at proposed position)\n const proposedBounds = new Rectangle(\n proposedParentPos.x + this.#localBounds.x,\n proposedParentPos.y + this.#localBounds.y,\n this.#localBounds.width,\n this.#localBounds.height,\n );\n\n // Check for Snaps\n const otherBounds = this.#getOtherClipsBounds();\n const {\n dx: snapDx,\n dy: snapDy,\n guides,\n } = this.#snappingManager.snapMove(proposedBounds, otherBounds);\n\n this.#drawGuides(guides, parentScale);\n\n // Calculate Final Target Position\n const finalParentPosX = proposedParentPos.x + snapDx;\n const finalParentPosY = proposedParentPos.y + snapDy;\n\n // Calculate Delta to apply to Objects\n const currentParentPos = this.parent!.toLocal(this.#pivotWorld);\n const moveDx = finalParentPosX - currentParentPos.x;\n const moveDy = finalParentPosY - currentParentPos.y;\n\n // Calculate New Global Pivot\n const newPivotWorld = this.parent!.toGlobal(new Point(finalParentPosX, finalParentPosY));\n\n return { moveDx, moveDy, newPivotWorld };\n }\n\n #beginHandleDrag(handle: HandleKind, start: Point) {\n this.#initBounds(); // Refresh pivot/bounds state\n this.isDragging = true;\n this.activeHandle = handle;\n\n this.#childStart.clear();\n\n for (const c of this.group) this.#childStart.set(c, c.localTransform.clone());\n\n this.rotation = this.#angle;\n this.#opBounds.copyFrom(this.#localBounds);\n\n this.#setScalePivot(handle);\n\n // For mid-point handles, store initial distance to prevent jump at drag start\n if ([\"ml\", \"mr\", \"mt\", \"mb\"].includes(handle)) {\n const pivot = this.#scalePivotLocal;\n const angle = this.rotation;\n const cos = Math.cos(angle);\n const sin = Math.sin(angle);\n const localStart = this.toLocal(start);\n const dx = localStart.x - pivot.x;\n const dy = localStart.y - pivot.y;\n\n if (handle === \"ml\" || handle === \"mr\") {\n this.#midHandleStartDist = dx * cos + dy * sin;\n this.#midHandleStartDim = this.#opBounds.width;\n } else {\n this.#midHandleStartDist = -dx * sin + dy * cos;\n this.#midHandleStartDim = this.#opBounds.height;\n }\n }\n }\n\n #updateDrag(handle: HandleKind, pos: Point) {\n this.#scale(handle, pos);\n }\n\n async #scale(handle: HandleKind, global: Point) {\n const { proposed, sx, sy, pivotWorld } = await this.#calculateSnappedScale(handle, global);\n\n // Check if we're transforming a Text or Caption\n const isTextClip = this.opts.clip && this.opts.clip.type === \"Text\";\n const isCaptionClip = this.opts.clip && this.opts.clip.type === \"Caption\";\n\n if (isTextClip || isCaptionClip) {\n this.emit(\"textClipResize\", {\n handle,\n newWidth: proposed.width,\n newHeight: proposed.height,\n pivotWorld,\n proposed,\n sx,\n sy,\n });\n } else {\n this.#applyWorldDelta(this.#deltaScale(pivotWorld, this.#angle, sx, sy));\n }\n\n this.#localBounds.copyFrom(proposed);\n this.#refresh();\n this.emit(\"transforming\");\n }\n\n async #calculateSnappedScale(handle: HandleKind, global: Point) {\n const pivotLocal = this.#scalePivotLocal;\n const parentScale = this.parent ? Math.abs(this.parent.worldTransform.a) : 1;\n\n // Mouse in parent space (artboard space) - this is the visual position we want to match\n const mouseParent = this.parent ? this.parent.toLocal(global) : global;\n\n // Convert mouse from parent space to transformer local space\n // The transformer's localTransform converts local -> parent, so we need to invert it\n let proposed: Rectangle;\n const localTransform = this.localTransform;\n const det = localTransform.a * localTransform.d - localTransform.b * localTransform.c;\n if (det !== 0) {\n const invDet = 1 / det;\n const dx = mouseParent.x - localTransform.tx;\n const dy = mouseParent.y - localTransform.ty;\n const mouseLocalX = (localTransform.d * dx - localTransform.b * dy) * invDet;\n const mouseLocalY = (-localTransform.c * dx + localTransform.a * dy) * invDet;\n const mouseLocal = new Point(mouseLocalX, mouseLocalY);\n\n proposed = this.#proposeScaledRect(handle, mouseLocal, pivotLocal);\n } else {\n proposed = this.#proposeScaledRect(handle, this.toLocal(global), pivotLocal);\n }\n\n // For resize snapping, use object scale (1) for dimensions, not parent zoom\n // parentScale is only needed for threshold and drawing guides\n const objectScale = 1;\n this.#snappingManager.updateContext(\n this.opts.artboardWidth ?? 1920,\n this.opts.artboardHeight ?? 1080,\n objectScale,\n );\n\n // Snap the proposed rectangle using snapResize (only snaps moving edges)\n // Only resize handles trigger snapping - rotation handles skip this\n const resizeHandles = [\"tl\", \"tr\", \"bl\", \"br\", \"ml\", \"mr\", \"mt\", \"mb\"] as const;\n if (resizeHandles.includes(handle as any)) {\n // Calculate proposed rect position in parent space (artboard space)\n // The transformer's localTransform converts local → parent\n const proposedParent = this.localTransform.apply(new Point(proposed.x, proposed.y));\n\n const otherBounds = this.#getOtherClipsBounds();\n const { corrected, guides } = this.#snappingManager.snapResize(\n proposed,\n proposedParent,\n handle as any,\n otherBounds,\n );\n this.#drawGuides(guides, parentScale);\n const sx = corrected.width / this.#opBounds.width;\n const sy = corrected.height / this.#opBounds.height;\n const pivotWorld = this.toGlobal(pivotLocal);\n return { proposed: corrected, sx, sy, pivotWorld };\n }\n\n const sx = proposed.width / this.#opBounds.width;\n const sy = proposed.height / this.#opBounds.height;\n const pivotWorld = this.toGlobal(pivotLocal);\n return { proposed, sx, sy, pivotWorld };\n }\n\n #beginRotateDrag(start: Point) {\n this.#initBounds(); // Refresh pivot/bounds state\n this.isDragging = true;\n this.activeHandle = \"rot\";\n this.#childStart.clear();\n for (const c of this.group) this.#childStart.set(c, c.localTransform.clone());\n this.#startAngle = Math.atan2(start.y - this.#pivotWorld.y, start.x - this.#pivotWorld.x);\n }\n\n #rotate(global: Point) {\n const now = Math.atan2(global.y - this.#pivotWorld.y, global.x - this.#pivotWorld.x);\n const da = now - this.#startAngle;\n const live = this.#angle + da;\n\n this.#applyWorldDelta(this.#deltaRotate(this.#pivotWorld, da));\n this.rotation = live;\n this.#refresh(live);\n this.emit(\"transforming\");\n }\n\n #endDrag() {\n this.isDragging = false;\n this.#angle = this.rotation;\n this.activeHandle = null;\n this.#guidelines.clear();\n this.#refresh(this.#angle);\n this.emit(\"transformEnd\");\n }\n\n #drawGuides(guides: SnapGuide[], scale: number) {\n this.#guidelines.clear();\n if (!guides.length || !this.parent) return;\n\n this.#guidelines.stroke({ width: 1 / scale, color: 0x48dbfb }); // Blue for guides\n\n for (const guide of guides) {\n // Create points in Parent Space\n let p1: Point, p2: Point;\n\n if (guide.type === \"vertical\") {\n p1 = new Point(guide.position, guide.start);\n p2 = new Point(guide.position, guide.end);\n } else {\n p1 = new Point(guide.start, guide.position);\n p2 = new Point(guide.end, guide.position);\n }\n\n // Convert to Local Space\n this.toLocal(p1, this.parent, p1);\n this.toLocal(p2, this.parent, p2);\n\n this.#guidelines\n .moveTo(p1.x, p1.y)\n .lineTo(p2.x, p2.y)\n .stroke({ width: 1 / scale, color: 0x48dbfb });\n }\n }\n\n #refresh(angle: number = this.#angle) {\n if (this.parent) this.position.copyFrom(this.parent.toLocal(this.#pivotWorld));\n this.rotation = angle;\n\n // Calculate handle scale based on parent's world scale\n const parentScale = this.parent ? Math.abs(this.parent.worldTransform.a) : 1;\n const handleScale = 1 / (parentScale || 1);\n\n const r = this.#localBounds;\n this.wireframe.draw(r, handleScale);\n\n const cx = r.x + r.width / 2;\n const cy = r.y + r.height / 2;\n\n // Get visible handles from clip (if available)\n // When locked, hide ALL handles - only show the wireframe outline\n const isLocked = this.opts.locked;\n const visibleHandles = isLocked\n ? []\n : (this.opts.clip?.getVisibleHandles?.() ?? [\n \"tl\",\n \"tr\",\n \"bl\",\n \"br\",\n \"ml\",\n \"mr\",\n \"mt\",\n \"mb\",\n \"rot\",\n ]);\n\n const handles = [\n this.#handles.tl,\n this.#handles.tr,\n this.#handles.bl,\n this.#handles.br,\n this.#handles.ml,\n this.#handles.mr,\n this.#handles.mt,\n this.#handles.mb,\n this.#handles.rot_tl,\n this.#handles.rot_tr,\n this.#handles.rot_bl,\n this.#handles.rot_br,\n ];\n\n for (const h of handles) {\n h.scale.set(handleScale);\n }\n\n const hasRot = visibleHandles.includes(\"rot\");\n\n // Set visibility based on clip's visible handles\n this.#handles.tl.visible = visibleHandles.includes(\"tl\");\n this.#handles.tr.visible = visibleHandles.includes(\"tr\");\n this.#handles.bl.visible = visibleHandles.includes(\"bl\");\n this.#handles.br.visible = visibleHandles.includes(\"br\");\n this.#handles.ml.visible = visibleHandles.includes(\"ml\");\n this.#handles.mr.visible = visibleHandles.includes(\"mr\");\n this.#handles.mt.visible = visibleHandles.includes(\"mt\");\n this.#handles.mb.visible = visibleHandles.includes(\"mb\");\n this.#handles.rot_tl.visible = hasRot;\n this.#handles.rot_tr.visible = hasRot;\n this.#handles.rot_bl.visible = hasRot;\n this.#handles.rot_br.visible = hasRot;\n\n this.#handles.tl.position.set(r.x, r.y);\n this.#handles.tr.position.set(r.x + r.width, r.y);\n this.#handles.bl.position.set(r.x, r.y + r.height);\n this.#handles.br.position.set(r.x + r.width, r.y + r.height);\n\n this.#handles.ml.position.set(r.x, cy);\n this.#handles.mr.position.set(r.x + r.width, cy);\n this.#handles.mt.position.set(cx, r.y);\n this.#handles.mb.position.set(cx, r.y + r.height);\n\n this.#handles.rot_tl.position.set(r.x, r.y);\n this.#handles.rot_tr.position.set(r.x + r.width, r.y);\n this.#handles.rot_bl.position.set(r.x, r.y + r.height);\n this.#handles.rot_br.position.set(r.x + r.width, r.y + r.height);\n\n // Dynamic rotation cursor generator\n const getRotationCursor = (cornerX: number, cornerY: number) => {\n const dx = cornerX - cx;\n const dy = cornerY - cy;\n const tangentAngle = Math.atan2(dx, -dy);\n const totalAngle = angle + tangentAngle;\n const angleDeg = Math.round((totalAngle * 180) / Math.PI) - 90;\n\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" viewBox=\"0 0 32 32\">\n <g transform=\"rotate(${angleDeg} 16 16)\">\n <path d=\"M 24 10 A 10 10 0 0 1 24 22\" fill=\"none\" stroke=\"white\" stroke-width=\"4\" stroke-linecap=\"round\"/>\n <path d=\"M 20 10 L 24 10 L 24 6\" fill=\"none\" stroke=\"white\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M 24 26 L 24 22 L 20 22\" fill=\"none\" stroke=\"white\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M 24 10 A 10 10 0 0 1 24 22\" fill=\"none\" stroke=\"black\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n <path d=\"M 20 10 L 24 10 L 24 6\" fill=\"none\" stroke=\"black\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M 24 26 L 24 22 L 20 22\" fill=\"none\" stroke=\"black\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </g>\n </svg>`;\n\n const encoded = encodeURIComponent(svg).replace(/'/g, \"%27\").replace(/\"/g, \"%22\");\n\n return `url('data:image/svg+xml;utf8,${encoded}') 16 16, auto`;\n };\n\n this.#handles.rot_tl.cursor = getRotationCursor(r.x, r.y);\n this.#handles.rot_tr.cursor = getRotationCursor(r.x + r.width, r.y);\n this.#handles.rot_bl.cursor = getRotationCursor(r.x, r.y + r.height);\n this.#handles.rot_br.cursor = getRotationCursor(r.x + r.width, r.y + r.height);\n\n // Update selection outlines\n this.#drawSelectionOutlines(handleScale);\n }\n\n /**\n * Draw individual bounding boxes for selected items\n * optimized to use cached points and avoid allocations\n */\n #drawSelectionOutlines(handleScale: number) {\n this.selectionOutlines.clear();\n\n // Only draw individual outlines if multiple clips are selected and we are valid\n if (this.group.length <= 1 || !this.parent) return;\n\n const strokeStyle = { width: 1 * handleScale, color: 0x00aaff, alpha: 1.0 };\n\n for (const item of this.group) {\n // Get content bounds (local to item)\n const b = this.#getContentBounds(item);\n\n // Setup corners in item local space using reused points\n // TL\n this.#tmpQuad[0].set(b.x, b.y);\n // TR\n this.#tmpQuad[1].set(b.x + b.width, b.y);\n // BR\n this.#tmpQuad[2].set(b.x + b.width, b.y + b.height);\n // BL\n this.#tmpQuad[3].set(b.x, b.y + b.height);\n\n // Transform to transformer local space in-place\n // item local -> global -> transformer local\n for (const p of this.#tmpQuad) {\n item.toGlobal(p, p);\n this.toLocal(p, undefined, p);\n }\n\n // Draw polygon using the transformed points\n this.selectionOutlines\n .moveTo(this.#tmpQuad[0].x, this.#tmpQuad[0].y)\n .lineTo(this.#tmpQuad[1].x, this.#tmpQuad[1].y)\n .lineTo(this.#tmpQuad[2].x, this.#tmpQuad[2].y)\n .lineTo(this.#tmpQuad[3].x, this.#tmpQuad[3].y)\n .closePath()\n .stroke(strokeStyle);\n }\n }\n\n // helpers\n\n #setScalePivot(handle: HandleKind) {\n const s = this.#opBounds;\n if (this.opts.centeredScaling) {\n this.#scalePivotLocal.set(s.x + s.width / 2, s.y + s.height / 2);\n return;\n }\n // For corners\n if (handle === \"tl\") this.#scalePivotLocal.set(s.x + s.width, s.y + s.height);\n else if (handle === \"tr\") this.#scalePivotLocal.set(s.x, s.y + s.height);\n else if (handle === \"bl\") this.#scalePivotLocal.set(s.x + s.width, s.y);\n else if (handle === \"br\") this.#scalePivotLocal.set(s.x, s.y);\n // For mid-point handles\n else if (handle === \"ml\") this.#scalePivotLocal.set(s.x + s.width, s.y + s.height / 2);\n else if (handle === \"mr\") this.#scalePivotLocal.set(s.x, s.y + s.height / 2);\n else if (handle === \"mt\") this.#scalePivotLocal.set(s.x + s.width / 2, s.y + s.height);\n else if (handle === \"mb\") this.#scalePivotLocal.set(s.x + s.width / 2, s.y);\n }\n\n #proposeScaledRect(handle: HandleKind, p: Point, pivot: Point) {\n let preserveRatio = false;\n if (this.opts.clip && (this.opts.clip.type === \"Image\" || this.opts.clip.type === \"Video\")) {\n preserveRatio = true;\n }\n\n if (this.opts.centeredScaling) {\n let w = Math.abs(p.x - pivot.x) * 2;\n let h = Math.abs(p.y - pivot.y) * 2;\n if (preserveRatio) {\n const origW = this.#opBounds.width;\n const origH = this.#opBounds.height;\n const ratio = origW / origH;\n if (w / origW > h / origH) {\n h = w / ratio;\n } else {\n w = h * ratio;\n }\n }\n w = Math.max(this.#minW, w);\n h = Math.max(this.#minH, h);\n return new Rectangle(pivot.x - w / 2, pivot.y - h / 2, w, h);\n }\n\n // Corner handles - scale in both dimensions\n if ([\"tl\", \"tr\", \"bl\", \"br\"].includes(handle)) {\n let newW = Math.abs(p.x - pivot.x);\n let newH = Math.abs(p.y - pivot.y);\n\n if (preserveRatio) {\n const origW = this.#opBounds.width;\n const origH = this.#opBounds.height;\n const ratio = origW / origH;\n if (newW / origW > newH / origH) {\n newH = newW / ratio;\n } else {\n newW = newH * ratio;\n }\n }\n\n newW = Math.max(this.#minW, newW);\n newH = Math.max(this.#minH, newH);\n\n if (handle === \"tl\") {\n return new Rectangle(pivot.x - newW, pivot.y - newH, newW, newH);\n }\n if (handle === \"tr\") {\n return new Rectangle(pivot.x, pivot.y - newH, newW, newH);\n }\n if (handle === \"bl\") {\n return new Rectangle(pivot.x - newW, pivot.y, newW, newH);\n }\n if (handle === \"br\") {\n return new Rectangle(pivot.x, pivot.y, newW, newH);\n }\n }\n\n // Mid-point handles - scale in one dimension only\n // When rotated, we need to project mouse movement onto the rotated axes\n const s = this.#opBounds;\n const angle = this.rotation;\n const cos = Math.cos(angle);\n const sin = Math.sin(angle);\n\n // Calculate pivot offset as ratio of original dimensions\n const pivotOffsetX = (pivot.x - s.x) / s.width;\n const pivotOffsetY = (pivot.y - s.y) / s.height;\n\n // Mouse position relative to pivot, projected onto rotated axes\n const dx = p.x - pivot.x;\n const dy = p.y - pivot.y;\n // Project onto rotated X axis (for width calculations)\n const distX = dx * cos + dy * sin;\n // Project onto rotated Y axis (for height calculations)\n const distY = -dx * sin + dy * cos;\n\n // Use delta from initial position for mid-point handles to prevent jump at drag start\n if (handle === \"ml\") {\n // Left edge moves, pivot is at right edge\n // Delta from initial: positive delta means dragging away from pivot (increasing width)\n const delta = this.#midHandleStartDist - distX; // Inverted because left moves opposite to right\n const newW = Math.max(this.#minW, this.#midHandleStartDim + delta);\n const newX = pivot.x - newW * pivotOffsetX;\n const newY = pivot.y - s.height * pivotOffsetY;\n return new Rectangle(newX, newY, newW, s.height);\n }\n if (handle === \"mr\") {\n // Right edge moves, pivot is at left edge\n // Delta from initial: positive delta means dragging away from pivot (increasing width)\n const delta = distX - this.#midHandleStartDist;\n const newW = Math.max(this.#minW, this.#midHandleStartDim + delta);\n const newX = pivot.x - newW * pivotOffsetX;\n const newY = pivot.y - s.height * pivotOffsetY;\n return new Rectangle(newX, newY, newW, s.height);\n }\n if (handle === \"mt\") {\n // Top edge moves, pivot is at bottom edge\n // Delta from initial: positive delta means dragging away from pivot (increasing height)\n const delta = this.#midHandleStartDist - distY; // Inverted because top moves opposite to bottom\n const newH = Math.max(this.#minH, this.#midHandleStartDim + delta);\n const newX = pivot.x - s.width * pivotOffsetX;\n const newY = pivot.y - newH * pivotOffsetY;\n return new Rectangle(newX, newY, s.width, newH);\n }\n if (handle === \"mb\") {\n // Bottom edge moves, pivot is at top edge\n // Delta from initial: positive delta means dragging away from pivot (increasing height)\n const delta = distY - this.#midHandleStartDist;\n const newH = Math.max(this.#minH, this.#midHandleStartDim + delta);\n const newX = pivot.x - s.width * pivotOffsetX;\n const newY = pivot.y - newH * pivotOffsetY;\n return new Rectangle(newX, newY, s.width, newH);\n }\n\n // Fallback (shouldn't reach here)\n return new Rectangle(pivot.x, pivot.y, this.#minW, this.#minH);\n }\n\n #deltaScale(pivotWorld: Point, angle: number, sx: number, sy: number) {\n return TMP.delta\n .identity()\n .translate(-pivotWorld.x, -pivotWorld.y)\n .rotate(-angle)\n .scale(sx, sy)\n .rotate(angle)\n .translate(pivotWorld.x, pivotWorld.y);\n }\n\n #deltaRotate(pivotWorld: Point, da: number) {\n return TMP.delta\n .identity()\n .translate(-pivotWorld.x, -pivotWorld.y)\n .rotate(da)\n .translate(pivotWorld.x, pivotWorld.y);\n }\n\n #applyWorldDelta(worldDelta: Matrix) {\n for (const c of this.group) {\n const start = this.#childStart.get(c);\n const parent = c.parent;\n if (!start || !parent) continue;\n const parentInv = parent.worldTransform.clone().invert();\n\n // Calculate Start Global Matrix\n // Pixi uses Row Vectors: v_world = v_local * M_local * M_parent ...\n // So World = Local * Parent\n // P.append(L) -> L * P\n const startWorld = parent.worldTransform.clone().append(start);\n\n // Apply Global Delta\n // NewGlobal = Global * Delta\n // D.append(G) -> G * D\n const newWorld = worldDelta.clone().append(startWorld);\n\n // Convert back to Local\n // NewLocal = NewGlobal * ParentInv\n // Inv.append(N) -> N * Inv\n const newLocal = parentInv.clone().append(newWorld);\n\n c.setFromMatrix(newLocal);\n }\n }\n}\n","import {\n type Application,\n type Container,\n Graphics,\n Point,\n Rectangle,\n type FederatedPointerEvent,\n} from \"pixi.js\";\nimport type { IClip } from \"../clips/iclip\";\nimport { Text } from \"../clips/text-clip\";\nimport { Caption } from \"../clips/caption-clip\";\nimport { Transformer } from \"../transformer/transformer\";\nimport type { Studio } from \"../studio\";\nimport { nanoid } from \"nanoid\";\n\nexport class SelectionManager {\n public selectedClips: Set<IClip> = new Set();\n public activeTransformer: Transformer | null = null;\n public interactiveClips: Set<IClip> = new Set(); // Track which clips have interactivity set up\n\n public getSelection(): IClip[] {\n return Array.from(this.selectedClips);\n }\n\n // Drag-to-select state\n public selectionGraphics: Graphics | null = null;\n public isDragSelecting = false;\n private dragSelectionStart = new Point();\n\n // Text/Caption realtime resize state\n private isUpdatingTextRealtime = false;\n private textClipResizedWidth: number | null = null;\n private textClipResizeHandle: string | null = null;\n private textClipResizedSx: number | null = null;\n private textClipResizedSy: number | null = null;\n\n // Double-click detection state\n private lastPointerDownTime = 0;\n private lastPointerDownClip: IClip | null = null;\n\n constructor(private studio: Studio) {}\n\n public init(app: Application, artboard: Container) {\n // Initialize Selection Graphics (for rubber band selection)\n this.selectionGraphics = new Graphics();\n this.selectionGraphics.visible = false;\n this.selectionGraphics.zIndex = 1000; // Ensure it's on top\n artboard.addChild(this.selectionGraphics);\n\n // Make stage interactive to handle clicks and drag selection\n app.stage.eventMode = \"static\";\n app.stage.hitArea = app.screen;\n\n app.stage.on(\"pointerdown\", (e) => this.onStagePointerDown(e));\n app.stage.on(\"globalpointermove\", (e) => this.onStagePointerMove(e));\n app.stage.on(\"pointerup\", () => this.onStagePointerUp());\n app.stage.on(\"pointerupoutside\", () => this.onStagePointerUp());\n }\n\n private onStagePointerDown(e: FederatedPointerEvent) {\n // Only start drag selection if clicking directly on stage (not on a child)\n // AND not initiating a transformer action (handled by transformer)\n if (e.target === this.studio.pixiApp?.stage) {\n // Clear selection first (standard behavior)\n if (!e.shiftKey) {\n this.deselectClip();\n }\n\n // Start drag selection\n this.isDragSelecting = true;\n // Convert global to artboard local space\n this.studio.artboard?.toLocal(e.global, undefined, this.dragSelectionStart);\n\n if (this.selectionGraphics) {\n this.selectionGraphics.clear();\n this.selectionGraphics.visible = true;\n }\n }\n }\n\n private onStagePointerMove(e: FederatedPointerEvent) {\n if (this.isDragSelecting && this.selectionGraphics && this.studio.artboard) {\n const currentPos = this.studio.artboard.toLocal(e.global);\n\n const x = Math.min(this.dragSelectionStart.x, currentPos.x);\n const y = Math.min(this.dragSelectionStart.y, currentPos.y);\n const width = Math.abs(currentPos.x - this.dragSelectionStart.x);\n const height = Math.abs(currentPos.y - this.dragSelectionStart.y);\n\n this.selectionGraphics.clear();\n // Semi-transparent blue fill\n this.selectionGraphics.rect(x, y, width, height).fill({ color: 0x0abde3, alpha: 0.3 });\n // Blue border\n this.selectionGraphics.rect(x, y, width, height).stroke({ width: 2, color: 0x0abde3 });\n\n // Calculate current selection bounds for real-time preview\n const bounds = this.selectionGraphics.getBounds();\n const selectionRect = new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height);\n\n if (selectionRect.width > 2 || selectionRect.height > 2) {\n const intersectingClips = this.getIntersectingClips(selectionRect);\n this.updatePreviewSelection(intersectingClips);\n } else {\n // If drag is too small, hide preview if we aren't shift-selecting\n if (this.selectedClips.size === 0) {\n this.destroyTransformer();\n }\n }\n\n // Always flush the marquee rectangle to screen, even when no clips are hit\n this.studio.pixiApp?.render();\n }\n }\n\n private onStagePointerUp() {\n if (this.isDragSelecting && this.selectionGraphics && this.studio.artboard) {\n // Finalize selection\n const bounds = this.selectionGraphics.getBounds();\n const selectionRect = new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height);\n\n if (selectionRect.width > 2 || selectionRect.height > 2) {\n const intersectingClips = this.getIntersectingClips(selectionRect);\n if (intersectingClips.length > 0) {\n // Batch select and refresh once\n for (const clip of intersectingClips) {\n this.selectedClips.add(clip);\n }\n this.recreateTransformer();\n\n this.studio.emit(\"selection:created\", {\n selected: Array.from(this.selectedClips),\n });\n } else if (this.selectedClips.size === 0) {\n // If we finished dragging but nothing was selected,\n // and we aren't adding to a selection, make sure it's gone\n this.destroyTransformer();\n }\n } else if (this.selectedClips.size === 0) {\n // Accidental micro-drag, ensure no stray preview remains\n this.destroyTransformer();\n }\n\n // Cleanup marquee\n this.selectionGraphics.clear();\n this.selectionGraphics.visible = false;\n this.isDragSelecting = false;\n this.studio.pixiApp?.render();\n }\n }\n\n /**\n * Find clips that intersect with the given selection rectangle\n */\n private getIntersectingClips(selectionRect: Rectangle): IClip[] {\n const intersectingClips: IClip[] = [];\n\n for (const clip of this.studio.clips) {\n const renderer = this.studio.spriteRenderers.get(clip);\n if (!renderer) continue;\n\n const root = renderer.getRoot();\n if (!root || !root.visible) continue;\n\n const clipBounds = root.getBounds();\n\n // Simple AABB intersection\n const intersects =\n selectionRect.x < clipBounds.x + clipBounds.width &&\n selectionRect.x + selectionRect.width > clipBounds.x &&\n selectionRect.y < clipBounds.y + clipBounds.height &&\n selectionRect.y + selectionRect.height > clipBounds.y;\n\n if (intersects) {\n intersectingClips.push(clip);\n }\n }\n\n return intersectingClips;\n }\n\n /**\n * Update the transformer to show a preview of what will be selected\n */\n private updatePreviewSelection(clips: IClip[]) {\n if (clips.length === 0) {\n // If we have an existing selection (e.g. shift-selecting), don't destroy it\n // but if we are just drag-selecting from scratch, hide it\n if (this.selectedClips.size === 0) {\n this.destroyTransformer();\n } else {\n // Just refresh the existing selection transformer\n this.recreateTransformer();\n }\n return;\n }\n\n // Combine preview clips with already selected clips if shift is held\n // (though drag-selection usually starts fresh unless we want to support additive drag)\n // For now, let's just show what IS in the marquee.\n const previewSet = new Set(clips);\n // If we want additive selection during drag, we could do:\n // for (const c of this.selectedClips) previewSet.add(c);\n\n const sprites: Container[] = [];\n let singleClip: IClip | null = null;\n\n for (const clip of previewSet) {\n const renderer = this.studio.spriteRenderers.get(clip);\n if (renderer == null) continue;\n\n const root = renderer.getRoot();\n if (root == null) continue;\n\n sprites.push(root);\n if (previewSet.size === 1) {\n singleClip = clip;\n }\n }\n\n if (sprites.length === 0) {\n if (this.selectedClips.size === 0) this.destroyTransformer();\n return;\n }\n\n if (this.activeTransformer) {\n this.activeTransformer.group = sprites;\n this.activeTransformer.opts.group = sprites;\n this.activeTransformer.opts.clip = singleClip;\n this.activeTransformer.updateBounds();\n this.activeTransformer.showImmediate();\n } else {\n // Create transformer (temp group)\n this.activeTransformer = new Transformer({\n group: sprites,\n clip: singleClip,\n artboardWidth: this.studio.opts.width,\n artboardHeight: this.studio.opts.height,\n });\n this.studio.artboard?.addChild(this.activeTransformer);\n this.activeTransformer.showImmediate();\n }\n\n this.studio.pixiApp?.render();\n }\n\n /**\n * Update root.hitArea to match logical clip dimensions.\n * Must be called after clip.width/height change (e.g. after text reflow or resize).\n */\n public refreshClipHitArea(clip: IClip): void {\n const renderer = this.studio.spriteRenderers.get(clip);\n if (renderer == null) return;\n const root = renderer.getRoot();\n if (root == null) return;\n // root is centered at (0,0), so hitArea is a centred rectangle\n root.hitArea = new Rectangle(-clip.width / 2, -clip.height / 2, clip.width, clip.height);\n }\n\n /**\n * Setup sprite interactivity for click selection\n */\n public setupSpriteInteractivity(clip: IClip): void {\n // Skip if already set up\n if (this.interactiveClips.has(clip)) return;\n\n const renderer = this.studio.spriteRenderers.get(clip);\n if (renderer == null) return;\n\n const root = renderer.getRoot();\n if (root == null) return;\n\n // Make sprite interactive\n root.eventMode = \"static\";\n root.cursor = \"pointer\";\n\n // Set hitArea to logical clip dimensions so Pixi's event system\n // doesn't use the padded texture bounds for hit detection.\n // root is centered (pivot at 0,0), so hitArea is centred too.\n this.refreshClipHitArea(clip);\n\n // Add click handler that selects the topmost clip at the click position\n root.on(\"pointerdown\", (e) => {\n const now = Date.now();\n const topmostClip = this.getTopmostClipAtPoint(e.global);\n\n // Detect double-click\n if (\n topmostClip === clip &&\n topmostClip === this.lastPointerDownClip &&\n now - this.lastPointerDownTime < 350\n ) {\n if (topmostClip.type === \"Text\" || topmostClip.type === \"Caption\") {\n this.studio.emit(\"clip:dblclick\", { clip: topmostClip });\n }\n }\n\n this.lastPointerDownTime = now;\n this.lastPointerDownClip = topmostClip;\n\n if (topmostClip) {\n // Select the topmost clip (pass shift key for multi-selection)\n this.selectClip(topmostClip, e.shiftKey);\n }\n\n // Don't stop propagation - let the event bubble up for transformer dragging\n });\n\n // Mark as interactive\n this.interactiveClips.add(clip);\n }\n\n /**\n * Find the topmost clip (highest zIndex) at a given point\n */\n public getTopmostClipAtPoint(globalPoint: { x: number; y: number }): IClip | null {\n if (!this.studio.pixiApp) return null;\n\n let topmostClip: IClip | null = null;\n let highestZIndex = -Infinity;\n\n // Check all interactive clips\n for (const clip of this.interactiveClips) {\n const renderer = this.studio.spriteRenderers.get(clip);\n if (!renderer) continue;\n\n const root = renderer.getRoot();\n if (!root || !root.visible) continue;\n\n const localPoint = root.toLocal(globalPoint);\n\n // Use logical clip dimensions for hit testing.\n // root.getLocalBounds() includes the animation padding (oversized texture),\n // which causes false positives in the transparent padding area.\n const hw = clip.width / 2;\n const hh = clip.height / 2;\n\n if (localPoint.x >= -hw && localPoint.x <= hw && localPoint.y >= -hh && localPoint.y <= hh) {\n // This clip contains the point, check if it has higher zIndex\n if (clip.zIndex > highestZIndex) {\n highestZIndex = clip.zIndex;\n topmostClip = clip;\n }\n }\n }\n\n return topmostClip;\n }\n\n /**\n * Select a clip and show transform controls\n */\n public selectClip(clip: IClip, addToSelection: boolean = false): void {\n if (this.studio.destroyed || this.studio.pixiApp == null) return;\n\n // If not adding to selection, clear current selection\n if (!addToSelection) {\n this.deselectClip();\n }\n\n // Toggle selection if Shift is held\n if (addToSelection && this.selectedClips.has(clip)) {\n // Remove from selection\n this.selectedClips.delete(clip);\n this.recreateTransformer();\n\n this.studio.emit(\"selection:updated\", {\n selected: Array.from(this.selectedClips),\n });\n this.studio.pixiApp?.render();\n return;\n }\n\n // Add to selection\n this.selectedClips.add(clip);\n this.recreateTransformer();\n\n if (addToSelection) {\n this.studio.emit(\"selection:updated\", {\n selected: Array.from(this.selectedClips),\n });\n } else {\n this.studio.emit(\"selection:created\", {\n selected: Array.from(this.selectedClips),\n });\n }\n this.studio.pixiApp?.render();\n }\n\n public selectClipsByIds(ids: string[]): void {\n const clipsToSelect = this.studio.clips.filter((c) => ids.includes(c.id));\n this.setSelection(clipsToSelect);\n }\n\n public setSelection(clips: IClip[]): void {\n if (this.studio.destroyed || this.studio.pixiApp == null) return;\n\n // Check if selection is effectively the same\n if (this.selectedClips.size === clips.length && clips.every((c) => this.selectedClips.has(c))) {\n return;\n }\n\n // Sync current selection before changing\n for (const clip of this.selectedClips) {\n this.syncSpriteToClipProperties(clip);\n }\n\n this.destroyTransformer();\n\n // Update selection\n this.selectedClips.clear();\n for (const clip of clips) {\n this.selectedClips.add(clip);\n }\n\n // Create new transformer\n if (this.selectedClips.size > 0) {\n this.createTransformer();\n this.studio.emit(\"selection:updated\", {\n selected: Array.from(this.selectedClips),\n });\n } else {\n this.studio.emit(\"selection:cleared\", { deselected: [] });\n }\n this.studio.pixiApp?.render();\n }\n\n public deselectClip(): void {\n if (this.selectedClips.size > 0) {\n for (const clip of this.selectedClips) {\n this.syncSpriteToClipProperties(clip);\n }\n }\n\n this.destroyTransformer();\n\n const deselected = Array.from(this.selectedClips);\n this.selectedClips.clear();\n\n if (deselected.length > 0) {\n this.studio.emit(\"selection:cleared\", { deselected });\n }\n this.studio.pixiApp?.render();\n }\n\n public async move(dx: number, dy: number) {\n if (this.selectedClips.size === 0) return;\n\n const updates: { id: string; updates: Partial<IClip> }[] = [];\n for (const clip of this.selectedClips) {\n updates.push({\n id: clip.id,\n updates: {\n left: (clip.left ?? 0) + dx,\n top: (clip.top ?? 0) + dy,\n },\n });\n }\n\n await this.studio.updateClips(updates);\n\n // Refresh transformer bounds if active\n if (this.activeTransformer) {\n this.activeTransformer.updateBounds();\n }\n }\n\n public clear() {\n this.deselectClip();\n this.interactiveClips.clear();\n }\n\n public recreateTransformer() {\n this.destroyTransformer();\n if (this.selectedClips.size > 0) {\n this.createTransformer();\n }\n }\n\n private destroyTransformer() {\n if (this.activeTransformer != null) {\n if (this.activeTransformer.parent != null) {\n this.activeTransformer.parent.removeChild(this.activeTransformer);\n }\n this.activeTransformer.destroy();\n this.activeTransformer = null;\n }\n }\n\n private createTransformer(): void {\n if (this.studio.destroyed || this.studio.artboard == null || this.selectedClips.size === 0)\n return;\n\n // Collect sprites from all selected clips\n const sprites: Container[] = [];\n let singleClip: IClip | null = null;\n\n for (const clip of this.selectedClips) {\n const renderer = this.studio.spriteRenderers.get(clip);\n if (renderer == null) continue;\n\n const root = renderer.getRoot();\n if (root == null) continue;\n\n sprites.push(root);\n if (this.selectedClips.size === 1) {\n singleClip = clip;\n }\n }\n\n if (sprites.length === 0) {\n console.warn(\"Cannot create transformer: no sprites found\");\n return;\n }\n\n // Create transformer\n const isLocked = singleClip?.locked ?? false;\n this.activeTransformer = new Transformer({\n group: sprites,\n clip: singleClip, // Only pass clip for single selection\n artboardWidth: this.studio.opts.width,\n artboardHeight: this.studio.opts.height,\n locked: isLocked,\n });\n\n // Listen for events\n let rafId: number | null = null;\n this.activeTransformer.on(\"transforming\", () => {\n if (rafId !== null) return;\n rafId = requestAnimationFrame(() => {\n rafId = null;\n this.syncSelectedClipsTransformsRealtime();\n\n // Emit for real-time sync to Core/UI with computed transform values\n for (const clip of this.selectedClips) {\n const renderer = this.studio.spriteRenderers.get(clip);\n if (!renderer) continue;\n const root = renderer.getRoot();\n if (!root) continue;\n\n // Compute current ephemeral transform values from Pixi root\n const flipFactor = clip.flip?.x || clip.flip?.y ? -1 : 1;\n const ephemeralAngle = flipFactor * root.angle;\n\n this.studio.emit(\"clip:transforming\", {\n clip,\n ephemeral: {\n left: clip.left,\n top: clip.top,\n width: clip.width,\n height: clip.height,\n angle: ephemeralAngle,\n scaleX: root.scale.x,\n scaleY: root.scale.y,\n },\n });\n }\n\n // Force render for real-time visual feedback\n this.studio.pixiApp?.render();\n });\n });\n\n this.activeTransformer.on(\"textClipResize\", (data: any) => {\n this.textClipResizedWidth = data.newWidth;\n this.textClipResizeHandle = data.handle;\n this.textClipResizedSx = data.sx;\n this.textClipResizedSy = data.sy;\n\n // Real-time text reflow during transform for live wrapping feedback\n const clip = this.selectedClips.size === 1 ? Array.from(this.selectedClips)[0] : null;\n if (clip instanceof Text && this.textClipResizedWidth !== null) {\n // Use fast layout update for real-time wrapping\n const newDims = clip.updateLayoutForWidth(this.textClipResizedWidth);\n // Update the transformer's proposed height to match auto-calculated height\n if (data.proposed && newDims.height !== data.proposed.height) {\n data.proposed.height = newDims.height;\n }\n }\n });\n\n this.activeTransformer.on(\"transformEnd\", async () => {\n if (rafId !== null) {\n cancelAnimationFrame(rafId);\n rafId = null;\n }\n\n const core = this.studio.opts.core;\n if (core) {\n // Collect updates for ALL selected clips\n const updatesList: { id: string; updates: any }[] = [];\n\n for (const clip of this.selectedClips) {\n const renderer = this.studio.spriteRenderers.get(clip);\n if (!renderer) continue;\n\n const root = renderer.getRoot();\n const sprite = renderer.getSprite();\n if (!root || !sprite || !sprite.texture) continue;\n\n const animPadC: number = clip.renderTexturePadding ?? 0;\n const textureWidth = sprite.texture.width - animPadC * 2;\n const textureHeight = sprite.texture.height - animPadC * 2;\n const newWidth = Math.abs(root.scale.x * sprite.scale.x) * textureWidth;\n const newHeight = Math.abs(root.scale.y * sprite.scale.y) * textureHeight;\n\n const updates: any = {\n left: root.x - newWidth / 2,\n top: root.y - newHeight / 2,\n width: newWidth,\n height: newHeight,\n angle: (clip.flip?.x || clip.flip?.y ? -1 : 1) * root.angle,\n };\n\n // Special case for Text/Caption reflow\n if (\n (clip.type === \"Text\" || clip.type === \"Caption\") &&\n this.textClipResizedWidth !== null\n ) {\n updates.width = this.textClipResizedWidth;\n // Note: height will be updated by the engine after reflow\n }\n\n updatesList.push({ id: clip.id, updates });\n }\n\n // Batch update via core\n if (updatesList.length > 0) {\n core.execute({\n id: nanoid(),\n type: \"clip.update\",\n payload: updatesList.length === 1 ? updatesList[0] : updatesList, // Handle batch vs single update if handler supports it\n });\n // Actually, our handler currently handles { id, updates }.\n // I should add a batch handler or a multi-update handler.\n }\n } else {\n // Fallback to legacy direct mutation if core is not present\n await this.syncSelectedClipsTransforms();\n }\n\n for (const clip of this.selectedClips) {\n this.studio.emit(\"clip:updated\", { clip });\n }\n this.studio.emit(\"transform:end\", {\n transformer: this.activeTransformer!,\n });\n });\n\n this.activeTransformer.on(\"pointerdown\", (e: any) => {\n if (e.button !== 0) return;\n this.studio.emit(\"transform:start\", {\n transformer: this.activeTransformer!,\n });\n // If a handle is currently active (being clicked/dragged), do not select clips underneath\n if (this.activeTransformer?.activeHandle !== null) {\n return;\n }\n\n const topmostClip = this.getTopmostClipAtPoint(e.global);\n\n const now = Date.now();\n if (\n topmostClip &&\n topmostClip === this.lastPointerDownClip &&\n now - this.lastPointerDownTime < 350\n ) {\n if (topmostClip.type === \"Text\" || topmostClip.type === \"Caption\") {\n this.studio.emit(\"clip:dblclick\", { clip: topmostClip });\n }\n }\n this.lastPointerDownTime = now;\n this.lastPointerDownClip = topmostClip;\n\n if (topmostClip && !this.selectedClips.has(topmostClip)) {\n this.selectClip(topmostClip, e.shiftKey);\n e.stopPropagation();\n }\n });\n\n this.studio.artboard.addChild(this.activeTransformer);\n this.activeTransformer.showImmediate();\n this.studio.pixiApp?.render();\n }\n\n // Copied Sync Logic\n private async syncSelectedClipsTransformsRealtime(): Promise<void> {\n if (this.selectedClips.size === 0 || this.activeTransformer == null) return;\n\n const activeHandle = this.activeTransformer.activeHandle;\n\n // Handle standard move (dragging the whole clip)\n if (activeHandle === null) {\n for (const clip of this.selectedClips) {\n const renderer = this.studio.spriteRenderers.get(clip);\n if (renderer == null) continue;\n\n const root = renderer.getRoot();\n const sprite = renderer.getSprite();\n if (root == null || sprite == null || sprite.texture == null) continue;\n\n // Sync clip position based on root position\n // Since root pivot is centered, clip.left = root.x - clip.width / 2\n // Subtract animation padding from texture dimensions to get true logical clip size.\n const animPad: number = clip.renderTexturePadding ?? 0;\n const logicalTexW = sprite.texture.width - animPad * 2;\n const logicalTexH = sprite.texture.height - animPad * 2;\n const logicalWidth = Math.abs(root.scale.x * sprite.scale.x) * logicalTexW;\n const logicalHeight = Math.abs(root.scale.y * sprite.scale.y) * logicalTexH;\n clip.left = root.x - logicalWidth / 2;\n clip.top = root.y - logicalHeight / 2;\n // Note: ephemeral transform values (including angle) are computed and passed\n // in the clip:transforming event, not stored on the clip object to avoid feedback loops\n }\n return;\n }\n\n // Handle side-resize for Text/Caption\n if (activeHandle === \"mr\" || activeHandle === \"ml\") {\n if (this.isUpdatingTextRealtime) return;\n this.isUpdatingTextRealtime = true;\n\n try {\n for (const clip of this.selectedClips) {\n if (!(clip instanceof Text)) continue;\n\n const renderer = this.studio.spriteRenderers.get(clip);\n if (renderer == null) continue;\n\n const root = renderer.getRoot();\n const sprite = renderer.getSprite();\n if (root == null || sprite == null || sprite.texture == null) continue;\n\n const currentScaleX = Math.abs(root.scale.x * sprite.scale.x);\n if (currentScaleX === 1.0) continue;\n\n const preservedLeft = clip.left;\n const preservedTop = clip.top;\n const preservedWidth = clip.width;\n const animPadT: number = clip.renderTexturePadding ?? 0;\n const textureWidth = sprite.texture.width - animPadT * 2;\n const newWidth = currentScaleX * textureWidth;\n\n await clip.updateStyle({\n wordWrap: true,\n wordWrapWidth: newWidth,\n });\n\n const newTexture = await clip.getTexture();\n if (newTexture) {\n await renderer.updateFrame(newTexture);\n sprite.scale.set(1, 1);\n root.scale.set(1, 1);\n\n if (activeHandle === \"ml\") {\n clip.left = preservedLeft + preservedWidth - clip.width;\n } else {\n clip.left = preservedLeft;\n }\n clip.top = preservedTop;\n\n root.x = clip.left + clip.width / 2;\n root.y = clip.top + clip.height / 2;\n\n this.activeTransformer.updateBounds();\n this.refreshClipHitArea(clip);\n }\n }\n } finally {\n this.isUpdatingTextRealtime = false;\n }\n }\n }\n\n private async syncSelectedClipsTransforms(): Promise<void> {\n if (this.selectedClips.size === 0 || this.activeTransformer == null) return;\n\n for (const clip of this.selectedClips) {\n const renderer = this.studio.spriteRenderers.get(clip);\n if (renderer == null) continue;\n\n const root = renderer.getRoot();\n const sprite = renderer.getSprite();\n if (root == null || sprite == null || sprite.texture == null) continue;\n\n const animPadS: number = clip.renderTexturePadding ?? 0;\n const textureWidth = sprite.texture.width - animPadS * 2;\n const textureHeight = sprite.texture.height - animPadS * 2;\n const newWidth = Math.abs(root.scale.x * sprite.scale.x) * textureWidth;\n const newHeight = Math.abs(root.scale.y * sprite.scale.y) * textureHeight;\n\n const finalNewWidth =\n (clip instanceof Text || clip instanceof Caption) && this.textClipResizedWidth !== null\n ? this.textClipResizedWidth\n : newWidth;\n\n const oldWidth = clip.width;\n const oldFontSize = (clip as any).style?.fontSize ?? 16;\n const newFontSize =\n oldFontSize * Math.max(this.textClipResizedSx || 1, this.textClipResizedSy || 1);\n\n // position calculation\n // root is center.\n let newRootX = root.x;\n\n const isReflowableTextClip =\n (clip instanceof Text || clip instanceof Caption) && this.textClipResizedWidth !== null;\n\n if (isReflowableTextClip) {\n const styleUpdate: any = {\n wordWrap: true,\n wordWrapWidth: finalNewWidth,\n };\n\n if (this.textClipResizeHandle === \"mr\") {\n newRootX = clip.left + finalNewWidth / 2;\n root.x = newRootX;\n } else if (this.textClipResizeHandle === \"ml\") {\n newRootX = clip.left + finalNewWidth / 2 - (finalNewWidth - oldWidth);\n root.x = newRootX;\n } else if ([\"br\", \"tr\"].includes(this.textClipResizeHandle!)) {\n newRootX = clip.left + finalNewWidth / 2;\n styleUpdate.fontSize = newFontSize;\n } else if ([\"bl\", \"tl\"].includes(this.textClipResizeHandle!)) {\n newRootX = clip.left + finalNewWidth / 2 - (finalNewWidth - oldWidth);\n styleUpdate.fontSize = newFontSize;\n }\n\n await clip.updateStyle(styleUpdate);\n const newTexture = await clip.getTexture();\n\n if (newTexture) {\n await renderer.updateFrame(newTexture);\n clip.width = finalNewWidth;\n const reflowAnimPad: number = clip.renderTexturePadding ?? 0;\n clip.height = newTexture.height - reflowAnimPad * 2;\n this.textClipResizedWidth = null;\n\n clip.left = newRootX - clip.width / 2;\n clip.top = root.y - clip.height / 2;\n\n sprite.scale.set(1, 1);\n root.scale.set(1, 1);\n }\n } else {\n const logicalWidth = newWidth;\n const logicalHeight = newHeight;\n\n clip.left = root.x - logicalWidth / 2;\n clip.top = root.y - logicalHeight / 2;\n clip.width = logicalWidth;\n clip.height = logicalHeight;\n\n const flipFactor = clip.flip?.x || clip.flip?.y ? -1 : 1;\n clip.angle = flipFactor * root.angle;\n }\n }\n\n if (this.activeTransformer != null) {\n this.activeTransformer.updateBounds();\n }\n\n for (const clip of this.selectedClips) {\n const renderer = this.studio.spriteRenderers.get(clip);\n if (renderer != null) {\n renderer.updateTransforms();\n }\n this.refreshClipHitArea(clip);\n }\n }\n\n private syncSpriteToClipProperties(clip: IClip): void {\n // Same logic as Studio\n const renderer = this.studio.spriteRenderers.get(clip);\n if (renderer != null) {\n const root = renderer.getRoot();\n const sprite = renderer.getSprite();\n if (root != null && sprite != null && sprite.texture != null) {\n const animPad: number = clip.renderTexturePadding ?? 0;\n const textureWidth = sprite.texture.width - animPad * 2;\n const textureHeight = sprite.texture.height - animPad * 2;\n\n const newWidth = Math.abs(root.scale.x * sprite.scale.x) * textureWidth;\n const newHeight = Math.abs(root.scale.y * sprite.scale.y) * textureHeight;\n\n const logicalWidth = newWidth;\n const logicalHeight = newHeight;\n\n const newLeft = root.x - logicalWidth / 2;\n const newTop = root.y - logicalHeight / 2;\n\n clip.left = newLeft;\n clip.top = newTop;\n clip.width = logicalWidth;\n clip.height = logicalHeight;\n\n const flipFactor = clip.flip?.x || clip.flip?.y ? -1 : 1;\n clip.angle = flipFactor * root.angle;\n\n renderer.updateTransforms();\n this.studio.emit(\"clip:updated\", { clip });\n }\n }\n }\n\n public async deleteSelected() {\n return this.studio.deleteSelected();\n }\n}\n","import type { Studio } from \"../studio\";\nimport type { IClip, IPlaybackCapable } from \"../clips/iclip\";\n\nexport interface PlaybackElementInfo {\n element: HTMLVideoElement | HTMLAudioElement;\n objectUrl?: string;\n}\n\nexport class Transport {\n public isPlaying = false;\n public currentTime = 0; // in microseconds\n public maxDuration = 0; // in microseconds\n\n private playStartTime = 0; // in microseconds - time when playback started\n private playStartTimestamp = 0; // performance.now() when playback started\n private rafId: number | null = null;\n\n // Playback elements for clips that support playback\n public playbackElements = new Map<IClip, PlaybackElementInfo>();\n\n constructor(private studio: Studio) {}\n\n public setMaxDuration(duration: number) {\n this.maxDuration = duration;\n }\n\n /**\n * Start playback\n */\n async play(): Promise<void> {\n if (this.isPlaying || this.studio.destroyed) return;\n if (this.maxDuration <= 0 || this.maxDuration === Infinity || isNaN(this.maxDuration)) {\n console.warn(\"Cannot play: invalid duration\", this.maxDuration);\n return;\n }\n\n if (!this.isPlaying) {\n this.isPlaying = true; // Set flag immediately to allow renderLoop to start\n }\n this.playStartTime = this.currentTime;\n this.playStartTimestamp = performance.now();\n\n // Start render loop — syncPlayback (called every frame inside updateFrame)\n // is the sole authority for starting/stopping/volume on playback elements.\n // Calling clip.play() directly here would bypass the fade-volume computation\n // inside syncPlayback, causing fade-in to be skipped on the first frame.\n this.renderLoop();\n this.studio.emit(\"play\", { isPlaying: true });\n }\n\n /**\n * Pause playback\n */\n pause(): void {\n this.isPlaying = false;\n if (this.rafId != null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n // Pause all playback elements\n for (const [clip, { element }] of this.playbackElements.entries()) {\n if (this.isPlaybackCapable(clip)) {\n clip.pause(element);\n }\n }\n this.studio.emit(\"pause\", { isPlaying: false });\n }\n\n /**\n * Stop playback and reset to start\n */\n async stop(): Promise<void> {\n this.pause();\n await this.seek(0);\n }\n\n /**\n * Seek to a specific time (in microseconds)\n */\n async seek(time: number): Promise<void> {\n if (this.studio.destroyed) return;\n\n // Store current play state\n const wasPlaying = this.isPlaying;\n\n // Update play start time/timestamp for accurate timing after seek\n this.playStartTime = Math.max(0, Math.min(time, this.maxDuration));\n this.playStartTimestamp = performance.now();\n\n // Set new time (already set above with playStartTime)\n this.currentTime = this.playStartTime;\n\n // Seek all playback elements\n for (const [clip, { element }] of this.playbackElements.entries()) {\n // Check if clip should be active at current time\n const shouldBeActive =\n this.currentTime >= clip.display.from &&\n (clip.display.to === 0 || this.currentTime <= clip.display.to);\n\n if (!shouldBeActive) {\n if (this.isPlaybackCapable(clip)) {\n clip.pause(element);\n }\n continue;\n }\n\n const relativeTime = (this.currentTime - clip.display.from) / 1e6;\n if (this.isPlaybackCapable(clip)) {\n const seekTime = this.currentTime;\n // Register a settle callback: when seeked fires and this is still\n // the most recent seek, re-upload the texture and re-render.\n const videoEl = element as HTMLVideoElement;\n (videoEl as any).__pendingRender = () => {\n if (this.currentTime !== seekTime) return; // stale seek, skip\n this.studio.updateFrame(seekTime);\n };\n\n await clip.seek(element, relativeTime);\n }\n }\n\n // Update frame to render the sought position\n await this.studio.updateFrame(this.currentTime);\n this.studio.emit(\"currentTime\", { currentTime: this.currentTime });\n\n // Restore play state if it was playing.\n // Same reason as transport.play(): let syncPlayback handle the actual\n // element.play() call so fade volume is applied before audio starts.\n if (wasPlaying) {\n this.isPlaying = true;\n }\n }\n\n /**\n * Move to the next frame\n */\n async frameNext(): Promise<void> {\n const fps = this.studio.opts.fps || 30;\n const frameDuration = 1_000_000 / fps;\n const nextTime = Math.min(this.currentTime + frameDuration, this.maxDuration);\n await this.seek(nextTime);\n }\n\n /**\n * Move to the previous frame\n */\n async framePrev(): Promise<void> {\n const fps = this.studio.opts.fps || 30;\n const frameDuration = 1_000_000 / fps;\n const prevTime = Math.max(0, this.currentTime - frameDuration);\n await this.seek(prevTime);\n }\n\n private async renderLoop(): Promise<void> {\n if (!this.isPlaying || this.studio.destroyed || this.studio.pixiApp == null) return;\n if (this.maxDuration <= 0 || this.maxDuration === Infinity || isNaN(this.maxDuration)) {\n this.pause();\n return;\n }\n\n const render = async () => {\n if (!this.isPlaying || this.studio.destroyed || this.studio.pixiApp == null) return;\n if (this.currentTime >= this.maxDuration) {\n this.currentTime = this.maxDuration;\n this.pause();\n return;\n }\n\n // Calculate current time based on actual elapsed time\n // This ensures playback speed matches the configured fps\n const elapsedMs = performance.now() - this.playStartTimestamp;\n const elapsedMicroseconds = elapsedMs * 1000;\n this.currentTime = Math.min(this.playStartTime + elapsedMicroseconds, this.maxDuration);\n this.studio.emit(\"currentTime\", { currentTime: this.currentTime });\n\n // Await frame update to ensure it completes before moving to next frame\n // This prevents blinking caused by overlapping frame updates\n try {\n await this.studio.updateFrame(this.currentTime);\n } catch (err) {\n console.warn(\"Error updating frame:\", err);\n }\n\n // Continue with next frame using requestAnimationFrame\n // This gives the browser time to update video textures smoothly\n if (this.isPlaying) {\n this.rafId = requestAnimationFrame(render);\n }\n };\n\n render();\n }\n\n public isPlaybackCapable(clip: any): clip is IPlaybackCapable {\n return \"play\" in clip && \"pause\" in clip && \"seek\" in clip;\n }\n}\n","import { Texture, Sprite } from \"pixi.js\";\nimport type { Studio, StudioTrack } from \"../studio\";\nimport type { IClip, IPlaybackCapable } from \"../clips/iclip\";\nimport { Transition } from \"../clips/transition-clip\";\nimport { PixiSpriteRenderer } from \"../sprite/pixi-sprite-renderer\";\nimport {\n clipToJSON,\n jsonToClip,\n ProjectJSON,\n ClipJSON,\n GlobalTransitionJSON as TransitionJSON,\n} from \"../json-serialization\";\nimport { fontManager, IFont } from \"../utils/fonts\";\n\nexport class TimelineModel {\n public tracks: StudioTrack[] = [];\n public clips: IClip[] = [];\n\n constructor(private studio: Studio) {}\n\n public getTrackById(trackId: string): StudioTrack | undefined {\n return this.tracks.find((t) => t.id === trackId);\n }\n\n public getClipById(clipId: string): IClip | undefined {\n return this.clips.find((c) => c.id === clipId);\n }\n\n public findTrackIdByClipId(clipId: string): string | undefined {\n for (const track of this.tracks) {\n if (track.clipIds.includes(clipId)) return track.id;\n }\n return undefined;\n }\n\n public getTrackIndex(trackId: string): number {\n return this.tracks.findIndex((t) => t.id === trackId);\n }\n\n /**\n * Add a new track to the studio\n */\n addTrack(track: { name: string; type: string; id?: string }, index?: number): StudioTrack {\n const newTrack: StudioTrack = {\n id: track.id || `track_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n name: track.name,\n type: track.type,\n clipIds: [],\n };\n\n if (typeof index === \"number\") {\n this.tracks.splice(index, 0, newTrack);\n } else {\n // Default to unshift (front/top) for new tracks if no index provided\n this.tracks.unshift(newTrack);\n }\n\n this.studio.emit(\"track:added\", { track: newTrack, index: index ?? 0 });\n this.studio.emit(\"track:order-changed\", { tracks: this.tracks });\n return newTrack;\n }\n\n /**\n * Remove a track and all its clips\n */\n async removeTrack(trackId: string): Promise<void> {\n const index = this.tracks.findIndex((t) => t.id === trackId);\n if (index === -1) return;\n\n const track = this.tracks[index];\n const clipIds = [...track.clipIds];\n\n for (const clipId of clipIds) {\n await this.removeClipById(clipId);\n }\n\n this.tracks.splice(index, 1);\n this.studio.emit(\"track:removed\", { trackId });\n this.studio.emit(\"track:order-changed\", { tracks: this.tracks });\n }\n\n /**\n * Move a track to a new index\n */\n public async moveTrack(trackId: string, newIndex: number): Promise<void> {\n const currentIndex = this.tracks.findIndex((t) => t.id === trackId);\n if (currentIndex === -1) return;\n\n const track = this.tracks[currentIndex];\n this.tracks.splice(currentIndex, 1);\n this.tracks.splice(newIndex, 0, track);\n\n this.studio.emit(\"track:order-changed\", { tracks: this.tracks });\n await this.studio.updateFrame(this.studio.currentTime);\n }\n\n /**\n * Set the order of tracks by ID\n */\n public async setTrackOrder(trackIds: string[]): Promise<void> {\n const newTracks: StudioTrack[] = [];\n const currentTracksMap = new Map(this.tracks.map((t) => [t.id, t]));\n\n for (const id of trackIds) {\n const track = currentTracksMap.get(id);\n if (track) {\n newTracks.push(track);\n }\n }\n\n // Basic validation: ensure we didn't lose any tracks\n if (newTracks.length !== this.tracks.length) {\n console.warn(\"[Studio] setTrackOrder: invalid track IDs provided, order not updated fully\");\n }\n\n this.tracks = newTracks;\n this.studio.emit(\"track:order-changed\", { tracks: this.tracks });\n await this.studio.updateFrame(this.studio.currentTime);\n }\n\n /**\n * Add a Transition clip at the join where the selected clip starts.\n */\n async addTransition(\n transitionKey: string,\n duration: number = 2000000,\n fromClipId?: string | null,\n toClipId?: string | null,\n id?: string,\n ): Promise<void> {\n if (this.studio.destroyed) return;\n\n let clipA: IClip | null = null;\n let clipB: IClip | null = null;\n if (fromClipId && toClipId) {\n clipA = this.getClipById(fromClipId) ?? null;\n clipB = this.getClipById(toClipId) ?? null;\n }\n\n if (!clipA || !clipB) {\n console.warn(\"[Studio] Invalid fromClipId or toClipId\", {\n fromClipId,\n toClipId,\n });\n return;\n }\n\n // Ensure clips are ready before calculating timing\n await Promise.all([clipA.ready, clipB.ready]);\n\n const transitionDuration = duration;\n\n const transitionStart = clipB.display.from - transitionDuration / 2;\n const transitionEnd = transitionStart + transitionDuration;\n\n const transitionMeta = {\n key: transitionKey,\n name: transitionKey,\n duration: transitionDuration,\n fromClipId: clipA.id,\n toClipId: clipB.id,\n start: Math.max(0, transitionStart),\n end: transitionEnd,\n };\n\n // Remove any existing transition clip between these two clips\n const targetTrackId = this.findTrackIdByClipId(clipB.id);\n if (targetTrackId) {\n const track = this.tracks.find((t) => t.id === targetTrackId);\n if (track) {\n const existingTransitions = track.clipIds\n .map((id) => this.getClipById(id))\n .filter((c): c is IClip => {\n if (!c || c.type !== \"Transition\") return false;\n const tc = c as any;\n return tc.fromClipId === clipA!.id && tc.toClipId === clipB!.id;\n });\n // Remove existing transition clips\n for (const existingTransition of existingTransitions) {\n await this.removeClip(existingTransition);\n }\n }\n }\n\n // Clear cached transition renderers to ensure new transition type is used\n const transKey = `${clipA.id}_${clipB.id}`;\n if (this.studio.transitionRenderers.has(transKey)) {\n this.studio.transitionRenderers.get(transKey)?.destroy();\n this.studio.transitionRenderers.delete(transKey);\n }\n\n // Force set transition property\n (clipA as any).transition = { ...transitionMeta };\n (clipB as any).transition = { ...transitionMeta };\n\n const tClip = new Transition(transitionKey as any);\n // Preserve the core clip ID so that removal/lookup by core ID works correctly\n if (id) {\n tClip.id = id;\n }\n tClip.duration = transitionDuration;\n tClip.fromClipId = Math.max(0, transitionStart) === 0 ? null : clipA.id;\n tClip.toClipId = clipB.id;\n\n if (tClip.fromClipId === null && clipA) {\n tClip.fromClipId = clipA.id;\n }\n\n tClip.display.from = Math.max(0, transitionStart);\n tClip.display.to = transitionEnd;\n\n await this.addClip(tClip, { trackId: targetTrackId });\n\n this.studio.seek(this.studio.currentTime);\n }\n\n /**\n * Add a clip (or clips) to the studio\n */\n async addClip(\n clipOrClips: IClip | IClip[],\n options?:\n | {\n trackId?: string;\n audioSource?: string | File | Blob;\n }\n | string\n | File\n | Blob,\n ): Promise<void> {\n const clips = Array.isArray(clipOrClips) ? clipOrClips : [clipOrClips];\n if (clips.length === 0) return;\n\n // 1. Normalize Options\n const { trackId, audioSource } = this.normalizeAddClipOptions(options);\n\n // 2. Validate Context\n if (this.studio.destroyed) return;\n if (this.studio.pixiApp == null) {\n throw new Error(\"Failed to initialize Pixi.js Application\");\n }\n\n // 3. Prepare Internal Logic (IDs, Tracks, Listeners)\n // Filter out clips that already exist to avoid duplicates\n const newClips = clips.filter((clip) => !this.getClipById(clip.id));\n const addedClips: IClip[] = [];\n for (const clip of newClips) {\n await this.prepareClipForTimeline(clip, trackId);\n addedClips.push(clip);\n }\n\n // 4. Update Time Limits\n await this.recalculateMaxDuration();\n\n // 5. Setup Visuals & Playback\n for (const clip of addedClips) {\n await this.setupClipVisuals(clip, audioSource);\n }\n\n // 6. Update Render\n await this.studio.updateFrame(this.studio.currentTime);\n\n // 7. Emit Events\n this.emitAddClipEvents(addedClips, trackId);\n }\n\n private normalizeAddClipOptions(\n options?: { trackId?: string; audioSource?: string | File | Blob } | string | File | Blob,\n ) {\n let audioSource: string | File | Blob | undefined;\n let trackId: string | undefined;\n\n if (\n options &&\n (typeof options === \"string\" || options instanceof File || options instanceof Blob)\n ) {\n audioSource = options;\n } else if (typeof options === \"object\" && options !== null && !(\"size\" in options)) {\n const opts = options as {\n trackId?: string;\n audioSource?: string | File | Blob;\n };\n audioSource = opts.audioSource;\n trackId = opts.trackId;\n }\n return { trackId, audioSource };\n }\n\n private async prepareClipForTimeline(clip: IClip, trackId?: string) {\n // A. Ensure ID immediately (Synchronous)\n if (!clip.id) {\n (clip as any).id = `clip_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n\n // B. Add to internal list immediately (Synchronous)\n // Check by ID to prevent duplicates when same clip is added via different\n // object instances (e.g., from Core patches creating new objects)\n if (!this.getClipById(clip.id)) {\n this.clips.push(clip);\n }\n\n // C. Add to Track immediately (Synchronous)\n this.addClipToTrack(clip, trackId);\n\n // D. Listen for property changes\n const onPropsChange = async () => {\n await this.studio.updateFrame(this.studio.currentTime);\n const interactionManager = this.studio.selection;\n if (\n interactionManager.activeTransformer != null &&\n interactionManager.selectedClips.has(clip) &&\n typeof (interactionManager.activeTransformer as any).updateBounds === \"function\"\n ) {\n (interactionManager.activeTransformer as any).updateBounds();\n }\n // Refresh hit area when dimensions change\n interactionManager.refreshClipHitArea(clip);\n };\n clip.on(\"propsChange\", onPropsChange);\n this.studio.clipListeners.set(clip, onPropsChange);\n\n // E. Link Renderer\n if (this.studio.pixiApp != null && typeof clip.setRenderer === \"function\") {\n clip.setRenderer(this.studio.pixiApp.renderer);\n }\n\n // F. Wait for Ready\n await clip.ready;\n }\n\n private addClipToTrack(clip: IClip, trackId?: string) {\n if (trackId) {\n // Try to find existing track (could be newly added in same batch)\n const track = this.tracks.find((t) => t.id === trackId);\n if (track) {\n if (!track.clipIds.includes(clip.id)) {\n track.clipIds.push(clip.id);\n }\n } else {\n // Track ID provided but doesn't exist -> Create it\n const newTrack: StudioTrack = {\n id: trackId,\n name: `Track ${this.tracks.length + 1}`,\n type: clip.type,\n clipIds: [clip.id],\n };\n this.tracks.unshift(newTrack);\n this.studio.emit(\"track:added\", { track: newTrack, index: 0 });\n this.studio.emit(\"track:order-changed\", { tracks: this.tracks });\n }\n } else {\n // Auto-create new track\n const newTrackId = `track_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n const newTrack: StudioTrack = {\n id: newTrackId,\n name: `Track ${this.tracks.length + 1}`,\n type: clip.type,\n clipIds: [clip.id],\n };\n this.tracks.unshift(newTrack);\n this.studio.emit(\"track:added\", { track: newTrack, index: 0 });\n this.studio.emit(\"track:order-changed\", { tracks: this.tracks });\n }\n }\n\n private async setupClipVisuals(clip: IClip, audioSource?: string | File | Blob) {\n // If we've already set up visuals (from cache), check if we need to re-add to container\n const existingRenderer = this.studio.spriteRenderers.get(clip);\n if (existingRenderer) {\n const container = this.studio.clipsNormalContainer!;\n const root = existingRenderer.getRoot();\n if (root && !root.parent) {\n container.addChild(root);\n }\n } else {\n const meta = await clip.ready;\n\n if (meta.width > 0 && meta.height > 0) {\n const container = this.studio.clipsNormalContainer!;\n // Simple logic as both branches did the same thing in previous code\n const isVideo = clip.type === \"Video\" && this.isPlaybackCapable(clip);\n if (!isVideo || (isVideo && (clip as any).tickInterceptor != null)) {\n const renderer = new PixiSpriteRenderer(this.studio.pixiApp!, clip, container);\n this.studio.spriteRenderers.set(clip, renderer);\n }\n }\n }\n\n // Playback\n // For cached clips, setupPlaybackForClip will re-register the element with transport\n await this.setupPlaybackForClip(clip, audioSource);\n\n // Interactivity\n if (this.studio.opts.interactivity) {\n this.studio.selection.setupSpriteInteractivity(clip);\n }\n }\n\n private emitAddClipEvents(addedClips: IClip[], trackId?: string) {\n if (addedClips.length === 0) return;\n\n if (addedClips.length === 1) {\n const clip = addedClips[0];\n const actualTrackId =\n trackId || this.tracks.find((t) => t.clipIds.includes(clip.id))?.id || \"\";\n\n this.studio.emit(\"clip:added\", {\n clip,\n trackId: actualTrackId,\n });\n } else {\n this.studio.emit(\"clips:added\", {\n clips: addedClips,\n trackId,\n });\n }\n }\n\n async removeClip(\n clip: IClip,\n options: { permanent: boolean } = { permanent: true },\n ): Promise<void> {\n const { permanent } = options;\n if (clip.locked) return;\n const index = this.clips.findIndex((c) => c === clip);\n if (index === -1) return;\n\n // Separate cleanup for Transition to remove 'transition' property from linked clips\n if (clip instanceof Transition) {\n if (clip.fromClipId) {\n const fromClip = this.getClipById(clip.fromClipId);\n if (fromClip && \"transition\" in fromClip) {\n delete (fromClip as any).transition;\n }\n }\n if (clip.toClipId) {\n const toClip = this.getClipById(clip.toClipId);\n if (toClip && \"transition\" in toClip) {\n delete (toClip as any).transition;\n }\n }\n }\n\n // Deselect\n if (this.studio.selection.selectedClips.has(clip)) {\n this.studio.selection.deselectClip();\n }\n\n // Remove from generic clips list\n this.clips.splice(index, 1);\n\n // Remove ID from tracks\n const tracksToCheck: string[] = [];\n for (const track of this.tracks) {\n const idx = track.clipIds.indexOf(clip.id);\n if (idx !== -1) {\n track.clipIds.splice(idx, 1);\n tracksToCheck.push(track.id);\n }\n }\n\n // Auto-remove empty tracks and reconcile dangling references\n this.reconcileTracks();\n\n // Remove from interactive tracking\n\n // Remove from interactive tracking\n this.studio.selection.interactiveClips.delete(clip);\n\n // Clean up listener\n const onPropsChange = this.studio.clipListeners.get(clip);\n if (onPropsChange) {\n clip.off(\"propsChange\", onPropsChange);\n this.studio.clipListeners.delete(clip);\n }\n\n // Clean up renderer\n const renderer = this.studio.spriteRenderers.get(clip);\n if (renderer != null) {\n if (permanent) {\n renderer.destroy();\n this.studio.spriteRenderers.delete(clip);\n } else {\n const root = renderer.getRoot();\n if (root && root.parent) {\n root.parent.removeChild(root);\n }\n }\n }\n\n // Clean up playback element\n const playbackInfo = this.studio.transport.playbackElements.get(clip);\n if (playbackInfo != null) {\n if (this.isPlaybackCapable(clip)) {\n // Always stop playback immediately so removed clips can't keep producing audio.\n // This is especially important for undo/redo where `permanent` can be false.\n clip.pause(playbackInfo.element);\n }\n\n // Always unregister from the transport so it can't be driven by play/seek loops.\n // For non-permanent removals (e.g. undo), we may skip full cleanup to keep media\n // warm in memory, but it must not be audible.\n this.studio.transport.playbackElements.delete(clip);\n\n if (permanent && this.isPlaybackCapable(clip)) {\n clip.cleanupPlayback(playbackInfo.element, playbackInfo.objectUrl);\n }\n }\n\n // Clean up video sprite\n const sprite = this.studio.videoSprites.get(clip);\n if (sprite != null && this.studio.pixiApp != null) {\n if (sprite.parent) {\n sprite.parent.removeChild(sprite);\n }\n if (permanent) {\n sprite.destroy();\n this.studio.videoSprites.delete(clip);\n }\n }\n\n // Recalculate max duration\n await this.recalculateMaxDuration();\n\n this.studio.emit(\"clip:removed\", { clipId: clip.id });\n }\n\n /**\n * Remove multiple clips in a batch\n */\n async removeClips(\n clips: IClip[],\n options: { permanent: boolean } = { permanent: true },\n ): Promise<void> {\n if (clips.length === 0) return;\n\n for (const clip of clips) {\n if (clip.locked) continue;\n const index = this.clips.findIndex((c) => c === clip);\n if (index === -1) continue;\n\n // Transition cleanup\n if (clip instanceof Transition) {\n if (clip.fromClipId) {\n const fromClip = this.getClipById(clip.fromClipId);\n if (fromClip && \"transition\" in fromClip) {\n delete (fromClip as any).transition;\n }\n }\n if (clip.toClipId) {\n const toClip = this.getClipById(clip.toClipId);\n if (toClip && \"transition\" in toClip) {\n delete (toClip as any).transition;\n }\n }\n }\n\n // Deselect\n if (this.studio.selection.selectedClips.has(clip)) {\n this.studio.selection.deselectClip();\n }\n\n // Remove from generic clips list\n this.clips.splice(index, 1);\n\n // Remove ID from tracks\n for (const track of this.tracks) {\n const idx = track.clipIds.indexOf(clip.id);\n if (idx !== -1) {\n track.clipIds.splice(idx, 1);\n }\n }\n\n // Remove from interactive tracking\n this.studio.selection.interactiveClips.delete(clip);\n\n // Clean up listener\n const onPropsChange = this.studio.clipListeners.get(clip);\n if (onPropsChange) {\n clip.off(\"propsChange\", onPropsChange);\n this.studio.clipListeners.delete(clip);\n }\n\n // Clean up renderer\n const renderer = this.studio.spriteRenderers.get(clip);\n if (renderer != null) {\n if (options.permanent) {\n renderer.destroy();\n this.studio.spriteRenderers.delete(clip);\n } else {\n const root = renderer.getRoot();\n if (root && root.parent) {\n root.parent.removeChild(root);\n }\n }\n }\n\n // Clean up playback element\n const playbackInfo = this.studio.transport.playbackElements.get(clip);\n if (playbackInfo != null) {\n if (this.isPlaybackCapable(clip)) {\n // Always stop playback immediately so removed clips can't keep producing audio.\n clip.pause(playbackInfo.element);\n }\n\n // Always unregister from transport, regardless of permanence.\n this.studio.transport.playbackElements.delete(clip);\n\n if (options.permanent && this.isPlaybackCapable(clip)) {\n clip.cleanupPlayback(playbackInfo.element, playbackInfo.objectUrl);\n }\n }\n\n // Clean up video sprite\n const sprite = this.studio.videoSprites.get(clip);\n if (sprite != null && this.studio.pixiApp != null) {\n if (sprite.parent) {\n sprite.parent.removeChild(sprite);\n }\n if (options.permanent) {\n sprite.destroy();\n this.studio.videoSprites.delete(clip);\n }\n }\n }\n\n // Auto-remove empty tracks\n for (let i = this.tracks.length - 1; i >= 0; i--) {\n if (this.tracks[i].clipIds.length === 0) {\n const trackId = this.tracks[i].id;\n this.tracks.splice(i, 1);\n this.studio.emit(\"track:removed\", { trackId });\n }\n }\n\n // Batch updates\n await this.recalculateMaxDuration();\n\n this.studio.emit(\"clips:removed\", {\n clipIds: clips.map((c) => c.id),\n });\n }\n\n async removeClipById(clipId: string): Promise<void> {\n const clip = this.clips.find((c) => c.id === clipId);\n if (clip) {\n await this.removeClip(clip);\n }\n }\n\n async updateClip(clipId: string, updates: Partial<IClip>): Promise<void> {\n const clip = this.clips.find((c) => c.id === clipId);\n if (!clip) return;\n\n // Allow unlocking, but block other property changes if locked\n if (clip.locked && !(\"locked\" in updates)) {\n return;\n }\n\n // If locked and trying to change other properties through updateClip, only allow 'locked' change\n if (clip.locked && \"locked\" in updates) {\n const onlyLocked = Object.keys(updates).length === 1;\n if (!onlyLocked) {\n updates = { locked: updates.locked } as any;\n }\n }\n\n await this.applyClipUpdate(clip, updates);\n\n // Recalculate max duration\n await this.recalculateMaxDuration();\n\n // Trigger update\n await this.studio.updateFrame(this.studio.currentTime);\n\n // Update transformer if selected\n this.updateTransformer(clip);\n\n this.studio.emit(\"clip:updated\", { clip });\n }\n\n async updateClips(updates: { id: string; updates: Partial<IClip> }[]): Promise<void> {\n const updatedClips: IClip[] = [];\n\n for (const { id, updates: clipUpdates } of updates) {\n const clip = this.clips.find((c) => c.id === id);\n if (clip) {\n await this.applyClipUpdate(clip, clipUpdates);\n updatedClips.push(clip);\n }\n }\n\n if (updatedClips.length === 0) return;\n\n // Recalculate max duration once\n await this.recalculateMaxDuration();\n\n // Trigger update once\n await this.studio.updateFrame(this.studio.currentTime);\n\n // Update transformer for any selected clips\n for (const clip of updatedClips) {\n this.updateTransformer(clip);\n this.studio.emit(\"clip:updated\", { clip });\n }\n }\n\n /**\n * Replace all clips with the same source with new clips generated by a factory.\n * Useful for replacing placeholders with actual assets.\n */\n async replaceClipsBySource(\n src: string,\n newClipFactory: (oldClip: IClip) => Promise<IClip>,\n ): Promise<void> {\n // Collect all clips that match the source first to avoid issues with array modification\n const toReplace = this.clips.filter((c) => c.src === src);\n if (toReplace.length === 0) return;\n\n this.studio.suspendRendering();\n\n for (const oldClip of toReplace) {\n // Verify the clip is still in the list (might have been removed in a previous iteration)\n if (!this.clips.includes(oldClip)) continue;\n\n const trackId = this.findTrackIdByClipId(oldClip.id);\n if (!trackId) continue;\n\n const track = this.getTrackById(trackId);\n if (!track) continue;\n\n const newClip = await newClipFactory(oldClip);\n\n // 1. Setup listeners for the new clip (matches prepareClipForTimeline logic)\n const onPropsChange = async () => {\n await this.studio.updateFrame(this.studio.currentTime);\n this.updateTransformer(newClip);\n };\n newClip.on(\"propsChange\", onPropsChange);\n this.studio.clipListeners.set(newClip, onPropsChange);\n\n if (this.studio.pixiApp != null && typeof (newClip as any).setRenderer === \"function\") {\n (newClip as any).setRenderer(this.studio.pixiApp.renderer);\n }\n\n // 2. Wait for Ready\n await newClip.ready;\n\n // 3. Replace in internal clips list at the same index\n const clipIdx = this.clips.indexOf(oldClip);\n if (clipIdx !== -1) {\n this.clips[clipIdx] = newClip;\n }\n\n // 4. Replace in track\n const trackClipIdx = track.clipIds.indexOf(oldClip.id);\n if (trackClipIdx !== -1) {\n track.clipIds[trackClipIdx] = newClip.id;\n }\n\n // 5. Setup visuals for the new clip\n await this.setupClipVisuals(newClip);\n\n // 6. Cleanup old visuals and listeners MANUALLY\n // Search for any renderer associated with this clip and destroy it\n const oldRenderer = this.studio.spriteRenderers.get(oldClip);\n if (oldRenderer) {\n oldRenderer.destroy();\n this.studio.spriteRenderers.delete(oldClip);\n }\n\n const oldVideoSprite = this.studio.videoSprites.get(oldClip);\n if (oldVideoSprite) {\n if (oldVideoSprite.parent) {\n oldVideoSprite.parent.removeChild(oldVideoSprite);\n }\n oldVideoSprite.destroy();\n this.studio.videoSprites.delete(oldClip);\n }\n\n const oldListener = this.studio.clipListeners.get(oldClip);\n if (oldListener) {\n oldClip.off(\"propsChange\", oldListener);\n this.studio.clipListeners.delete(oldClip);\n }\n\n // 7. Sync selection\n if (this.studio.selection.selectedClips.has(oldClip)) {\n this.studio.selection.selectedClips.delete(oldClip);\n this.studio.selection.selectedClips.add(newClip);\n }\n\n // 8. Emit event to sync with editor store\n this.studio.emit(\"clip:replaced\", { oldClip, newClip, trackId });\n }\n\n await this.recalculateMaxDuration();\n this.studio.resumeRendering();\n await this.studio.updateFrame(this.studio.currentTime);\n }\n\n private async applyClipUpdate(clip: IClip, updates: Partial<IClip>) {\n // Special handling for TextClip and CaptionClip style updates\n if (clip.type === \"Text\" || clip.type === \"Caption\") {\n const textOrCaption = clip as any;\n if (typeof textOrCaption.updateStyle === \"function\") {\n await textOrCaption.updateStyle(updates);\n }\n\n // Remove 'style' from updates to prevent setter/getter conflicts\n if (\"style\" in updates) {\n delete (updates as any).style;\n }\n }\n\n // Merge updates\n Object.assign(clip, updates);\n\n // Ensure consistency between display and duration\n // If updates contains display, but no duration, update duration\n if (updates.display && !updates.duration) {\n clip.duration = updates.display.to - updates.display.from;\n }\n // If updates contains duration, but no display.to, update display.to\n else if (updates.duration && (!updates.display || !updates.display.to)) {\n if (!clip.display) {\n // Should not happen if clip is valid, but safety check\n clip.display = { from: 0, to: updates.duration };\n }\n clip.display.to = clip.display.from + updates.duration;\n }\n // If both display and duration are updated, trust display.to if explicit, or re-verify?\n if (updates.display && updates.duration) {\n const calculatedDuration = updates.display.to - updates.display.from;\n if (calculatedDuration !== updates.duration) {\n clip.duration = calculatedDuration;\n }\n } else {\n // Just in case valid data was merged but we need to ensure consistency\n if (clip.display) {\n clip.display.to = clip.display.from + clip.duration;\n }\n }\n }\n\n private updateTransformer(clip: IClip) {\n const interactionManager = this.studio.selection;\n if (interactionManager.selectedClips.has(clip) && interactionManager.activeTransformer) {\n interactionManager.activeTransformer.updateBounds();\n }\n }\n\n /**\n * Export current project state to JSON\n */\n exportToJSON(): ProjectJSON {\n this.reconcileTracks();\n\n const clips: Record<string, ClipJSON> = {};\n for (const clip of this.clips) {\n clips[clip.id] = clipToJSON(clip, false);\n }\n\n const tracks = this.tracks.map((track) => ({\n id: track.id,\n name: track.name,\n type: track.type,\n clipIds: [...track.clipIds], // Create a new array to avoid reference leakage\n }));\n\n const transitions: TransitionJSON[] = [];\n this.clips.forEach((clip) => {\n if (clip.transition) {\n // Find predecessor on the same track\n const track = this.tracks.find((t) => t.clipIds.includes(clip.id));\n if (track) {\n const clipIndex = track.clipIds.indexOf(clip.id);\n if (clipIndex > 0) {\n const prevClipId = track.clipIds[clipIndex - 1];\n transitions.push({\n key: clip.transition.name,\n duration: clip.transition.duration,\n clips: [prevClipId, clip.id],\n });\n }\n }\n }\n });\n\n return {\n tracks,\n clips,\n settings: {\n width: this.studio.opts.width,\n height: this.studio.opts.height,\n fps: this.studio.opts.fps,\n backgroundColor: this.studio.opts.backgroundColor,\n },\n };\n }\n\n /**\n * Load clips from JSON\n */\n async loadFromJSON(json: ProjectJSON): Promise<void> {\n await this.clear();\n\n // Update settings if provided\n if (json.settings) {\n const dimensionsChanged =\n (json.settings.width && json.settings.width !== this.studio.opts.width) ||\n (json.settings.height && json.settings.height !== this.studio.opts.height);\n\n if (json.settings.width) this.studio.opts.width = json.settings.width;\n if (json.settings.height) this.studio.opts.height = json.settings.height;\n if (json.settings.fps) this.studio.opts.fps = json.settings.fps;\n if (json.settings.backgroundColor)\n this.studio.opts.backgroundColor = json.settings.backgroundColor;\n\n // Resize PixiJS renderer and canvas if dimensions changed\n if (dimensionsChanged && this.studio.pixiApp != null) {\n const newWidth = this.studio.opts.width;\n const newHeight = this.studio.opts.height;\n\n // Resize the renderer\n this.studio.pixiApp.renderer.resize(newWidth, newHeight);\n\n // Update canvas dimensions\n if (this.studio.opts.canvas) {\n this.studio.opts.canvas.width = newWidth;\n this.studio.opts.canvas.height = newHeight;\n }\n }\n }\n\n // Load all clips first (Normalized)\n // Load all clips in parallel (Batched)\n const clipPromises: Promise<{\n clip: IClip | null;\n intendedTrackId?: string;\n }>[] = [];\n const clipsArray = Object.values(json.clips ?? {});\n if (clipsArray.length > 0) {\n // 1. Load Fonts First\n await this.ensureFontsForClips(clipsArray);\n\n // 2. Preload Resources (Video, Audio, Image) - DO NOT AWAIT (Performance)\n const urlsToPreload = clipsArray\n .map((clip) => clip.src)\n .filter((src) => src && src.trim() !== \"\");\n this.studio.resourceManager.preload(urlsToPreload as string[]);\n\n // Build map of ClipID -> TrackID from json.tracks\n const clipToTrackId = new Map<string, string>();\n if (json.tracks) {\n for (const t of json.tracks) {\n if (t.clipIds) {\n for (const cid of t.clipIds) {\n clipToTrackId.set(cid, t.id);\n }\n }\n }\n }\n\n // Initialize tracks from JSON first\n if (json.tracks) {\n for (const t of json.tracks) {\n this.tracks.push({\n id: t.id,\n name: t.name,\n type: t.type,\n clipIds: [], // Will fill as we add clips\n });\n }\n }\n\n // Create promises for clip loading\n for (const clipJSON of clipsArray) {\n clipPromises.push(\n (async () => {\n try {\n let intendedTrackId = clipJSON.id ? clipToTrackId.get(clipJSON.id) : undefined;\n\n // Inference for Transitions without top-level ID\n if (clipJSON.type === \"Transition\") {\n const transJSON = clipJSON as any;\n const targetId = transJSON.toClipId || transJSON.fromClipId;\n if (targetId) {\n intendedTrackId = clipToTrackId.get(targetId);\n }\n }\n\n // Pre-validation for empty sources\n if (\n clipJSON.type !== \"Text\" &&\n clipJSON.type !== \"Caption\" &&\n clipJSON.type !== \"Effect\" &&\n clipJSON.type !== \"Transition\" &&\n (!clipJSON.src || clipJSON.src.trim() === \"\")\n ) {\n console.warn(`Skipping clip ${clipJSON.type} with empty source`, clipJSON);\n return { clip: null };\n }\n\n const clip = await jsonToClip(clipJSON);\n\n // If scaling needed (Video/Image)\n if (\n (clip.type === \"Video\" || clip.type === \"Image\") &&\n (!clipJSON.transform?.width || !clipJSON.transform?.height)\n ) {\n // We defer scaling to after we have the clip ready,\n // but we can assume jsonToClip awaits 'ready' or we await it here\n // jsonToClip returns fully constructed clip, but 'ready' promise might not be awaited inside it fully?\n // Actually jsonToClip awaits fetch and createImageBitmap, so basic dimensions should be known.\n if (this.studio.opts.width && this.studio.opts.height) {\n if (typeof (clip as any).scaleToFit === \"function\") {\n await (clip as any).scaleToFit(this.studio.opts.width, this.studio.opts.height);\n }\n if (typeof (clip as any).centerInScene === \"function\") {\n (clip as any).centerInScene(this.studio.opts.width, this.studio.opts.height);\n }\n }\n }\n\n // Handle audioSource if necessary?\n // setupPlaybackForClip uses audioSource if provided.\n // We'll pass it down or attach to clip temporarily?\n // Or better, we handle playback setup later using the source URL we already have in clip.src\n\n return { clip, intendedTrackId };\n } catch (err) {\n console.error(`Failed to load clip ${clipJSON.id || \"unknown\"}:`, err);\n return { clip: null };\n }\n })(),\n );\n }\n\n const results = await Promise.all(clipPromises);\n\n // Add clips to internal list and tracks\n for (const { clip, intendedTrackId } of results) {\n if (!clip) continue;\n\n // Ensure ID\n if (!clip.id) {\n (clip as any).id = `clip_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n this.clips.push(clip);\n this.addClipToTrack(clip, intendedTrackId);\n }\n }\n\n // Now process loaded clips (listeners, renderer, ready)\n // IMPORTANT: this.studio.pixiApp must be ready\n if (this.studio.pixiApp) {\n this.clips.forEach((clip) => {\n // A. Listen for property changes\n const onPropsChange = async () => {\n await this.studio.updateFrame(this.studio.currentTime);\n const interactionManager = this.studio.selection;\n if (\n interactionManager.activeTransformer != null &&\n interactionManager.selectedClips.has(clip) &&\n typeof (interactionManager.activeTransformer as any).updateBounds === \"function\"\n ) {\n (interactionManager.activeTransformer as any).updateBounds();\n }\n };\n clip.on(\"propsChange\", onPropsChange);\n this.studio.clipListeners.set(clip, onPropsChange);\n\n // B. Link Renderer\n if (typeof clip.setRenderer === \"function\") {\n clip.setRenderer(this.studio.pixiApp!.renderer);\n }\n\n // C. Wait for Ready & Setup Visuals (Background)\n (async () => {\n try {\n await clip.ready;\n await this.setupClipVisuals(clip);\n // Trigger a frame update once a clip is visually ready\n await this.studio.updateFrame(this.studio.currentTime);\n } catch (err) {\n console.warn(`[Studio] Failed to setup visuals for clip ${clip.id}:`, err);\n }\n })();\n });\n }\n\n // Restore global effects from loaded clips\n for (const clip of this.clips) {\n const effects = (clip as any).effects;\n if (Array.isArray(effects)) {\n for (const effect of effects) {\n if (!this.studio.globalEffects.has(effect.id)) {\n this.studio.globalEffects.set(effect.id, {\n id: effect.id,\n key: effect.key,\n startTime: effect.startTime,\n duration: effect.duration,\n });\n }\n }\n }\n }\n\n // Restore transition links on target clips\n // Transition clips store fromClipId/toClipId, but the preview engine\n // expects clip.transition on the actual video/image clips\n for (const clip of this.clips) {\n if (clip instanceof Transition) {\n const transitionMeta = {\n name: clip.transitionKey,\n key: clip.transitionKey,\n duration: clip.duration,\n fromClipId: clip.fromClipId,\n toClipId: clip.toClipId,\n start: clip.display.from,\n end: clip.display.to,\n };\n\n if (clip.fromClipId) {\n const fromClip = this.getClipById(clip.fromClipId);\n if (fromClip) {\n (fromClip as any).transition = { ...transitionMeta };\n }\n }\n\n if (clip.toClipId) {\n const toClip = this.getClipById(clip.toClipId);\n if (toClip) {\n (toClip as any).transition = { ...transitionMeta };\n }\n }\n }\n }\n\n // Recalculate duration once\n await this.recalculateMaxDuration();\n\n // Update Frame once\n try {\n await this.studio.updateFrame(this.studio.currentTime);\n } catch (err) {\n console.error(\"[Studio] Failed to update initial frame:\", err);\n }\n\n // Emit single restore event\n this.studio.emit(\"studio:restored\", {\n clips: this.clips,\n tracks: this.tracks,\n settings: this.studio.opts,\n });\n }\n\n /**\n * Delete all currently selected clips\n */\n async deleteSelected(): Promise<void> {\n const selectedClips = this.studio.selection.selectedClips;\n const clipsToDelete = Array.from(selectedClips);\n if (clipsToDelete.length === 0) return;\n\n for (const clip of clipsToDelete) {\n await this.removeClip(clip);\n }\n }\n\n /**\n * Duplicate all currently selected clips\n */\n async duplicateSelected(): Promise<void> {\n const selectedClips = this.studio.selection.selectedClips;\n const clipsToDuplicate = Array.from(selectedClips).filter((c) => !c.locked);\n if (clipsToDuplicate.length === 0) return;\n\n const newClipIds: string[] = [];\n\n for (const clip of clipsToDuplicate) {\n const trackId = this.findTrackIdByClipId(clip.id);\n if (!trackId) continue;\n\n const track = this.tracks.find((t) => t.id === trackId);\n if (!track) continue;\n\n // Clone Clip\n const json = clipToJSON(clip, false);\n const newClip = await jsonToClip(json);\n newClip.id = `clip_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\n // Create new track for duplicate\n const newTrackId = `track_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n const newTrackName = `${track.name} (Copy)`;\n\n this.addTrack({\n id: newTrackId,\n name: newTrackName,\n type: track.type,\n });\n\n await this.addClip(newClip, { trackId: newTrackId });\n newClipIds.push(newClip.id);\n }\n\n if (newClipIds.length > 0) {\n this.studio.selection.selectClipsByIds(newClipIds);\n }\n }\n\n /**\n * Split the selected clip at the given time or current time\n */\n async splitSelected(splitTime?: number): Promise<void> {\n if (this.studio.opts.core) {\n this.studio.opts.core.clip.split(splitTime);\n return;\n }\n\n const selected = Array.from(this.studio.selection.selectedClips);\n if (selected.length !== 1) {\n console.warn(\"[Studio] Split requires exactly one selected clip\");\n return;\n }\n\n const clip = selected[0];\n if (clip.locked) {\n console.warn(\"[Studio] Cannot split a locked clip\");\n return;\n }\n const time = splitTime ?? this.studio.currentTime;\n\n if (time <= clip.display.from || (clip.display.to > 0 && time >= clip.display.to)) {\n console.warn(\"[Studio] Split time is outside clip bounds\");\n return;\n }\n\n const originalJson = clipToJSON(clip, false);\n const splitOffset = time - clip.display.from;\n const playbackRate = clip.playbackRate || 1;\n const splitOffsetInSource = splitOffset * playbackRate;\n\n // 1. Update original clip (Left Part)\n const updates: any = {\n duration: splitOffset,\n display: {\n from: clip.display.from,\n to: time,\n },\n };\n\n if (clip.trim) {\n updates.trim = {\n from: clip.trim.from,\n to: clip.trim.from + splitOffsetInSource,\n };\n }\n\n await this.updateClip(clip.id, updates);\n\n // 2. Create new clip (Right Part)\n const newJson = { ...originalJson } as any;\n if (!newJson.timing) {\n newJson.timing = {};\n }\n const origTo = originalJson.timing?.display?.to ?? 0;\n const origFrom = originalJson.timing?.display?.from ?? 0;\n const origDuration = originalJson.timing?.duration ?? clip.duration;\n const originalEnd = origTo > 0 ? origTo : origFrom + origDuration;\n\n newJson.timing.display = {\n from: time,\n to: originalEnd,\n };\n newJson.timing.duration = origDuration - splitOffset;\n\n if (newJson.timing.trim) {\n newJson.timing.trim = {\n from: newJson.timing.trim.from + splitOffsetInSource,\n to: newJson.timing.trim.to,\n };\n }\n\n const newClip = await jsonToClip(newJson);\n newClip.id = `clip_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\n const trackId = this.findTrackIdByClipId(clip.id);\n if (trackId) {\n await this.addClip(newClip, { trackId });\n this.studio.selection.selectClipsByIds([newClip.id]);\n }\n }\n\n /**\n * Trim the selected clip from a specified time\n * @param trimFromSeconds - Number of seconds to trim from the start of the clip\n */\n async trimSelected(trimFromSeconds: number): Promise<void> {\n const selected = Array.from(this.studio.selection.selectedClips);\n if (selected.length !== 1) {\n console.warn(\"[Studio] Trim requires exactly one selected clip\");\n return;\n }\n\n const clip = selected[0];\n if (clip.locked) {\n console.warn(\"[Studio] Cannot trim a locked clip\");\n return;\n }\n\n // Convert seconds to microseconds\n const trimFromUs = trimFromSeconds * 1_000_000;\n\n // Get playback rate for proper trim calculation\n const playbackRate = clip.playbackRate || 1;\n const trimOffsetInSource = trimFromUs * playbackRate;\n\n // Validate trim amount doesn't exceed clip duration\n if (trimFromUs >= clip.duration) {\n console.warn(\"[Studio] Trim amount exceeds clip duration\");\n return;\n }\n\n // Calculate new values\n const newDuration = clip.duration - trimFromUs;\n const newDisplayFrom = clip.display.from + trimFromUs;\n const newDisplayTo = clip.display.to;\n\n const updates: any = {\n duration: newDuration,\n display: {\n from: newDisplayFrom,\n to: newDisplayTo,\n },\n };\n\n // Update trim if it exists, otherwise create it\n if (clip.trim) {\n updates.trim = {\n from: clip.trim.from + trimOffsetInSource,\n to: clip.trim.to,\n };\n } else {\n // If no trim exists, create one based on source duration\n const sourceDuration = (clip as any).sourceDuration || clip.duration;\n updates.trim = {\n from: trimOffsetInSource,\n to: sourceDuration,\n };\n }\n\n await this.updateClip(clip.id, updates);\n }\n\n async updateSelected(updates: Partial<IClip>): Promise<void> {\n const selected = Array.from(this.studio.selection.selectedClips);\n if (selected.length === 0) return;\n\n for (const clip of selected) {\n await this.updateClip(clip.id, updates);\n }\n }\n\n async setTracks(tracks: StudioTrack[]): Promise<void> {\n // Deep clone tracks to avoid sharing references with history or other sources\n const previousTracks = JSON.parse(JSON.stringify(this.tracks));\n this.tracks = JSON.parse(JSON.stringify(tracks));\n this.reconcileTracks();\n // If incoming layout referenced only stale/dangling clipIds, reconcile drops\n // every track while clips still exist — revert so we do not emit [] to the UI.\n if (this.tracks.length === 0 && this.clips.length > 0) {\n this.tracks = previousTracks;\n this.reconcileTracks();\n }\n await this.recalculateMaxDuration();\n if (!this.studio.isRestoring) {\n this.studio.emit(\"track:order-changed\", { tracks: this.tracks });\n }\n await this.studio.updateFrame(this.studio.currentTime);\n }\n\n /**\n * Reconciles the tracks list with the available clips.\n * 1. Filters each track's clipIds to only include IDs present in this.clips.\n * 2. Removes any tracks that are then empty.\n * This is used as a safety net to ensure no orphaned empty tracks or dangling references remain.\n */\n public reconcileTracks(): void {\n const existingClipIds = new Set(this.clips.map((c) => c.id));\n\n for (let i = this.tracks.length - 1; i >= 0; i--) {\n const track = this.tracks[i];\n\n // Filter out dangling IDs\n const validClipIds = track.clipIds.filter((id) => existingClipIds.has(id));\n\n if (validClipIds.length !== track.clipIds.length) {\n track.clipIds = validClipIds;\n }\n\n if (track.clipIds.length === 0) {\n this.tracks.splice(i, 1);\n if (!this.studio.isRestoring) {\n this.studio.emit(\"track:removed\", { trackId: track.id });\n }\n }\n }\n\n if (this.tracks.length === 0 && !this.studio.isRestoring) {\n this.studio.emit(\"track:order-changed\", { tracks: this.tracks });\n }\n }\n\n private async ensureFontsForClips(clips: any[]): Promise<void> {\n const fontsToLoad = new Map<string, IFont>();\n for (const clip of clips) {\n // Check TextClip style\n if (clip.type === \"Text\") {\n const fontUrl = clip.style?.fontUrl || (clip as any).fontUrl;\n if (fontUrl) {\n fontsToLoad.set(fontUrl, {\n name: clip.style?.fontFamily || (clip as any).fontFamily || \"CustomFont\",\n url: fontUrl,\n });\n }\n }\n\n // Check Caption style\n if (clip.type === \"Caption\") {\n const fontUrl = clip.style?.fontUrl || (clip as any).fontUrl;\n if (fontUrl) {\n fontsToLoad.set(fontUrl, {\n name: clip.style?.fontFamily || (clip as any).fontFamily || \"CustomFont\",\n url: fontUrl,\n });\n }\n }\n }\n\n if (fontsToLoad.size > 0) {\n try {\n await fontManager.loadFonts(Array.from(fontsToLoad.values()));\n } catch (err) {\n console.warn(\"Failed to load some fonts:\", err);\n }\n }\n }\n\n async recalculateMaxDuration(): Promise<void> {\n let max = 0;\n for (const clip of this.clips) {\n if (\n clip.display.to === 0 &&\n clip.duration !== Infinity &&\n !isNaN(clip.duration) &&\n clip.duration > 0\n ) {\n // Fallback if to is 0?\n // Usually we care about display.to if set, or from + duration\n }\n\n const duration = clip.duration > 0 ? clip.duration : 0;\n if (duration === Infinity) continue; // Don't let infinite clips set max duration blindly?\n\n const end = clip.display.to > 0 ? clip.display.to : clip.display.from + duration;\n if (end > max) max = end;\n }\n this.studio.maxDuration = max;\n }\n\n private async setupPlaybackForClip(\n clip: IClip,\n audioSource?: string | File | Blob,\n ): Promise<void> {\n if (this.studio.pixiApp == null) return;\n if (!this.isPlaybackCapable(clip)) {\n return;\n }\n\n try {\n const playbackClip = clip as IPlaybackCapable;\n if (clip.type === \"Audio\" && audioSource && typeof audioSource !== \"string\") {\n const objectUrl = URL.createObjectURL(audioSource);\n (clip as any).src = objectUrl;\n }\n\n const { element, objectUrl } = await playbackClip.createPlaybackElement();\n\n if (clip.type === \"Video\") {\n const texture = Texture.from(element as HTMLVideoElement);\n const sprite = new Sprite(texture);\n sprite.visible = false;\n if (this.studio.clipsNormalContainer) {\n this.studio.clipsNormalContainer.addChild(sprite);\n }\n this.studio.videoSprites.set(clip, sprite);\n }\n\n this.studio.transport.playbackElements.set(clip, { element, objectUrl });\n } catch (err) {\n console.warn(`Failed to setup playback for ${clip.constructor.name}`, err);\n }\n }\n\n private isPlaybackCapable(clip: IClip): clip is IClip & IPlaybackCapable {\n return (\n \"createPlaybackElement\" in clip &&\n \"play\" in clip &&\n \"pause\" in clip &&\n \"seek\" in clip &&\n \"syncPlayback\" in clip &&\n \"cleanupPlayback\" in clip\n );\n }\n\n async clear(): Promise<void> {\n this.studio.selection.deselectClip();\n this.studio.selection.interactiveClips.clear();\n\n // Clear listeners\n for (const [clip, listener] of this.studio.clipListeners) {\n clip.off(\"propsChange\", listener);\n }\n this.studio.clipListeners.clear();\n\n // Effect, Global, Transition clear logic...\n this.studio.globalEffects.clear();\n this.studio.effectFilters.clear();\n\n // Transition clear\n this.studio.transitionRenderers.forEach((r) => r.destroy());\n this.studio.transitionRenderers.clear();\n this.studio.transitionSprites.forEach((s) => {\n if (s.parent) s.parent.removeChild(s);\n s.destroy();\n });\n this.studio.transitionSprites.clear();\n\n // Renderers clear\n this.studio.spriteRenderers.forEach((r) => r.destroy());\n this.studio.spriteRenderers.clear();\n\n // Playback clear\n for (const [clip, playbackInfo] of this.studio.transport.playbackElements) {\n if (this.isPlaybackCapable(clip)) {\n clip.cleanupPlayback(playbackInfo.element, playbackInfo.objectUrl);\n }\n }\n this.studio.transport.playbackElements.clear();\n\n // VideoSprites clear\n for (const sprite of this.studio.videoSprites.values()) {\n sprite.destroy();\n }\n this.studio.videoSprites.clear();\n\n // Tracks & Clips\n this.tracks = [];\n this.clips = [];\n this.studio.maxDuration = 0;\n this.studio.currentTime = 0;\n\n this.studio.emit(\"reset\");\n }\n\n /**\n * Remove a time range from the entire timeline and shift subsequent content left.\n * This is a ripple delete operation.\n * @param fromUs Start time in microseconds\n * @param toUs End time in microseconds\n */\n async rippleDelete(fromUs: number, toUs: number): Promise<void> {\n if (fromUs >= toUs) return;\n const durationToRemove = toUs - fromUs;\n\n // Use a copy of the clips array because it will be modified during the loop\n const clipsToProcess = [...this.clips];\n\n for (const clip of clipsToProcess) {\n const clipStart = clip.display.from;\n const clipEnd = clip.display.to;\n\n // Case 1: Clip ends before or at the start of the deletion range - No change\n if (clipEnd <= fromUs) {\n continue;\n }\n\n // Case 2: Clip starts at or after the end of the deletion range - Shift left\n if (clipStart >= toUs) {\n await this.updateClip(clip.id, {\n display: {\n from: clip.display.from - durationToRemove,\n to: clip.display.to - durationToRemove,\n },\n });\n continue;\n }\n\n // Case 3: Clip is completely within the deletion range - Remove\n if (clipStart >= fromUs && clipEnd <= toUs) {\n await this.removeClip(clip);\n continue;\n }\n\n // Case 4: Clip spans across the entire deletion range - Split into two\n if (clipStart < fromUs && clipEnd > toUs) {\n // Create second part first\n const secondPart = await clip.clone();\n secondPart.id = `clip_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\n const secondPartDisplayFrom = fromUs;\n const secondPartDisplayTo = fromUs + (clipEnd - toUs);\n const secondPartTrimFrom = clip.trim.from + (toUs - clipStart) * clip.playbackRate;\n const secondPartTrimTo = clip.trim.to;\n\n // Add to the same track\n const track = this.tracks.find((t) => t.clipIds.includes(clip.id));\n if (track) {\n await this.addClip(secondPart, { trackId: track.id });\n await this.updateClip(secondPart.id, {\n display: {\n from: secondPartDisplayFrom,\n to: secondPartDisplayTo,\n },\n trim: {\n from: secondPartTrimFrom,\n to: secondPartTrimTo,\n },\n });\n }\n\n // Adjust first part\n await this.updateClip(clip.id, {\n display: {\n from: clip.display.from,\n to: fromUs,\n },\n trim: {\n from: clip.trim.from,\n to: clip.trim.from + (fromUs - clipStart) * clip.playbackRate,\n },\n });\n continue;\n }\n\n // Case 5: Clip starts before range and ends inside - Cut end\n if (clipStart < fromUs && clipEnd <= toUs) {\n await this.updateClip(clip.id, {\n display: {\n from: clip.display.from,\n to: fromUs,\n },\n trim: {\n from: clip.trim.from,\n to: clip.trim.from + (fromUs - clipStart) * clip.playbackRate,\n },\n });\n continue;\n }\n\n // Case 6: Clip starts inside range and ends after - Cut start and shift\n if (clipStart >= fromUs && clipEnd > toUs) {\n await this.updateClip(clip.id, {\n display: {\n from: fromUs,\n to: fromUs + (clipEnd - toUs),\n },\n trim: {\n from: clip.trim.from + (toUs - clipStart) * clip.playbackRate,\n to: clip.trim.to,\n },\n });\n continue;\n }\n }\n\n await this.recalculateMaxDuration();\n await this.studio.updateFrame(this.studio.currentTime);\n }\n}\n","import diff, { Difference } from \"microdiff\";\nimport { ClipJSON, ProjectJSON, StudioTrackJSON } from \"../json-serialization\";\n\nexport interface HistoryOptions {\n maxSize?: number;\n}\n\nexport interface HistoryState {\n clips: Record<string, ClipJSON>;\n tracks: StudioTrackJSON[];\n settings: any;\n}\n\nexport class HistoryManager {\n private past: Difference[][] = [];\n private future: Difference[][] = [];\n private lastState: HistoryState | null = null;\n private maxSize: number;\n\n constructor(options: HistoryOptions = {}) {\n this.maxSize = options.maxSize || 50;\n }\n\n private projectToHistoryState(project: ProjectJSON): HistoryState {\n const clips: Record<string, ClipJSON> = {};\n const tracks: StudioTrackJSON[] = JSON.parse(JSON.stringify(project.tracks || []));\n\n for (const [id, clip] of Object.entries(project.clips ?? {})) {\n clips[id] = JSON.parse(JSON.stringify(clip));\n }\n\n return {\n clips,\n tracks,\n settings: JSON.parse(JSON.stringify(project.settings || {})),\n };\n }\n\n /**\n * Initialize history with the starting state\n */\n public init(state: ProjectJSON) {\n this.lastState = this.projectToHistoryState(JSON.parse(JSON.stringify(state)));\n this.past = [];\n this.future = [];\n }\n\n /**\n * Push a new state to history. Calculates the diff from the last state.\n */\n public push(newState: ProjectJSON) {\n if (!this.lastState) {\n this.init(newState);\n return;\n }\n\n const currentHistoryState = this.projectToHistoryState(JSON.parse(JSON.stringify(newState)));\n const patches = diff(this.lastState, currentHistoryState);\n\n if (patches.length === 0) return;\n\n this.past.push(patches);\n if (this.past.length > this.maxSize) {\n this.past.shift();\n }\n\n this.future = []; // Clear redo stack on new action\n this.lastState = currentHistoryState;\n }\n\n /**\n * Undo the last action. Returns the patches and the new target state.\n */\n public undo(currentState: ProjectJSON): { patches: Difference[]; state: HistoryState } | null {\n const patches = this.past.pop();\n if (!patches) return null;\n\n const currentHistoryState = this.projectToHistoryState(\n JSON.parse(JSON.stringify(currentState)),\n );\n\n // Calculate new state by reversing patches\n const newState = this.applyPatches(currentHistoryState, patches, true);\n\n this.future.push(patches);\n this.lastState = newState;\n\n return { patches, state: newState };\n }\n\n /**\n * Redo the next action. Returns the patches and the new target state.\n */\n public redo(currentState: ProjectJSON): { patches: Difference[]; state: HistoryState } | null {\n const patches = this.future.pop();\n if (!patches) return null;\n\n const currentHistoryState = this.projectToHistoryState(\n JSON.parse(JSON.stringify(currentState)),\n );\n\n // Calculate new state by applying patches\n const newState = this.applyPatches(currentHistoryState, patches, false);\n this.past.push(patches);\n this.lastState = newState;\n\n return { patches, state: newState };\n }\n\n /**\n * Apply patches to an object.\n */\n private applyPatches(obj: any, patches: Difference[], reverse: boolean): any {\n const newObj = JSON.parse(JSON.stringify(obj));\n const patchesToApply = reverse ? [...patches].reverse() : patches;\n\n for (const patch of patchesToApply) {\n const { type, path } = patch;\n const value = (patch as any).value;\n const oldValue = (patch as any).oldValue;\n\n let target = newObj;\n let skip = false;\n for (let i = 0; i < path.length - 1; i++) {\n if (target[path[i]] === undefined || target[path[i]] === null) {\n // If we are reversing a REMOVE, we might need to recreate the path.\n // However, microdiff should provide the patches in order.\n // For now, let's just be safe and skip if the path is truly broken.\n skip = true;\n break;\n }\n target = target[path[i]];\n }\n\n if (skip) continue;\n\n const lastKey = path[path.length - 1];\n\n if (reverse) {\n switch (type) {\n case \"CREATE\":\n if (Array.isArray(target)) {\n target.splice(lastKey as number, 1);\n } else {\n delete target[lastKey];\n }\n break;\n case \"REMOVE\":\n target[lastKey] =\n oldValue && typeof oldValue === \"object\"\n ? JSON.parse(JSON.stringify(oldValue))\n : oldValue;\n break;\n case \"CHANGE\":\n target[lastKey] =\n oldValue && typeof oldValue === \"object\"\n ? JSON.parse(JSON.stringify(oldValue))\n : oldValue;\n break;\n }\n } else {\n switch (type) {\n case \"CREATE\":\n target[lastKey] =\n value && typeof value === \"object\" ? JSON.parse(JSON.stringify(value)) : value;\n break;\n case \"REMOVE\":\n if (Array.isArray(target)) {\n target.splice(lastKey as number, 1);\n } else {\n delete target[lastKey];\n }\n break;\n case \"CHANGE\":\n target[lastKey] =\n value && typeof value === \"object\" ? JSON.parse(JSON.stringify(value)) : value;\n break;\n }\n }\n }\n\n return newObj;\n }\n\n public canUndo(): boolean {\n return this.past.length > 0;\n }\n\n public canRedo(): boolean {\n return this.future.length > 0;\n }\n}\n","import {\n Application,\n Sprite,\n Texture,\n Container,\n Graphics,\n RenderTexture,\n BlurFilter,\n ColorMatrixFilter,\n Filter,\n GlProgram,\n UniformGroup,\n} from \"pixi.js\";\n\nimport { Caption } from \"./clips/caption-clip\";\nimport { Image } from \"./clips/image-clip\";\nimport type { IClip, IPlaybackCapable } from \"./clips/iclip\";\nimport { Text } from \"./clips/text-clip\";\nimport { Video } from \"./clips/video-clip\";\nimport { Effect } from \"./clips/effect-clip\";\nimport { Transition } from \"./clips/transition-clip\";\nimport { PixiSpriteRenderer, updateSpriteTransform } from \"./sprite/pixi-sprite-renderer\";\nimport { type ProjectJSON } from \"./json-serialization\";\nimport { Transformer } from \"./transformer/transformer\";\nimport type { EffectKey } from \"./effect/glsl/gl-effect\";\nimport { makeEffect } from \"./effect/effect\";\nimport { makeTransition } from \"./transition/transition\";\nimport { parseColor, hexToRgb } from \"./utils/color\";\nimport { vertex } from \"./effect/vertex\";\nimport { SELECTIVE_HSL_FRAGMENT } from \"./effect/glsl/custom-glsl\";\nimport {\n applyColorAdjustmentToMatrix,\n getAllSelectiveHsl,\n hasColorAdjustment,\n} from \"./utils/color-adjustment\";\n\nimport EventEmitter from \"./event-emitter\";\nimport { Core } from \"@agrhub/core\";\nimport { StudioBridge } from \"./studio-bridge\";\n\nexport interface IStudioOpts {\n width: number;\n height: number;\n fps?: number;\n backgroundColor?: string; // Outside workspace backdrop color\n artboardColor?: string; // Artboard background color\n canvas?: HTMLCanvasElement;\n interactivity?: boolean;\n spacing?: number;\n core?: Core;\n allowZoom?: boolean;\n allowPan?: boolean;\n /**\n * Internal rendering resolution multiplier for preview (0-1).\n * e.g., 0.5 renders at half-resolution, improving playback performance.\n * Default is 1.\n */\n previewScale?: number;\n}\n\ninterface ActiveGlobalEffect {\n id: string;\n key: EffectKey;\n startTime: number;\n duration: number;\n trackIndex?: number;\n values?: Record<string, any>;\n}\ninterface GlobalEffectInfo {\n id: string;\n key: EffectKey;\n startTime: number;\n duration: number;\n}\n\nexport interface StudioEvents {\n \"selection:created\": { selected: IClip[] };\n \"selection:updated\": { selected: IClip[] };\n \"selection:cleared\": { deselected: IClip[] };\n \"track:added\": { track: StudioTrack; index?: number };\n \"track:order-changed\": { tracks: StudioTrack[] };\n \"track:removed\": { trackId: string };\n \"clip:added\": { clip: IClip; trackId: string };\n \"clips:added\": { clips: IClip[]; trackId?: string }; // Batch event\n \"clip:removed\": { clipId: string };\n \"clip:updated\": { clip: IClip };\n \"clip:lock-changed\": { clip: IClip; locked: boolean };\n \"clip:replaced\": { oldClip: IClip; newClip: IClip; trackId: string };\n \"studio:restored\": {\n clips: IClip[];\n tracks: StudioTrack[];\n settings: IStudioOpts;\n };\n currentTime: { currentTime: number };\n play: { isPlaying: boolean };\n pause: { isPlaying: boolean };\n \"history:changed\": { canUndo: boolean; canRedo: boolean };\n \"transform:start\": { transformer: Transformer };\n \"transform:end\": { transformer: Transformer };\n \"clip:dblclick\": { clip: IClip };\n \"viewport:changed\": { zoomLevel: number; panOffset: { x: number; y: number } };\n [key: string]: any;\n [key: symbol]: any;\n}\n\nexport interface StudioTrack {\n id: string;\n name: string;\n type: string;\n clipIds: string[];\n /** Silences every clip on the track without changing their own volume/muted */\n muted?: boolean;\n}\n\nimport { SelectionManager } from \"./studio/selection-manager\";\nimport { Transport } from \"./studio/transport\";\nimport { TimelineModel } from \"./studio/timeline-model\";\nimport { HistoryManager, HistoryState } from \"./studio/history-manager\";\nimport { ResourceManager } from \"./studio/resource-manager\";\nimport { jsonToClip } from \"./json-serialization\";\nimport { Difference } from \"microdiff\";\n\nexport class Studio extends EventEmitter<StudioEvents> {\n public selection: SelectionManager;\n public transport: Transport;\n public timeline: TimelineModel;\n public history: HistoryManager;\n public resourceManager: ResourceManager;\n public pixiApp: Application | null = null;\n public get tracks() {\n return this.timeline.tracks;\n }\n public get clips() {\n return this.timeline.clips;\n }\n // BUT I need to remove the getter/setter I added in previous step.\n // And restoring `private clips` property.\n\n public spriteRenderers = new Map<IClip, PixiSpriteRenderer>();\n public artboard: Container | null = null;\n public clipContainer: Container | null = null;\n public artboardMask: Graphics | null = null;\n public artboardBg: Graphics | null = null;\n\n // Transformer for interactive transform controls\n // Transformer for interactive transform controls\n // Delegated to SelectionManager\n public get activeTransformer(): Transformer | null {\n return this.selection.activeTransformer;\n }\n public set activeTransformer(val: Transformer | null) {\n this.selection.activeTransformer = val;\n }\n\n public get selectedClips(): Set<IClip> {\n return this.selection.selectedClips;\n }\n public set selectedClips(val: Set<IClip>) {\n this.selection.selectedClips = val;\n }\n\n public get interactiveClips(): Set<IClip> {\n return this.selection.interactiveClips;\n }\n public set interactiveClips(val: Set<IClip>) {\n this.selection.interactiveClips = val;\n }\n\n // Playback elements for clips that support playback\n public get playbackElements() {\n return this.transport.playbackElements;\n }\n\n public videoSprites = new Map<IClip, Sprite>();\n public clipListeners = new Map<IClip, () => void>();\n // Only for Video\n\n public get isPlaying() {\n return this.transport.isPlaying;\n }\n public set isPlaying(val: boolean) {\n this.transport.isPlaying = val;\n }\n\n public get currentTime() {\n return this.transport.currentTime;\n }\n public set currentTime(val: number) {\n this.transport.currentTime = val;\n }\n\n public get maxDuration() {\n return this.transport.maxDuration;\n }\n public set maxDuration(val: number) {\n this.transport.maxDuration = val;\n }\n\n public opts: Required<Omit<IStudioOpts, \"canvas\" | \"core\">> & {\n canvas?: HTMLCanvasElement;\n core?: Core;\n };\n public destroyed = false;\n private renderingSuspended = false;\n /** Incremented per updateFrame call; only the latest call may apply decoded video frames */\n private frameToken = 0;\n private historyPaused = false;\n private processingHistory = false;\n /**\n * Indicates if the studio is currently restoring state from history (undo/redo)\n */\n public isRestoring = false;\n private historyGroupDepth = 0;\n private clipCache = new Map<string, IClip>();\n private _isUpdatingLayout = false;\n private bridge: StudioBridge | null = null;\n\n // ── Viewport (zoom / pan) ──────────────────────────────────────────────────\n /** User-controlled zoom multiplier on top of the fit-to-screen base scale.\n * 1.0 = 100 % (no extra zoom beyond fit). */\n private _zoomLevel = 1;\n /** Pan offset in canvas/screen pixels, applied after base centering. */\n private _panOffset = { x: 0, y: 0 };\n /** The base fit-to-screen scale last computed by updateArtboardLayout. */\n private _baseScale = 1;\n private _allowZoom = false;\n private _allowPan = false;\n private _isPanning = false;\n private _isSpaceDown = false;\n private _lastPointerPos = { x: 0, y: 0 };\n private _boundOnWheel: ((e: WheelEvent) => void) | null = null;\n private _boundOnPointerDown: ((e: PointerEvent) => void) | null = null;\n private _boundOnPointerMove: ((e: PointerEvent) => void) | null = null;\n private _boundOnPointerUp: ((e: PointerEvent) => void) | null = null;\n private _boundOnKeyDown: ((e: KeyboardEvent) => void) | null = null;\n private _boundOnKeyUp: ((e: KeyboardEvent) => void) | null = null;\n\n // Effect system\n public globalEffects = new Map<string, GlobalEffectInfo>();\n public activeGlobalEffects: ActiveGlobalEffect[] = [];\n // private postProcessContainer: Container; // Removed\n public currentGlobalEffectSprite: Sprite | null = null;\n public effectFilters = new Map<string, Awaited<ReturnType<typeof makeEffect>>>();\n public transitionRenderers = new Map<string, ReturnType<typeof makeTransition>>();\n public transitionSprites = new Map<string, Sprite>();\n public transFromTexture: RenderTexture | null = null;\n public transToTexture: RenderTexture | null = null;\n public transBgGraphics: Graphics | null = null;\n public clipsNormalContainer: Container | null = null;\n public clipsEffectContainer: Container | null = null;\n public videoTextureCache = new WeakMap<HTMLVideoElement, Texture>();\n public lastFromFrame: Texture | ImageBitmap | VideoFrame | null = null;\n public lastToFrame: Texture | ImageBitmap | VideoFrame | null = null;\n /**\n * Convert hex color string to number\n */\n private hexToNumber(hex: string): number {\n // Remove # if present\n const hexStr = hex.startsWith(\"#\") ? hex.slice(1) : hex;\n return parseInt(hexStr, 16);\n }\n\n public ready: Promise<void>;\n /**\n * Create a new Studio instance\n */\n constructor(opts: IStudioOpts) {\n super();\n this.opts = {\n fps: 30,\n backgroundColor: \"#000000\",\n artboardColor: \"#000000\",\n interactivity: true,\n spacing: 0,\n allowZoom: false,\n allowPan: false,\n previewScale: 1,\n ...opts,\n };\n\n this._allowZoom = !!this.opts.allowZoom;\n this._allowPan = !!this.opts.allowPan;\n\n this.selection = new SelectionManager(this);\n this.transport = new Transport(this);\n this.timeline = new TimelineModel(this);\n this.history = new HistoryManager();\n this.resourceManager = new ResourceManager();\n\n this.ready = this.initPixiApp().then(() => {\n // Initialize history with initial state after Pixi is ready and dimensions are set correctly\n this.history.init(this.exportToJSON());\n this._initViewportEvents();\n });\n\n this.on(\"clip:added\", (data) => this.handleTimelineChange(data));\n this.on(\"clips:added\", (data) => this.handleTimelineChange(data));\n this.on(\"clip:replaced\", (data) => this.handleTimelineChange({ clip: data.newClip }));\n this.on(\"studio:restored\", (data) => {\n data.clips.forEach((c) => this.attachClipEvents(c));\n this.handleTimelineChange();\n });\n this.on(\"clip:removed\", this.handleClipRemoved);\n this.on(\"clips:removed\", this.handleClipsRemoved);\n this.on(\"clip:updated\", this.handleTimelineChange);\n this.on(\"track:removed\", () => this.handleTimelineChange());\n this.on(\"track:added\", () => this.handleTimelineChange());\n\n if (this.opts.core) {\n this.bridge = new StudioBridge(this.opts.core, this);\n }\n }\n\n private attachClipEvents(clip: IClip) {\n if (this.clipListeners.has(clip)) return;\n const listener = () => {\n this.updateFrame(this.currentTime);\n };\n clip.on(\"request-render\" as any, listener);\n this.clipListeners.set(clip, listener);\n }\n\n private handleTimelineChange = (data?: { clip?: IClip; clips?: IClip[] }) => {\n if (data?.clip) this.attachClipEvents(data.clip);\n if (data?.clips) data.clips.forEach((c) => this.attachClipEvents(c));\n\n // Force a re-render of the current frame to reflect changes\n this.updateFrame(this.currentTime);\n this.saveHistory();\n };\n\n private saveHistory() {\n if (this.historyPaused || this.processingHistory) return;\n this.history.push(this.exportToJSON());\n this.emit(\"history:changed\", {\n canUndo: this.history.canUndo(),\n canRedo: this.history.canRedo(),\n });\n }\n\n public beginHistoryGroup() {\n // During undo/redo we are replaying history patches; grouping here would\n // incorrectly toggle `historyPaused` and push new history entries mid-restore.\n if (this.processingHistory || this.isRestoring) return;\n this.historyGroupDepth++;\n this.historyPaused = true;\n }\n\n public endHistoryGroup() {\n if (this.processingHistory || this.isRestoring) return;\n this.historyGroupDepth = Math.max(0, this.historyGroupDepth - 1);\n if (this.historyGroupDepth === 0) {\n this.historyPaused = false;\n this.saveHistory();\n }\n }\n\n private setPath(obj: any, path: (string | number)[], value: any) {\n let target = obj;\n for (let i = 0; i < path.length - 1; i++) {\n const key = path[i];\n if (!target[key]) {\n target[key] = typeof path[i + 1] === \"number\" ? [] : {};\n }\n target = target[key];\n }\n target[path[path.length - 1]] = value;\n }\n\n private async applyHistoryPatches(patches: Difference[], state: HistoryState, reverse: boolean) {\n const clipChanges = new Map<string, any>();\n const clipsToAdd = new Map<string, any>();\n const clipsToRemove = new Set<string>();\n\n for (const patch of patches) {\n const { type, path } = patch;\n const value = (patch as any).value;\n const oldValue = (patch as any).oldValue;\n\n if (path[0] === \"clips\") {\n const clipId = path[1] as string;\n if (reverse) {\n if (type === \"CREATE\") clipsToRemove.add(clipId);\n else if (type === \"REMOVE\") clipsToAdd.set(clipId, oldValue);\n else if (type === \"CHANGE\") {\n if (!clipChanges.has(clipId)) clipChanges.set(clipId, {});\n this.setPath(clipChanges.get(clipId), path.slice(2) as (string | number)[], oldValue);\n }\n } else {\n if (type === \"CREATE\") clipsToAdd.set(clipId, value);\n else if (type === \"REMOVE\") clipsToRemove.add(clipId);\n else if (type === \"CHANGE\") {\n if (!clipChanges.has(clipId)) clipChanges.set(clipId, {});\n this.setPath(clipChanges.get(clipId), path.slice(2) as (string | number)[], value);\n }\n }\n } else if (path[0] === \"settings\") {\n if (reverse) {\n this.setPath(this.opts, path.slice(1) as (string | number)[], oldValue);\n } else {\n this.setPath(this.opts, path.slice(1) as (string | number)[], value);\n }\n }\n }\n\n // Apply removals\n for (const clipId of clipsToRemove) {\n const clip = this.timeline.getClipById(clipId);\n if (clip) await this.removeClip(clip);\n }\n\n // Apply additions\n for (const [clipId, clipJSON] of clipsToAdd) {\n let clip = this.clipCache.get(clipId);\n if (!clip) {\n clip = await jsonToClip(clipJSON);\n this.clipCache.set(clipId, clip);\n this.attachClipEvents(clip);\n }\n\n // Find original track ID from target state\n let trackId: string | undefined;\n for (const track of state.tracks) {\n if (track.clipIds.includes(clipId)) {\n trackId = track.id;\n break;\n }\n }\n\n await this.addClip(clip, { trackId });\n }\n\n // Apply property changes\n for (const [clipId, updates] of clipChanges) {\n await this.updateClip(clipId, updates);\n }\n\n // Sync all tracks at once to ensure correct order and clipIds\n this.timeline.setTracks(state.tracks);\n\n // Emit single restore event to sync UI (e.g. Timeline Store)\n // This ensures tracks and clips are perfectly in sync with the engine state\n this.emit(\"studio:restored\", {\n clips: this.clips,\n tracks: this.tracks,\n settings: this.opts,\n });\n }\n\n public async undo() {\n if (!this.history.canUndo() || this.processingHistory) return;\n this.processingHistory = true;\n this.isRestoring = true;\n this.historyPaused = true;\n try {\n const result = this.history.undo(this.exportToJSON());\n if (result) {\n await this.applyHistoryPatches(result.patches, result.state, true);\n }\n this.emit(\"history:changed\", {\n canUndo: this.history.canUndo(),\n canRedo: this.history.canRedo(),\n });\n } finally {\n this.historyPaused = false;\n this.isRestoring = false;\n this.processingHistory = false;\n }\n }\n\n public async redo() {\n if (!this.history.canRedo() || this.processingHistory) return;\n this.processingHistory = true;\n this.isRestoring = true;\n this.historyPaused = true;\n try {\n const result = this.history.redo(this.exportToJSON());\n if (result) {\n await this.applyHistoryPatches(result.patches, result.state, false);\n }\n this.emit(\"history:changed\", {\n canUndo: this.history.canUndo(),\n canRedo: this.history.canRedo(),\n });\n } finally {\n this.historyPaused = false;\n this.isRestoring = false;\n this.processingHistory = false;\n }\n }\n\n private cleanupClipVisuals = (clipId: string) => {\n // 1. Cleanup SpriteRenderers\n for (const [clip, renderer] of this.spriteRenderers) {\n if (clip.id === clipId) {\n // Remove from parent if possible (renderer.getRoot() exists)\n const root = renderer.getRoot();\n if (root && root.parent) {\n root.parent.removeChild(root);\n }\n renderer.destroy();\n this.spriteRenderers.delete(clip);\n break; // Assuming 1:1 map\n }\n }\n\n // 2. Cleanup Transition Sprites\n const transSprite = this.transitionSprites.get(clipId);\n if (transSprite) {\n if (transSprite.parent) {\n transSprite.parent.removeChild(transSprite);\n }\n transSprite.destroy();\n this.transitionSprites.delete(clipId);\n }\n\n // 3. Cleanup Transition Renderers\n const transRenderer = this.transitionRenderers.get(clipId);\n if (transRenderer) {\n // transRenderer might not have destroy, just remove from map\n this.transitionRenderers.delete(clipId);\n }\n\n // 4. Cleanup Video Sprites\n for (const [clip, sprite] of this.videoSprites) {\n if (clip.id === clipId) {\n if (sprite.parent) {\n sprite.parent.removeChild(sprite);\n }\n sprite.destroy();\n this.videoSprites.delete(clip);\n break;\n }\n }\n\n // 5. Cleanup Clip Listeners\n const clip = this.timeline.getClipById(clipId);\n if (clip) {\n const listener = this.clipListeners.get(clip);\n if (listener) {\n clip.off(\"request-render\" as any, listener);\n this.clipListeners.delete(clip);\n }\n }\n };\n\n private handleClipRemoved = ({ clipId }: { clipId: string }) => {\n this.cleanupClipVisuals(clipId);\n this.updateFrame(this.currentTime);\n this.saveHistory();\n };\n\n private handleClipsRemoved = ({ clipIds }: { clipIds: string[] }) => {\n for (const clipId of clipIds) {\n this.cleanupClipVisuals(clipId);\n }\n this.updateFrame(this.currentTime);\n this.saveHistory();\n };\n\n private async initPixiApp(): Promise<void> {\n if (this.destroyed) return;\n const canvas = this.opts.canvas || document.createElement(\"canvas\");\n canvas.width = this.opts.width;\n canvas.height = this.opts.height;\n\n const app = new Application();\n // Use the parent element for resizing if available, otherwise fallback to window\n // This allows the Pixi canvas to fill its container (Player component)\n const resizeTo = canvas.parentElement || window;\n\n await app.init({\n canvas,\n resizeTo, // Auto-resize to fill the container\n // width/height are derived from resizeTo, so we don't set them explicitly for the renderer\n backgroundColor: this.hexToNumber(this.opts.backgroundColor),\n antialias: true,\n resolution: (window.devicePixelRatio || 1) * this.opts.previewScale,\n autoDensity: true,\n autoStart: false, // Prevent auto-rendering to avoid race conditions during async updates\n });\n this.pixiApp = app;\n\n // Sync current background color to the renderer in case it changed during asynchronous initialization\n app.renderer.background.color = this.hexToNumber(this.opts.backgroundColor);\n\n // Trigger initial render to avoid black screen\n app.render();\n\n // Make stage interactive to handle clicks on empty space\n app.stage.eventMode = \"static\";\n app.stage.hitArea = app.screen;\n\n // Initialize Artboard (Root Container for Viewport)\n this.artboard = new Container();\n this.artboard.label = \"ArtboardRoot\";\n app.stage.addChild(this.artboard);\n\n this.selection.init(app, this.artboard);\n\n // Create background for Artboard (in clip container)\n this.artboardBg = new Graphics();\n this.artboardBg\n .rect(0, 0, this.opts.width, this.opts.height)\n .fill({ color: this.hexToNumber(this.opts.artboardColor) });\n this.artboard.addChild(this.artboardBg);\n\n // Initialize Clip Container (Masked Content)\n this.clipContainer = new Container();\n this.clipContainer.label = \"ClipContainer\";\n this.artboard.addChild(this.clipContainer);\n // Create mask for Clip Container\n this.artboardMask = new Graphics();\n this.artboardMask.rect(0, 0, this.opts.width, this.opts.height).fill({ color: 0xffffff });\n this.clipContainer.addChild(this.artboardMask);\n this.clipContainer.mask = this.artboardMask;\n\n //effectContainer\n this.clipsEffectContainer = new Container();\n this.clipsEffectContainer.label = \"ClipsEffect\";\n this.clipsEffectContainer.visible = false;\n this.clipsEffectContainer.zIndex = 1; // Lowest\n this.clipsEffectContainer.sortableChildren = true;\n this.clipContainer.addChild(this.clipsEffectContainer);\n\n this.clipsNormalContainer = new Container();\n this.clipsNormalContainer.label = \"ClipsNormal\";\n this.clipsNormalContainer.zIndex = 10; // Highest (above effect)\n this.clipsNormalContainer.sortableChildren = true;\n this.clipContainer.addChild(this.clipsNormalContainer);\n\n // Initialize Transition helper objects\n this.recreateTransitionTextures();\n this.transBgGraphics = new Graphics();\n this.transBgGraphics.rect(0, 0, this.opts.width, this.opts.height).fill({\n color: 0x000000,\n alpha: 0,\n });\n\n // Enable sorting on parent to respect zIndex\n this.clipContainer.sortableChildren = true;\n\n // Artboard itself is NOT masked, so children added directly to it (like transformer)\n // will be visible outside the bounds.\n\n // Initial positioning\n this.updateArtboardLayout();\n\n // Listen for resize from Pixi renderer (since we used resizeTo)\n // This handles both window resize and container resize automatically\n app.renderer.on(\"resize\", () => {\n this.handleResize();\n });\n // Removed postProcessContainer usage\n }\n\n /**\n * Get studio options\n */\n public getOptions(): IStudioOpts {\n return this.opts;\n }\n\n /**\n * Update studio dimensions\n */\n public setSize(width: number, height: number) {\n this.updateDimensions(width, height);\n }\n\n /**\n * Set the preview resolution scale dynamically\n * @param scale A multiplier between 0.1 and 1\n */\n public setPreviewScale(scale: number): void {\n this.opts.previewScale = Math.max(0.1, Math.min(1, scale));\n if (this.pixiApp) {\n this.pixiApp.renderer.resolution = (window.devicePixelRatio || 1) * this.opts.previewScale;\n this.pixiApp.resize();\n }\n this.recreateTransitionTextures();\n this.updateArtboardLayout();\n this.updateFrame(this.currentTime);\n }\n\n private recreateTransitionTextures(): void {\n if (this.transFromTexture) {\n this.transFromTexture.destroy(true);\n this.transFromTexture = null;\n }\n if (this.transToTexture) {\n this.transToTexture.destroy(true);\n this.transToTexture = null;\n }\n\n this.transFromTexture = RenderTexture.create({\n width: this.opts.width,\n height: this.opts.height,\n resolution: this.opts.previewScale,\n });\n this.transToTexture = RenderTexture.create({\n width: this.opts.width,\n height: this.opts.height,\n resolution: this.opts.previewScale,\n });\n }\n\n /**\n * Update the background color of the studio (applies to the outside area)\n */\n public setBackgroundColor(color: string) {\n this.opts.backgroundColor = color;\n const colorNum = this.hexToNumber(color);\n\n if (this.pixiApp) {\n this.pixiApp.renderer.background.color = colorNum;\n this.pixiApp.render();\n }\n\n this.updateFrame(this.currentTime);\n }\n\n /**\n * Update the artboard background color of the studio (applies to the video frame itself)\n */\n public setArtboardColor(color: string) {\n this.opts.artboardColor = color;\n const colorNum = this.hexToNumber(color);\n\n if (this.artboardBg) {\n this.artboardBg\n .clear()\n .rect(0, 0, this.opts.width, this.opts.height)\n .fill({ color: colorNum });\n }\n\n if (this.pixiApp) {\n this.pixiApp.render();\n }\n\n this.updateFrame(this.currentTime);\n }\n\n public updateDimensions(width: number, height: number) {\n this.opts.width = width;\n this.opts.height = height;\n\n if (this.artboardBg) {\n this.artboardBg\n .clear()\n .rect(0, 0, width, height)\n .fill({ color: this.hexToNumber(this.opts.artboardColor) });\n }\n if (this.artboardMask) {\n this.artboardMask.clear().rect(0, 0, width, height).fill({ color: 0xffffff });\n }\n\n this.recreateTransitionTextures();\n if (this.transBgGraphics) {\n this.transBgGraphics.clear().rect(0, 0, width, height).fill({ color: 0x000000, alpha: 0 });\n }\n\n this.updateArtboardLayout();\n this.updateFrame(this.currentTime);\n }\n\n private handleResize = () => {\n if (this.destroyed || !this.pixiApp || this._isUpdatingLayout) return;\n this.updateArtboardLayout();\n };\n\n public updateArtboardLayout(options: { skipResize?: boolean } = {}) {\n if (!this.pixiApp || !this.artboard || this._isUpdatingLayout) return;\n this._isUpdatingLayout = true;\n\n try {\n // Force PIXI to resize its renderer to match its container (if resizeTo is set)\n if (!options.skipResize) {\n this.pixiApp.resize();\n }\n\n const canvas = this.pixiApp.canvas as HTMLCanvasElement;\n const parent = canvas.parentElement;\n\n // Use the parent's bounding rect if available, as clientWidth/Height might be 0 during initial mount or reflow\n const containerWidth = parent\n ? parent.getBoundingClientRect().width\n : this.pixiApp.screen.width;\n const containerHeight = parent\n ? parent.getBoundingClientRect().height\n : this.pixiApp.screen.height;\n\n // Artboard logical size (the \"true\" size of our project)\n const artboardWidth = this.opts.width;\n const artboardHeight = this.opts.height;\n\n const spacing = this.opts.spacing || 0;\n const containerWidthWithSpacing = Math.max(0, containerWidth - spacing * 2);\n const containerHeightWithSpacing = Math.max(0, containerHeight - spacing * 2);\n\n // Calculate scale to fit artboard in container with spacing\n const scaleX = containerWidthWithSpacing / artboardWidth;\n const scaleY = containerHeightWithSpacing / artboardHeight;\n const baseScale = Math.min(scaleX, scaleY);\n this._baseScale = baseScale;\n\n // Apply combined scale: base fit-to-screen × user zoom level\n const totalScale = baseScale * this._zoomLevel;\n this.artboard.scale.set(totalScale);\n\n // Center the artboard, then apply user pan offset\n this.artboard.x = (containerWidth - artboardWidth * totalScale) / 2 + this._panOffset.x;\n this.artboard.y = (containerHeight - artboardHeight * totalScale) / 2 + this._panOffset.y;\n\n // Ensure we render the layout change if ticker is not running\n this.pixiApp.render();\n\n // Notify listeners (e.g. zoom HUD)\n this.emit(\"viewport:changed\", {\n zoomLevel: this._zoomLevel,\n panOffset: { ...this._panOffset },\n });\n } finally {\n this._isUpdatingLayout = false;\n }\n }\n\n // ── Viewport API ────────────────────────────────────────────────────────────\n\n /** Current user zoom level (1 = fit-to-screen, 2 = 200 %, etc.). */\n public get zoomLevel(): number {\n return this._zoomLevel;\n }\n\n /** Base fit-to-screen scale (read-only, recomputed on every layout update). */\n public get baseScale(): number {\n return this._baseScale;\n }\n\n /**\n * Set the user zoom level.\n * @param level Desired zoom (1 = fit-to-screen). Clamped to [0.1, 10].\n * @param originX Optional canvas-space X to zoom toward (defaults to center).\n * @param originY Optional canvas-space Y to zoom toward (defaults to center).\n */\n public setZoom(level: number, originX?: number, originY?: number): void {\n if (!this.pixiApp || !this.artboard) return;\n\n const prevZoom = this._zoomLevel;\n const nextZoom = Math.min(10, Math.max(0.1, level));\n if (prevZoom === nextZoom) return;\n\n // Adjust pan so the zoom origin stays fixed under the cursor\n if (originX !== undefined && originY !== undefined) {\n const canvas = this.pixiApp.canvas as HTMLCanvasElement;\n const parent = canvas.parentElement;\n const containerWidth = parent\n ? parent.getBoundingClientRect().width\n : this.pixiApp.screen.width;\n const containerHeight = parent\n ? parent.getBoundingClientRect().height\n : this.pixiApp.screen.height;\n\n const baseScale = this._baseScale;\n const prevTotalScale = baseScale * prevZoom;\n const nextTotalScale = baseScale * nextZoom;\n\n const artW = this.opts.width;\n const artH = this.opts.height;\n\n // Current artboard origin (top-left) in screen space\n const prevOriginX = (containerWidth - artW * prevTotalScale) / 2 + this._panOffset.x;\n const prevOriginY = (containerHeight - artH * prevTotalScale) / 2 + this._panOffset.y;\n\n // The point relative to the artboard origin\n const relX = originX - prevOriginX;\n const relY = originY - prevOriginY;\n\n // After scaling, that point should remain at the same screen position\n const scaleFactor = nextTotalScale / prevTotalScale;\n const newOriginX = originX - relX * scaleFactor;\n const newOriginY = originY - relY * scaleFactor;\n\n this._panOffset.x = newOriginX - (containerWidth - artW * nextTotalScale) / 2;\n this._panOffset.y = newOriginY - (containerHeight - artH * nextTotalScale) / 2;\n }\n\n this._zoomLevel = nextZoom;\n this.updateArtboardLayout({ skipResize: true });\n }\n\n /**\n * Apply a relative pan (delta in screen pixels).\n */\n public pan(dx: number, dy: number): void {\n this._panOffset.x += dx;\n this._panOffset.y += dy;\n this.updateArtboardLayout({ skipResize: true });\n }\n\n /**\n * Reset zoom to 1× (fit-to-screen) and clear pan offset.\n */\n public resetView(): void {\n this._zoomLevel = 1;\n this._panOffset = { x: 0, y: 0 };\n this.updateArtboardLayout();\n }\n\n public setAllowZoom(enabled: boolean) {\n this._allowZoom = enabled;\n }\n\n public setAllowPan(enabled: boolean) {\n this._allowPan = enabled;\n }\n\n private _initViewportEvents() {\n if (!this.pixiApp) return;\n const canvas = this.pixiApp.canvas as HTMLCanvasElement;\n\n // 1. Wheel handler (Zoom & Pan)\n this._boundOnWheel = (e: WheelEvent) => {\n if (!this._allowZoom && !this._allowPan) return;\n e.preventDefault();\n\n // Detect if we're on a touchpad (fractional deltas) or discrete mouse wheel\n const isTouchpad =\n Math.abs(e.deltaY) > 0 &&\n Math.abs(e.deltaY) < 100 &&\n Math.floor(e.deltaY) !== Math.ceil(e.deltaY);\n\n if (e.ctrlKey || e.metaKey) {\n if (!this._allowZoom) return;\n // Zooming\n const rect = canvas.getBoundingClientRect();\n const cursorX = e.clientX - rect.left;\n const cursorY = e.clientY - rect.top;\n\n const speed = isTouchpad ? 0.992 : 0.996;\n const zoomFactor = Math.pow(speed, e.deltaY);\n\n const nextZoom = this._zoomLevel * zoomFactor;\n this.setZoom(nextZoom, cursorX, cursorY);\n } else {\n if (!this._allowPan) return;\n // Panning\n let dx = e.deltaX;\n let dy = e.deltaY;\n\n if (e.deltaMode === 1) {\n dx *= 25;\n dy *= 25;\n } else if (e.deltaMode === 2) {\n dx *= 400;\n dy *= 400;\n }\n\n this.pan(-dx, -dy);\n }\n };\n\n // 2. Pointer handlers (Drag Panning)\n this._boundOnPointerDown = (e: PointerEvent) => {\n if (!this._allowPan) return;\n // Middle mouse OR Space + Left click\n if (e.button === 1 || (e.button === 0 && this._isSpaceDown)) {\n this._isPanning = true;\n this._lastPointerPos = { x: e.clientX, y: e.clientY };\n canvas.setPointerCapture(e.pointerId);\n canvas.style.cursor = \"grabbing\";\n e.preventDefault();\n }\n };\n\n this._boundOnPointerMove = (e: PointerEvent) => {\n if (!this._isPanning) return;\n const dx = e.clientX - this._lastPointerPos.x;\n const dy = e.clientY - this._lastPointerPos.y;\n this._lastPointerPos = { x: e.clientX, y: e.clientY };\n this.pan(dx, dy);\n };\n\n this._boundOnPointerUp = (_e: PointerEvent) => {\n if (!this._isPanning) return;\n this._isPanning = false;\n canvas.style.cursor = this._isSpaceDown ? \"grab\" : \"\";\n };\n\n // 3. Keyboard handlers (Space Key)\n this._boundOnKeyDown = (e: KeyboardEvent) => {\n if (!this._allowPan) return;\n if (e.code === \"Space\" && !e.repeat) {\n const tag = (document.activeElement as HTMLElement)?.tagName;\n if (tag === \"INPUT\" || tag === \"TEXTAREA\") return;\n this._isSpaceDown = true;\n canvas.style.cursor = \"grab\";\n e.preventDefault();\n }\n };\n\n this._boundOnKeyUp = (e: KeyboardEvent) => {\n if (e.code === \"Space\") {\n this._isSpaceDown = false;\n if (!this._isPanning) canvas.style.cursor = \"\";\n }\n };\n\n canvas.addEventListener(\"wheel\", this._boundOnWheel, { passive: false });\n canvas.addEventListener(\"pointerdown\", this._boundOnPointerDown);\n window.addEventListener(\"pointermove\", this._boundOnPointerMove);\n window.addEventListener(\"pointerup\", this._boundOnPointerUp);\n window.addEventListener(\"pointercancel\", this._boundOnPointerUp);\n window.addEventListener(\"keydown\", this._boundOnKeyDown);\n window.addEventListener(\"keyup\", this._boundOnKeyUp);\n }\n\n private _destroyViewportEvents() {\n const canvas = this.pixiApp?.canvas as HTMLCanvasElement;\n if (canvas && this._boundOnWheel) {\n canvas.removeEventListener(\"wheel\", this._boundOnWheel);\n }\n if (canvas && this._boundOnPointerDown) {\n canvas.removeEventListener(\"pointerdown\", this._boundOnPointerDown);\n }\n if (this._boundOnPointerMove) {\n window.removeEventListener(\"pointermove\", this._boundOnPointerMove);\n }\n if (this._boundOnPointerUp) {\n window.removeEventListener(\"pointerup\", this._boundOnPointerUp);\n window.removeEventListener(\"pointercancel\", this._boundOnPointerUp);\n }\n if (this._boundOnKeyDown) {\n window.removeEventListener(\"keydown\", this._boundOnKeyDown);\n }\n if (this._boundOnKeyUp) {\n window.removeEventListener(\"keyup\", this._boundOnKeyUp);\n }\n }\n\n /**\n * Get the canvas element (creates one if not provided)\n */\n getCanvas(): HTMLCanvasElement {\n if (this.opts.canvas) {\n return this.opts.canvas;\n }\n if (this.pixiApp?.canvas) {\n return this.pixiApp.canvas as HTMLCanvasElement;\n }\n throw new Error(\"Canvas not initialized yet. Wait for initPixiApp to complete.\");\n }\n\n async addTransition(\n transitionKey: string,\n duration: number = 2000000,\n fromClipId?: string | null,\n toClipId?: string | null,\n id?: string,\n ): Promise<void> {\n return this.timeline.addTransition(transitionKey, duration, fromClipId, toClipId, id);\n }\n\n findTrackIdByClipId(clipId: string): string | undefined {\n return this.timeline.findTrackIdByClipId(clipId);\n }\n\n /**\n * Add a clip (or clips) to the studio\n * @param clipOrClips The clip or array of clips to add\n * @param options Options for addition (trackId, etc.)\n */\n async addClip(\n clipOrClips: IClip | IClip[],\n options?:\n | {\n trackId?: string;\n audioSource?: string | File | Blob;\n }\n | string\n | File\n | Blob,\n ): Promise<void> {\n const clips = Array.isArray(clipOrClips) ? clipOrClips : [clipOrClips];\n clips.forEach((c) => this.clipCache.set(c.id, c));\n\n this.beginHistoryGroup();\n try {\n const result = await this.timeline.addClip(clipOrClips, options);\n clips.forEach((c) => this.attachClipEvents(c));\n return result;\n } finally {\n this.endHistoryGroup();\n }\n }\n\n /**\n * Add a new track to the studio\n */\n addTrack(track: { name: string; type: string; id?: string }, index?: number): StudioTrack {\n return this.timeline.addTrack(track, index);\n }\n\n async setTracks(tracks: StudioTrack[]): Promise<void> {\n if (this.isRestoring) return;\n // Stale editor sync can pass [] or tracks whose clipIds no longer match\n // timeline.clips (e.g. redo vs Zustand timing). reconcileTracks() would drop\n // all rows and emit track:order-changed with [], wiping the timeline UI.\n const clipIds = new Set(this.timeline.clips.map((c) => c.id));\n if (tracks.length === 0 && clipIds.size > 0) {\n return;\n }\n if (tracks.length > 0 && clipIds.size > 0) {\n const anyKnown = tracks.some((t) => t.clipIds.some((id) => clipIds.has(id)));\n if (!anyKnown) {\n return;\n }\n }\n return this.timeline.setTracks(tracks);\n }\n\n /**\n * Move a track to a new index\n */\n public async moveTrack(trackId: string, newIndex: number): Promise<void> {\n return this.timeline.moveTrack(trackId, newIndex);\n }\n\n /**\n * Set the order of tracks by ID\n */\n public async setTrackOrder(trackIds: string[]): Promise<void> {\n return this.timeline.setTrackOrder(trackIds);\n }\n\n async removeTrack(trackId: string): Promise<void> {\n return this.timeline.removeTrack(trackId);\n }\n\n /**\n * Get a clip by its ID\n */\n public getClipById(id: string): IClip | undefined {\n return this.timeline.getClipById(id);\n }\n\n async updateClip(id: string, updates: Partial<IClip>): Promise<void> {\n return this.timeline.updateClip(id, updates);\n }\n\n /**\n * Centers object vertically and horizontally in the studio\n */\n async centerClip(clipOrId: IClip | string): Promise<void> {\n const clip = typeof clipOrId === \"string\" ? this.getClipById(clipOrId) : clipOrId;\n if (!clip) return;\n const left = (this.opts.width - clip.width) / 2;\n const top = (this.opts.height - clip.height) / 2;\n\n if (this.getClipById(clip.id)) {\n return this.updateClip(clip.id, { left, top });\n } else {\n clip.left = left;\n clip.top = top;\n }\n }\n\n /**\n * Centers object horizontally in the studio\n */\n async centerClipH(clipOrId: IClip | string): Promise<void> {\n const clip = typeof clipOrId === \"string\" ? this.getClipById(clipOrId) : clipOrId;\n if (!clip) return;\n const left = (this.opts.width - clip.width) / 2;\n\n if (this.getClipById(clip.id)) {\n return this.updateClip(clip.id, { left });\n } else {\n clip.left = left;\n }\n }\n\n /**\n * Centers object vertically in the studio\n */\n async centerClipV(clipOrId: IClip | string): Promise<void> {\n const clip = typeof clipOrId === \"string\" ? this.getClipById(clipOrId) : clipOrId;\n if (!clip) return;\n const top = (this.opts.height - clip.height) / 2;\n\n if (this.getClipById(clip.id)) {\n return this.updateClip(clip.id, { top });\n } else {\n clip.top = top;\n }\n }\n\n /**\n * Scale clip to fit within the studio dimensions while maintaining aspect ratio\n */\n async scaleToFit(clipOrId: IClip | string): Promise<void> {\n const clip = typeof clipOrId === \"string\" ? this.getClipById(clipOrId) : clipOrId;\n if (!clip) return;\n\n const meta = await clip.ready;\n const { width: origWidth, height: origHeight } = meta;\n if (origWidth === 0 || origHeight === 0) return;\n\n const scale = Math.min(this.opts.width / origWidth, this.opts.height / origHeight);\n const width = origWidth * scale;\n const height = origHeight * scale;\n\n if (this.getClipById(clip.id)) {\n return this.updateClip(clip.id, { width, height });\n } else {\n clip.width = width;\n clip.height = height;\n }\n }\n\n /**\n * Scale clip to fill the studio dimensions while maintaining aspect ratio\n */\n async scaleToCover(clipOrId: IClip | string): Promise<void> {\n const clip = typeof clipOrId === \"string\" ? this.getClipById(clipOrId) : clipOrId;\n if (!clip) return;\n\n const meta = await clip.ready;\n const { width: origWidth, height: origHeight } = meta;\n if (origWidth === 0 || origHeight === 0) return;\n\n const scale = Math.max(this.opts.width / origWidth, this.opts.height / origHeight);\n const width = origWidth * scale;\n const height = origHeight * scale;\n\n if (this.getClipById(clip.id)) {\n return this.updateClip(clip.id, { width, height });\n } else {\n clip.width = width;\n clip.height = height;\n }\n }\n\n async updateClips(updates: { id: string; updates: Partial<IClip> }[]): Promise<void> {\n this.suspendRendering();\n await this.timeline.updateClips(updates);\n this.resumeRendering();\n this.updateFrame(this.currentTime);\n }\n\n suspendRendering() {\n this.renderingSuspended = true;\n }\n\n resumeRendering() {\n this.renderingSuspended = false;\n }\n\n getTracks(): StudioTrack[] {\n return this.timeline.tracks;\n }\n\n getClip(id: string): IClip | undefined {\n return this.timeline.getClipById(id);\n }\n\n findClip(id: string): IClip | undefined {\n return this.timeline.getClipById(id);\n }\n\n /**\n * Setup sprite interactivity for click selection\n * Delegated to SelectionManager\n */\n public setupSpriteInteractivity(clip: IClip): void {\n this.selection.setupSpriteInteractivity(clip);\n }\n\n /**\n * Setup playback element for a clip (if it supports playback)\n */\n\n /**\n * Remove a clip from the studio\n */\n async removeClip(clipOrId: IClip | string): Promise<void> {\n const clip = typeof clipOrId === \"string\" ? this.getClipById(clipOrId) : clipOrId;\n\n if (!clip) {\n console.warn(`[Studio] removeClip: Clip not found`, clipOrId);\n return;\n }\n\n this.beginHistoryGroup();\n try {\n this.clipCache.set(clip.id, clip);\n return this.timeline.removeClip(clip, {\n permanent: !this.processingHistory,\n });\n } finally {\n this.endHistoryGroup();\n }\n }\n\n async removeClips(clips: IClip[]): Promise<void> {\n this.beginHistoryGroup();\n try {\n clips.forEach((c) => this.clipCache.set(c.id, c));\n return this.timeline.removeClips(clips, {\n permanent: !this.processingHistory,\n });\n } finally {\n this.endHistoryGroup();\n }\n }\n\n async removeClipById(clipId: string): Promise<void> {\n const clip = this.timeline.getClipById(clipId);\n if (clip) return this.removeClip(clip);\n }\n\n async removeClipsById(clipIds: string[]): Promise<void> {\n const clips = clipIds.map((id) => this.timeline.getClipById(id)).filter(Boolean) as IClip[];\n return this.removeClips(clips);\n }\n\n /**\n * Delete all currently selected clips\n */\n async deleteSelected(): Promise<void> {\n const selectedClips = this.selection.selectedClips;\n if (selectedClips.size === 0) return;\n\n this.beginHistoryGroup();\n try {\n await this.removeClips(Array.from(selectedClips));\n } finally {\n this.endHistoryGroup();\n }\n }\n\n async duplicateSelected(): Promise<void> {\n this.beginHistoryGroup();\n try {\n return await this.timeline.duplicateSelected();\n } finally {\n this.endHistoryGroup();\n }\n }\n\n async splitSelected(splitTime?: number): Promise<void> {\n this.beginHistoryGroup();\n try {\n return await this.timeline.splitSelected(splitTime);\n } finally {\n this.endHistoryGroup();\n }\n }\n\n async trimSelected(trimFromSeconds: number): Promise<void> {\n return this.timeline.trimSelected(trimFromSeconds);\n }\n\n async updateSelected(updates: Partial<IClip>): Promise<void> {\n return this.timeline.updateSelected(updates);\n }\n\n /**\n * Clear all clips from the studio\n */\n async clear(): Promise<void> {\n await this.timeline.clear();\n\n // Clear Studio-specific textures\n if (this.transFromTexture) {\n this.transFromTexture.destroy(true);\n this.transFromTexture = null;\n }\n if (this.transToTexture) {\n this.transToTexture.destroy(true);\n this.transToTexture = null;\n }\n if (this.transBgGraphics) {\n this.transBgGraphics.destroy(true);\n this.transBgGraphics = null;\n }\n this.transitionRenderers.forEach((r: any) => r.destroy());\n this.transitionRenderers.clear();\n this.transitionSprites.forEach((s) => s.destroy());\n this.transitionSprites.clear();\n\n this.emit(\"reset\");\n }\n\n /**\n * Start playback\n */\n async play(): Promise<void> {\n return this.transport.play();\n }\n\n /**\n * Pause playback\n */\n pause(): void {\n this.transport.pause();\n }\n\n /**\n * Stop playback and reset to start\n */\n async stop(): Promise<void> {\n return this.transport.stop();\n }\n\n /**\n * Seek to a specific time (in microseconds)\n */\n async seek(time: number): Promise<void> {\n return this.transport.seek(time);\n }\n\n /**\n * Move to the next frame\n */\n async frameNext(): Promise<void> {\n return this.transport.frameNext();\n }\n\n /**\n * Move to the previous frame\n */\n async framePrev(): Promise<void> {\n return this.transport.framePrev();\n }\n\n /**\n * Renders the frame at the given time and returns it as a base64-encoded PNG.\n *\n * The artboard is temporarily reset to 1:1 scale during extraction so the\n * output image always matches the project's configured width × height,\n * regardless of the current viewport zoom.\n *\n * @param timeMs Time in milliseconds\n * @param options.transparent If true, the artboard background fill is\n * hidden so the resulting PNG has a transparent background.\n * @returns Base64 data-URL string (e.g. \"data:image/png;base64,...\")\n *\n * @example\n * await studio.ready;\n * const frame = await studio.renderFrame(1500); // frame at 1.5 s\n * const transparent = await studio.renderFrame(1500, { transparent: true });\n * const img = document.createElement('img');\n * img.src = frame;\n */\n public async renderFrame(timeMs: number, options?: { transparent?: boolean }): Promise<string> {\n await this.ready;\n if (!this.pixiApp || !this.artboard) {\n throw new Error(\n \"Studio is not initialized yet. Wait for studio.ready before calling renderFrame().\",\n );\n }\n\n // Convert milliseconds → microseconds (internal timeline unit)\n const timeUs = timeMs * 1000;\n\n // Render the scene at the requested time\n await this.updateFrame(timeUs);\n\n // Temporarily reset artboard transform so extract covers exactly the\n // project dimensions (width × height) at pixel-perfect 1:1 resolution.\n const prevScale = this.artboard.scale.clone();\n const prevX = this.artboard.x;\n const prevY = this.artboard.y;\n\n this.artboard.scale.set(1);\n this.artboard.x = 0;\n this.artboard.y = 0;\n\n // Hide the artboard background fill when transparency is requested.\n const transparent = options?.transparent ?? false;\n if (transparent && this.artboardBg) {\n this.artboardBg.visible = false;\n }\n\n // Render into a fixed-size texture so the output always matches the\n // project's configured width × height, even when the background fill is\n // hidden and the artboard's visible bounds would otherwise shrink to\n // only the content.\n const renderTexture = RenderTexture.create({\n width: this.opts.width,\n height: this.opts.height,\n });\n\n // Make the renderer background transparent when requested so the\n // render-texture clear color has alpha 0.\n const prevBgAlpha = this.pixiApp.renderer.background.alpha;\n if (transparent) {\n this.pixiApp.renderer.background.alpha = 0;\n }\n\n let base64: string;\n try {\n this.pixiApp.renderer.render({\n container: this.artboard,\n target: renderTexture,\n clear: true,\n });\n base64 = await (this.pixiApp.renderer.extract as any).base64(renderTexture, \"image/png\", 1);\n } finally {\n renderTexture.destroy();\n // Always restore the original artboard layout\n if (transparent) {\n this.pixiApp.renderer.background.alpha = prevBgAlpha;\n }\n if (transparent && this.artboardBg) {\n this.artboardBg.visible = true;\n }\n this.artboard.scale.set(prevScale.x, prevScale.y);\n this.artboard.x = prevX;\n this.artboard.y = prevY;\n this.pixiApp.render();\n }\n\n return base64;\n }\n\n /**\n * Alias for {@link renderFrame} with support for the current playhead.\n * Captures a single frame as a base64-encoded PNG.\n *\n * @param timeMs Optional time in milliseconds, or an options object. If\n * omitted, the current playhead position is used.\n * @param options.transparent If true, the artboard background fill is\n * hidden so the resulting PNG has a transparent background.\n * @returns Base64 data-URL string (e.g. \"data:image/png;base64,...\")\n *\n * @example\n * await studio.ready;\n * const currentFrame = await studio.snapshot(); // current playhead\n * const frameAt2s = await studio.snapshot(2000); // explicit timestamp\n * const transparent = await studio.snapshot({ transparent: true }); // current frame, transparent\n * const transparent2s = await studio.snapshot(2000, { transparent: true });\n */\n public async snapshot(timeMs?: number | { transparent?: boolean }): Promise<string>;\n public async snapshot(\n timeMs?: number | { transparent?: boolean },\n options?: { transparent?: boolean },\n ): Promise<string> {\n const opts = typeof timeMs === \"number\" ? options : timeMs;\n const ms = typeof timeMs === \"number\" ? timeMs : undefined;\n return this.renderFrame(ms ?? this.currentTime / 1000, opts);\n }\n\n /**\n * Get current playback time (in microseconds)\n */\n getCurrentTime(): number {\n return this.transport.currentTime;\n }\n\n /**\n * Get maximum duration (in microseconds)\n */\n getMaxDuration(): number {\n return this.transport.maxDuration;\n }\n\n /**\n * Check if currently playing\n */\n getIsPlaying(): boolean {\n return this.transport.isPlaying;\n }\n\n /**\n * Get currently selected clips\n */\n getSelectedClips(): IClip[] {\n return Array.from(this.selectedClips);\n }\n\n // renderLoop deleted (moved to PlaybackController)\n\n private getVideoTexture(video: HTMLVideoElement): Texture {\n let texture = this.videoTextureCache.get(video);\n if (!texture) {\n texture = Texture.from(video);\n this.videoTextureCache.set(video, texture);\n }\n return texture;\n }\n private isPlaybackCapable(clip: IClip): clip is IClip & IPlaybackCapable {\n return (\n \"createPlaybackElement\" in clip &&\n \"play\" in clip &&\n \"pause\" in clip &&\n \"seek\" in clip &&\n \"syncPlayback\" in clip &&\n \"cleanupPlayback\" in clip\n );\n }\n\n public async updateFrame(timestamp: number): Promise<void> {\n if (this.destroyed || this.pixiApp == null || this.renderingSuspended) return;\n const frameToken = ++this.frameToken;\n this.updateActiveGlobalEffect(timestamp);\n\n const usedTransitionSprites = new Set<string>();\n const renderedTransitions = new Set<string>();\n const clipsClaimedByTransition = new Set<string>();\n\n // Apply Z-index based on track order\n // Track 0 (Top) should have highest Z-index\n // This ensures correct visual stacking even when clips are re-parented\n const totalTracks = this.tracks.length;\n for (const clip of this.clips) {\n const trackIndex = this.getTrackIndex(clip.id);\n if (trackIndex !== -1) {\n // Track 0 -> Highest Z\n const zIndex = (totalTracks - trackIndex) * 10;\n clip.zIndex = zIndex;\n\n // Also update renderer root zIndex\n const renderer = this.spriteRenderers.get(clip);\n if (renderer) {\n const root = renderer.getRoot();\n if (root) {\n root.zIndex = zIndex;\n }\n }\n\n // Also update video sprite zIndex immediately\n const videoSprite = this.videoSprites.get(clip);\n if (videoSprite) {\n videoSprite.zIndex = zIndex;\n }\n }\n }\n\n // Sort clips by zIndex\n const sortedClips = [...this.clips].sort((a, b) => a.zIndex - b.zIndex);\n\n // Update each clip\n for (const clip of sortedClips) {\n // Pre-calculate transition timing (needed for early-exit checks)\n const isTransitionable = clip.type === \"Video\" || clip.type === \"Image\";\n let transitionStartTime = clip.transition?.start ?? 0;\n let transitionEndTime = clip.transition?.end ?? 0;\n\n if (clip.transition && (clip.transition.fromClipId || clip.transition.toClipId)) {\n const fromClip = clip.transition.fromClipId\n ? this.getClipById(clip.transition.fromClipId)\n : null;\n const toClip = clip.transition.toClipId ? this.getClipById(clip.transition.toClipId) : null;\n\n if (toClip) {\n const duration = clip.transition.duration ?? 2e6;\n transitionStartTime = Math.max(0, toClip.display.from - duration / 2);\n transitionEndTime = transitionStartTime + duration;\n } else if (fromClip) {\n const duration = clip.transition.duration ?? 2e6;\n transitionStartTime = Math.max(0, fromClip.display.to - duration / 2);\n transitionEndTime = transitionStartTime + duration;\n }\n }\n\n const inTransition =\n isTransitionable &&\n clip.transition &&\n timestamp >= transitionStartTime &&\n timestamp < transitionEndTime;\n\n // Check if clip is before its display time\n // Skip if in active transition (transitions extend beyond display bounds)\n if (!inTransition && timestamp < clip.display.from) {\n const inactiveRenderer = this.spriteRenderers.get(clip);\n if (inactiveRenderer != null) {\n await inactiveRenderer.updateFrame(null);\n }\n const videoSprite = this.videoSprites.get(clip);\n if (videoSprite != null) {\n videoSprite.visible = false;\n }\n\n // Pause playback if it exists (fix for audio leak on split)\n const playbackInfo = this.playbackElements.get(clip);\n if (playbackInfo != null && this.isPlaybackCapable(clip)) {\n clip.pause(playbackInfo.element);\n }\n continue;\n }\n\n // Check if clip is after its display time (display.to)\n // Skip if in active transition (transitions extend beyond display bounds)\n if (!inTransition && clip.display.to > 0 && timestamp > clip.display.to) {\n const inactiveRenderer = this.spriteRenderers.get(clip);\n if (inactiveRenderer != null) {\n await inactiveRenderer.updateFrame(null);\n }\n const videoSprite = this.videoSprites.get(clip);\n if (videoSprite != null) {\n videoSprite.visible = false;\n }\n\n // Pause playback if it exists (fix for audio leak on split)\n const playbackInfo = this.playbackElements.get(clip);\n if (playbackInfo != null && this.isPlaybackCapable(clip)) {\n clip.pause(playbackInfo.element);\n }\n continue;\n }\n\n const relativeTime = timestamp - clip.display.from;\n const spriteTime = relativeTime * clip.playbackRate;\n\n // Update animation\n clip.animate(spriteTime);\n\n // Check if clip has exceeded its duration (different from display.to)\n // Skip if in active transition\n const meta = await clip.ready;\n const clipDuration = clip.duration || meta.duration;\n if (!inTransition && clipDuration > 0 && relativeTime > clipDuration) {\n const inactiveRenderer = this.spriteRenderers.get(clip);\n if (inactiveRenderer != null) {\n await inactiveRenderer.updateFrame(null);\n }\n const videoSprite = this.videoSprites.get(clip);\n if (videoSprite != null) {\n videoSprite.visible = false;\n }\n\n // Pause playback if it exists (fix for audio leak on split)\n const playbackInfo = this.playbackElements.get(clip);\n if (playbackInfo != null && this.isPlaybackCapable(clip)) {\n clip.pause(playbackInfo.element);\n }\n continue;\n }\n\n // Handle playback elements (VideoClip and AudioClip)\n const playbackInfo = this.playbackElements.get(clip);\n\n if (playbackInfo != null && this.isPlaybackCapable(clip)) {\n const playbackRelativeTime = relativeTime / 1e6; // Convert to seconds\n\n // Track-level mute is applied per frame without touching the clip's own muted flag\n clip.trackMuted = this.tracks.find((t) => t.clipIds.includes(clip.id))?.muted ?? false;\n\n // Sync playback using clip method\n clip.syncPlayback(playbackInfo.element, this.isPlaying, playbackRelativeTime);\n\n // For VideoClip, handle sprite visibility\n if (clip.type === \"Video\" && this.isPlaybackCapable(clip)) {\n const videoSprite = this.videoSprites.get(clip);\n if (videoSprite != null) {\n const clipDurationSeconds = (clip.duration || clip.meta.duration) / 1e6;\n const hasCustomRenderer = this.spriteRenderers.has(clip);\n\n // If we also have a PixiSpriteRenderer for this clip (e.g. chromakey),\n // treat the HTMLVideoElement as audio-only and don't show its sprite.\n // Otherwise, use the video sprite for rendering.\n if (!hasCustomRenderer) {\n videoSprite.visible =\n !inTransition &&\n !clipsClaimedByTransition.has(clip.id) &&\n playbackRelativeTime >= 0 &&\n playbackRelativeTime < clipDurationSeconds;\n if (videoSprite.visible) {\n updateSpriteTransform(clip, videoSprite);\n }\n\n // No custom renderer, so we can skip further processing for this clip\n // unless we are in transition (in which case we need to fall through to the transition block)\n if (!inTransition) {\n continue;\n }\n } else {\n videoSprite.visible = false;\n }\n }\n } else {\n // Audio-only clip, skip video rendering - safe to continue as they don't have transitions\n continue;\n }\n }\n\n if (inTransition) {\n const fromClipId = clip?.transition?.fromClipId;\n const toClipId = clip?.transition?.toClipId;\n const transKey = `${fromClipId}_${toClipId}`;\n\n // Ensure we only render this transition ONCE per frame\n if (renderedTransitions.has(transKey)) {\n // Hide this clip's own renderer/sprite if it's the one currently being updated\n const renderer = this.spriteRenderers.get(clip);\n if (renderer?.getRoot()) renderer.getRoot()!.visible = false;\n const videoSprite = this.videoSprites.get(clip);\n if (videoSprite) videoSprite.visible = false;\n continue;\n }\n\n renderedTransitions.add(transKey);\n\n // Inicialización lazy de texturas\n if (!this.transFromTexture || !this.transToTexture) {\n this.recreateTransitionTextures();\n }\n if (!this.transBgGraphics) {\n this.transBgGraphics = new Graphics();\n this.transBgGraphics\n .rect(0, 0, this.opts.width, this.opts.height)\n .fill({ color: 0x000000, alpha: 0 }); // fondo default\n }\n\n const fromClip = fromClipId ? this.getClipById(fromClipId) : null;\n const toClip = toClipId ? this.getClipById(toClipId) : null;\n\n let fromFrame: ImageBitmap | Texture | VideoFrame | null = null;\n let toFrame: ImageBitmap | Texture | VideoFrame | null = null;\n\n // Captura frame estático \"from\"\n if (fromClip) {\n const fromRelativeTime = Math.max(0, timestamp - fromClip.display.from);\n\n const { video } = await fromClip.getFrame(fromRelativeTime);\n\n if (video instanceof HTMLVideoElement) {\n fromFrame = this.getVideoTexture(video);\n } else {\n fromFrame = video;\n }\n\n if (fromFrame) {\n this.lastFromFrame = fromFrame;\n }\n }\n\n // Captura frame estático \"to\"\n if (toClip) {\n const toRelativeTime = Math.max(0, timestamp - toClip.display.from);\n\n const { video } = await toClip.getFrame(toRelativeTime);\n\n if (video instanceof HTMLVideoElement) {\n toFrame = this.getVideoTexture(video);\n } else {\n toFrame = video;\n }\n\n if (toFrame) {\n this.lastToFrame = toFrame;\n }\n }\n\n if (!fromFrame) fromFrame = this.lastFromFrame;\n if (!toFrame) toFrame = this.lastToFrame;\n if (!fromFrame || !toFrame) {\n continue;\n }\n if (fromFrame && toFrame && this.pixiApp && this.transFromTexture && this.transToTexture) {\n const progress = (timestamp - transitionStartTime) / clip?.transition?.duration!;\n\n // Renderizar \"from\" frame en la textura\n if (fromClip && fromFrame) {\n this.renderClipToTransitionTexture(fromClip, fromFrame, this.transFromTexture);\n }\n // Renderizar \"to\" frame en la textura\n if (toClip && toFrame) {\n this.renderClipToTransitionTexture(toClip, toFrame, this.transToTexture);\n }\n\n // Crear o reutilizar renderer de transición\n // Use shared transKey for the cache!\n let transRenderer = this.transitionRenderers.get(transKey);\n if (!transRenderer) {\n try {\n transRenderer = makeTransition({\n name: clip?.transition?.name as any,\n renderer: this.pixiApp.renderer,\n });\n this.transitionRenderers.set(transKey, transRenderer);\n } catch (err) {\n console.error(`[Studio] Failed to create transition renderer:`, err);\n }\n }\n\n if (transRenderer) {\n const transitionClip = this.clips.find(\n (c) =>\n c instanceof Transition &&\n c.fromClipId === fromClipId &&\n c.toClipId === toClipId,\n ) as Transition | undefined;\n const transTexture = transRenderer.render({\n width: this.opts.width,\n height: this.opts.height,\n from: this.transFromTexture,\n to: this.transToTexture,\n progress,\n values: transitionClip?.values,\n });\n\n // Mostrar transición\n let transSprite = this.transitionSprites.get(clip.id);\n if (!transSprite) {\n transSprite = new Sprite();\n transSprite.label = `TransitionSprite_${clip.id}`;\n this.transitionSprites.set(clip.id, transSprite);\n if (this.clipsNormalContainer) {\n this.clipsNormalContainer.addChild(transSprite);\n }\n }\n\n transSprite.texture = transTexture;\n transSprite.visible = true;\n transSprite.x = 0;\n transSprite.y = 0;\n transSprite.width = this.opts.width;\n transSprite.height = this.opts.height;\n transSprite.anchor.set(0, 0);\n transSprite.zIndex = clip.zIndex;\n usedTransitionSprites.add(clip.id);\n\n // Ocultar clips reales durante la transición\n\n const renderer = this.spriteRenderers.get(clip);\n if (renderer?.getRoot()) renderer.getRoot()!.visible = false;\n const videoSprite = this.videoSprites.get(clip);\n if (videoSprite) videoSprite.visible = false;\n\n if (fromClip) {\n const prevRenderer = this.spriteRenderers.get(fromClip);\n if (prevRenderer?.getRoot()) prevRenderer.getRoot()!.visible = false;\n const prevVideoSprite = this.videoSprites.get(fromClip);\n if (prevVideoSprite) prevVideoSprite.visible = false;\n clipsClaimedByTransition.add(fromClip.id);\n }\n\n if (toClip) {\n const nextRenderer = this.spriteRenderers.get(toClip);\n if (nextRenderer?.getRoot()) nextRenderer.getRoot()!.visible = false;\n const nextVideoSprite = this.videoSprites.get(toClip);\n if (nextVideoSprite) nextVideoSprite.visible = false;\n clipsClaimedByTransition.add(toClip.id);\n }\n\n continue;\n }\n }\n }\n\n // Hide transition sprite if not active for any clip in this loop\n // (Actually we should probably reset it at start of updateFrame)\n\n // Handle clips rendered via PixiSpriteRenderer (ImageClip, MP4 with\n // tickInterceptor/chromakey, etc)\n const renderer = this.spriteRenderers.get(clip);\n if (renderer != null) {\n // If this clip is claimed by an active transition, hide it and skip normal rendering\n if (clipsClaimedByTransition.has(clip.id)) {\n const root = renderer.getRoot();\n if (root) root.visible = false;\n const videoSprite = this.videoSprites.get(clip);\n if (videoSprite) videoSprite.visible = false;\n continue;\n }\n\n // Skip transform updates if this is the selected clip being transformed\n // The transformer directly manipulates the sprite, so we don't want to overwrite it\n const isSelected = this.selectedClips.has(clip);\n\n // Optimized path: Check if clip has a Texture (e.g., Image.fromUrl)\n // Skip Text and Caption clips here as they have async getTexture() and are handled below\n if (\n clip.type !== \"Text\" &&\n clip.type !== \"Caption\" &&\n typeof (clip as any).getTexture === \"function\" &&\n (clip as Image).getTexture() != null\n ) {\n const texture = (clip as Image).getTexture();\n if (texture != null) {\n // Use Texture directly for optimized rendering\n await renderer.updateFrame(texture);\n // Only update transforms if not currently being transformed\n if (!isSelected) {\n renderer.updateTransforms();\n }\n if (this.opts.interactivity) {\n this.selection.setupSpriteInteractivity(clip);\n }\n continue;\n }\n }\n\n // Optimized path for Text: Use Texture directly\n if (clip.type === \"Text\") {\n const textClip = clip as Text;\n if (this.pixiApp?.renderer && typeof textClip.setRenderer === \"function\") {\n textClip.setRenderer(this.pixiApp.renderer);\n }\n const texture = await textClip.getTexture();\n\n if (texture != null) {\n // Use Texture directly for optimized rendering\n await renderer.updateFrame(texture);\n // Only update transforms if not currently being transformed\n if (!isSelected) {\n renderer.updateTransforms();\n }\n if (this.opts.interactivity) {\n this.selection.setupSpriteInteractivity(clip);\n }\n continue;\n }\n }\n\n // Optimized path for Caption: Use Texture directly\n if (clip.type === \"Caption\") {\n // Update caption highlighting based on current time before rendering\n (clip as Caption).updateState(relativeTime);\n const captionClip = clip as Caption;\n if (this.pixiApp?.renderer && typeof captionClip.setRenderer === \"function\") {\n captionClip.setRenderer(this.pixiApp.renderer);\n }\n const texture = await captionClip.getTexture();\n if (texture != null) {\n // Use Texture directly for optimized rendering\n await renderer.updateFrame(texture);\n // Only update transforms if not currently being transformed\n if (!isSelected) {\n renderer.updateTransforms();\n }\n if (this.opts.interactivity) {\n this.selection.setupSpriteInteractivity(clip);\n }\n continue;\n }\n }\n\n // Shape clip: Set renderer before getting frame\n if (clip.type === \"Shape\") {\n const shapeClip = clip as any;\n if (this.pixiApp?.renderer && typeof shapeClip.setRenderer === \"function\") {\n shapeClip.setRenderer(this.pixiApp.renderer);\n }\n }\n\n const { video: frameVideo } = await clip.getFrame(relativeTime);\n\n // A newer updateFrame started while this one awaited the decoder (seek + seeked-event\n // re-render, bridge updates, scrubbing). Its frame wins: applying ours now could hide the\n // sprite (an aborted decode yields null) or show a stale frame.\n if (frameToken !== this.frameToken) return;\n\n // Update renderer with new frame\n // PixiSpriteRenderer will handle sprite creation and stage addition on first frame\n // Always call updateFrame - it will handle visibility internally\n // This ensures smooth updates without blinking\n await renderer.updateFrame(frameVideo);\n\n // Update transforms after frame update\n // Only update transforms if not currently being transformed\n if (!isSelected) {\n renderer.updateTransforms();\n }\n\n if (this.opts.interactivity) {\n this.selection.setupSpriteInteractivity(clip);\n }\n\n // Note: done flag is handled by duration check above\n }\n }\n\n // Render global effects sequence\n if (\n this.activeGlobalEffects.length > 0 &&\n this.clipsNormalContainer &&\n this.clipsEffectContainer\n ) {\n // 1. Reset all clips to Normal container first\n for (const c of this.clips) {\n this.moveClipToEffectContainer(c, false);\n }\n\n this.clipsNormalContainer.visible = true;\n await this.applyGlobalEffects(timestamp);\n } else {\n // No active global effects\n if (this.clipsNormalContainer) {\n for (const c of this.clips) {\n this.moveClipToEffectContainer(c, false);\n }\n\n this.clipsNormalContainer.visible = true;\n // Cleanup effect sprite\n if (this.currentGlobalEffectSprite) {\n if (this.currentGlobalEffectSprite.parent) {\n this.currentGlobalEffectSprite.parent.removeChild(this.currentGlobalEffectSprite);\n }\n this.currentGlobalEffectSprite.destroy();\n this.currentGlobalEffectSprite = null;\n }\n }\n }\n\n // Finally, hide any transition sprites that were NOT used this frame\n for (const [clipId, sprite] of this.transitionSprites.entries()) {\n if (!usedTransitionSprites.has(clipId)) {\n sprite.visible = false;\n }\n }\n\n // Render the scene\n if (this.pixiApp != null) {\n this.pixiApp.render();\n }\n }\n\n /**\n * Apply global effect to the current scene\n */\n\n moveClipToEffectContainer(clip: IClip, toEffect: boolean = true): void {\n if (!this.clipsNormalContainer || !this.clipsEffectContainer) return;\n\n const target = toEffect ? this.clipsEffectContainer : this.clipsNormalContainer;\n\n // 1. Move the regular clip sprite\n const renderer = this.spriteRenderers.get(clip);\n if (renderer) {\n const root = renderer.getRoot();\n if (root && root.parent !== target) {\n try {\n if (root.parent && (root.parent as Container).removeChild) {\n (root.parent as Container).removeChild(root);\n }\n } catch (err) {\n console.warn(\"moveClipToEffectContainer: could not remove root from parent\", err);\n }\n target.addChild(root);\n }\n }\n\n // 2. Move the transition sprite (if exists)\n const transSprite = this.transitionSprites.get(clip.id);\n if (transSprite && transSprite.parent !== target) {\n try {\n if (transSprite.parent && (transSprite.parent as Container).removeChild) {\n (transSprite.parent as Container).removeChild(transSprite);\n }\n } catch (err) {\n console.warn(\"moveClipToEffectContainer: could not remove transSprite from parent\", err);\n }\n target.addChild(transSprite);\n }\n\n // 3. Move the video sprite (if exists)\n const videoSprite = this.videoSprites.get(clip);\n if (videoSprite && videoSprite.parent !== target) {\n try {\n if (videoSprite.parent && (videoSprite.parent as Container).removeChild) {\n (videoSprite.parent as Container).removeChild(videoSprite);\n }\n } catch (err) {\n console.warn(\"moveClipToEffectContainer: could not remove videoSprite from parent\", err);\n }\n target.addChild(videoSprite);\n }\n }\n\n applyGlobalEffect(\n key: EffectKey,\n options: {\n startTime: number;\n duration?: number;\n id?: string;\n },\n clips: IClip[],\n ): string {\n const id = options.id || `${key}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n const effect = {\n id,\n key,\n startTime: options.startTime,\n duration: options.duration ?? 1_000_000,\n };\n for (const clip of clips) {\n if (clip instanceof Image) {\n clip.addEffect(effect);\n }\n if (clip instanceof Video) {\n clip.addEffect(effect);\n }\n if (clip instanceof Text) {\n clip.addEffect(effect);\n }\n if (clip instanceof Caption) {\n clip.addEffect(effect);\n }\n }\n this.globalEffects.set(id, effect);\n\n return id;\n }\n\n getTrackIndex(clipId: string): number {\n return this.tracks.findIndex((t) => t.clipIds.includes(clipId));\n }\n\n /**\n * Get the frame from the previous clip on the same track for transition\n */\n public async getTransitionFromFrame(\n clip: IClip,\n timestamp: number,\n ): Promise<VideoFrame | ImageBitmap | null | Texture> {\n let prevClip: IClip | null = null;\n\n // 1. Try explicit pairing first\n if (clip.transition?.prevClipId) {\n prevClip = this.clips.find((c) => c.id === clip.transition!.prevClipId) || null;\n }\n\n // 2. Fallback to track heuristic\n if (!prevClip) {\n prevClip = this.getPreviousClipOnTrack(clip);\n }\n if (!prevClip) return null;\n\n // Calculate relative time for the \"from\" clip\n // If clips overlap, we use the current absolute timestamp\n // If they are back-to-back, we clamp to the end of the previous clip\n const prevClipDuration = prevClip.duration > 0 ? prevClip.duration : 0;\n const prevRelativeTime = Math.max(\n 0,\n Math.min(timestamp - prevClip.display.from, prevClipDuration),\n );\n\n const { video } = await prevClip.getFrame(prevRelativeTime);\n return video;\n }\n\n private getPreviousClipOnTrack(clip: IClip): IClip | null {\n const trackIndex = this.getTrackIndex(clip.id);\n if (trackIndex === -1) return null;\n\n return (\n this.clips\n .filter(\n (c) =>\n c.id !== clip.id &&\n this.getTrackIndex(c.id) === trackIndex &&\n c.display.from < clip.display.from &&\n (c instanceof Video || c instanceof Image),\n )\n .sort((a, b) => b.display.to - a.display.to)[0] || null\n );\n }\n\n /**\n * Renders a clip frame onto a transition texture with red background\n */\n private renderClipToTransitionTexture(\n clip: IClip,\n frame: VideoFrame | ImageBitmap | Texture,\n target: RenderTexture,\n ): void {\n if (!this.pixiApp) return;\n\n const style = (clip as any).style || {};\n const { renderTransform } = clip;\n const isMirrored = (renderTransform?.mirror ?? 0) > 0.5;\n\n const tex = frame instanceof Texture ? frame : Texture.from(frame as any);\n\n // Apply transforms similar to PixiSpriteRenderer.applySpriteTransforms\n const xOffset = renderTransform?.x ?? 0;\n const yOffset = renderTransform?.y ?? 0;\n const angleOffset = renderTransform?.angle ?? 0;\n const scaleMultiplier = renderTransform?.scale ?? 1;\n const opacityMultiplier = renderTransform?.opacity ?? 1;\n const blurOffset = renderTransform?.blur ?? 0;\n const brightnessMultiplier = renderTransform?.brightness ?? 1;\n\n const textureWidth = tex.width || 1;\n const textureHeight = tex.height || 1;\n\n const isCaption = (clip as any).type === \"Caption\";\n\n const baseScaleX =\n !isCaption && clip.width && clip.width !== 0 ? Math.abs(clip.width) / textureWidth : 1;\n const baseScaleY =\n !isCaption && clip.height && clip.height !== 0 ? Math.abs(clip.height) / textureHeight : 1;\n\n // Create a root container that holds everything\n const rootContainer = new Container();\n\n rootContainer.x = clip.center.x + xOffset;\n rootContainer.y = clip.center.y + yOffset;\n rootContainer.rotation =\n ((clip.flip?.x || clip.flip?.y ? -1 : 1) * ((clip.angle + angleOffset) * Math.PI)) / 180;\n rootContainer.alpha = clip.opacity * opacityMultiplier;\n\n // Create the main sprite\n const tempSprite = new Sprite(tex);\n tempSprite.anchor.set(0.5, 0.5);\n\n let mirrorSprites: Sprite[] = [];\n\n if (isMirrored) {\n // True reflection: original at normal position, mirrors on all sides\n const sX = baseScaleX * scaleMultiplier;\n const sY = baseScaleY * scaleMultiplier;\n const scaledW = textureWidth * sX;\n const scaledH = textureHeight * sY;\n\n // Original sprite at normal position\n tempSprite.position.set(0, 0);\n tempSprite.scale.set(sX, sY);\n\n // Mirror layout: [dx, dy, scaleX, scaleY]\n const mirrors: [number, number, number, number][] = [\n [scaledW, 0, -sX, sY], // right\n [-scaledW, 0, -sX, sY], // left\n [0, scaledH, sX, -sY], // bottom\n [0, -scaledH, sX, -sY], // top\n [scaledW, scaledH, -sX, -sY], // bottom-right\n [-scaledW, scaledH, -sX, -sY], // bottom-left\n [scaledW, -scaledH, -sX, -sY], // top-right\n [-scaledW, -scaledH, -sX, -sY], // top-left\n ];\n\n for (const [dx, dy, sx, sy] of mirrors) {\n const ms = new Sprite(tex);\n ms.anchor.set(0.5, 0.5);\n ms.position.set(dx, dy);\n ms.scale.set(sx, sy);\n mirrorSprites.push(ms);\n }\n\n // Apply flip\n if (clip.flip?.x) {\n tempSprite.scale.x = -sX;\n for (let i = 0; i < 8; i++) {\n mirrorSprites[i].scale.x = -mirrors[i][2];\n }\n }\n if (clip.flip?.y) {\n tempSprite.scale.y = -sY;\n for (let i = 0; i < 8; i++) {\n mirrorSprites[i].scale.y = -mirrors[i][3];\n }\n }\n\n rootContainer.addChild(tempSprite);\n for (const ms of mirrorSprites) {\n rootContainer.addChild(ms);\n }\n } else {\n // Standard single sprite\n tempSprite.scale.x = clip.flip?.x\n ? -baseScaleX * scaleMultiplier\n : baseScaleX * scaleMultiplier;\n tempSprite.scale.y = clip.flip?.y\n ? -baseScaleY * scaleMultiplier\n : baseScaleY * scaleMultiplier;\n rootContainer.addChild(tempSprite);\n }\n\n // Apply Filters\n const filters: any[] = [];\n if (blurOffset > 0) {\n const blurFilter = new BlurFilter();\n blurFilter.strength = blurOffset;\n blurFilter.quality = 4;\n (blurFilter as any).repeatEdgePixels = true;\n filters.push(blurFilter);\n }\n\n const hasClipColorAdjustment = hasColorAdjustment((clip as any).colorAdjustment);\n if (brightnessMultiplier !== 1 || hasClipColorAdjustment) {\n const brightnessFilter = new ColorMatrixFilter();\n applyColorAdjustmentToMatrix(\n brightnessFilter,\n (clip as any).colorAdjustment,\n brightnessMultiplier,\n );\n filters.push(brightnessFilter);\n }\n\n const activeSelectiveHslList = getAllSelectiveHsl((clip as any).colorAdjustment);\n for (let i = 0; i < activeSelectiveHslList.length; i++) {\n const activeSelectiveHsl = activeSelectiveHslList[i];\n const hslUniforms = new UniformGroup({\n uTargetColor: { value: [1, 1, 0], type: \"vec3<f32>\" },\n uHueShift: { value: activeSelectiveHsl.hue, type: \"f32\" },\n uSatShift: { value: activeSelectiveHsl.saturation / 100, type: \"f32\" },\n uLightShift: { value: activeSelectiveHsl.lightness / 100, type: \"f32\" },\n uTolerance: { value: 0.22, type: \"f32\" },\n uSoftness: { value: 0.12, type: \"f32\" },\n });\n const rgb = hexToRgb(activeSelectiveHsl.targetColor);\n if (rgb) {\n hslUniforms.uniforms.uTargetColor[0] = rgb.r / 255;\n hslUniforms.uniforms.uTargetColor[1] = rgb.g / 255;\n hslUniforms.uniforms.uTargetColor[2] = rgb.b / 255;\n }\n const selectiveHslFilter = new Filter({\n glProgram: new GlProgram({\n vertex,\n fragment: SELECTIVE_HSL_FRAGMENT,\n name: `SelectiveHslShader_${i}`,\n }),\n resources: { hslUniforms },\n });\n filters.push(selectiveHslFilter);\n }\n\n rootContainer.filters = filters;\n\n const w = Math.abs(clip.width ?? 0) * scaleMultiplier;\n const h = Math.abs(clip.height ?? 0) * scaleMultiplier;\n\n // Apply Styles (Border Radius, Stroke, Shadow)\n const borderRadius = style.borderRadius || 0;\n let maskGraphics: Graphics | null = null;\n if (borderRadius > 0) {\n maskGraphics = new Graphics();\n maskGraphics.roundRect(-w / 2, -h / 2, w, h, Math.min(borderRadius, w / 2, h / 2));\n maskGraphics.fill({ color: 0xffffff, alpha: 1 });\n rootContainer.addChild(maskGraphics);\n // Force mask update by resetting the mask property\n tempSprite.mask = null;\n tempSprite.mask = maskGraphics;\n }\n\n const stroke = style.stroke;\n let strokeGraphics: Graphics | null = null;\n if (stroke && stroke.width > 0) {\n strokeGraphics = new Graphics();\n const color = parseColor(stroke.color) ?? 0xffffff;\n let alignment = 1; // Default outside (1)\n if (stroke.alignment !== undefined) {\n if (typeof stroke.alignment === \"number\") {\n alignment = stroke.alignment;\n } else if (stroke.alignment === \"center\" || stroke.alignment === \"middle\") {\n alignment = 0.5;\n } else if (stroke.alignment === \"inside\") {\n alignment = 0;\n } else if (stroke.alignment === \"outside\") {\n alignment = 1;\n }\n }\n strokeGraphics.setStrokeStyle({\n width: stroke.width,\n color: color,\n alignment: alignment,\n });\n\n if (borderRadius > 0) {\n const r = Math.min(borderRadius, w / 2, h / 2);\n strokeGraphics.roundRect(-w / 2, -h / 2, w, h, r);\n } else {\n strokeGraphics.rect(-w / 2, -h / 2, w, h);\n }\n strokeGraphics.stroke();\n rootContainer.addChild(strokeGraphics);\n }\n\n const shadow = style.shadow;\n let shadowGraphics: Graphics | null = null;\n if (shadow && (shadow.blur > 0 || (shadow.offsetX ?? 0) !== 0 || (shadow.offsetY ?? 0) !== 0)) {\n shadowGraphics = new Graphics();\n const color = parseColor(shadow.color) ?? 0x000000;\n const alpha = shadow.alpha ?? 0.5;\n const dx = shadow.offsetX ?? 0;\n const dy = shadow.offsetY ?? 0;\n\n if (borderRadius > 0) {\n const r = Math.min(borderRadius, w / 2, h / 2);\n shadowGraphics.roundRect(-w / 2 + dx, -h / 2 + dy, w, h, r);\n } else {\n shadowGraphics.rect(-w / 2 + dx, -h / 2 + dy, w, h);\n }\n shadowGraphics.fill({ color, alpha });\n rootContainer.addChildAt(shadowGraphics, 0);\n }\n\n // Render onto target and CLEAR the texture first\n this.pixiApp.renderer.render({\n container: rootContainer,\n target: target,\n clear: true,\n });\n\n // Clean up temporary objects\n if (!(frame instanceof Texture)) {\n tempSprite.texture.destroy(true);\n }\n if (maskGraphics) maskGraphics.destroy();\n if (strokeGraphics) strokeGraphics.destroy();\n if (shadowGraphics) shadowGraphics.destroy();\n for (const ms of mirrorSprites) ms.destroy();\n tempSprite.destroy();\n rootContainer.destroy();\n }\n\n removeGlobalEffect(id: string): void {\n this.globalEffects.delete(id);\n }\n\n clearGlobalEffects(): void {\n this.globalEffects.clear();\n }\n\n private updateActiveGlobalEffect(currentTime: number): void {\n const active: ActiveGlobalEffect[] = [];\n\n // 1. Check for Effect instances (Adjustment Layer)\n for (const clip of this.clips) {\n if (clip instanceof Effect) {\n const duration = clip.duration > 0 ? clip.duration : clip.display.to - clip.display.from;\n if (\n currentTime >= clip.display.from &&\n (clip.display.to === 0 || currentTime < clip.display.to) &&\n currentTime < clip.display.from + duration\n ) {\n active.push({\n id: clip.id,\n key: (clip as Effect).effectKey,\n startTime: clip.display.from,\n duration,\n trackIndex: this.getTrackIndex(clip.id),\n values: (clip as Effect).values,\n });\n }\n }\n }\n\n // 2. Add legacy globalEffects map if they match the time\n for (const effect of this.globalEffects.values()) {\n const endTime = effect.startTime + effect.duration;\n if (currentTime >= effect.startTime && currentTime < endTime) {\n active.push({\n id: effect.id,\n key: effect.key,\n startTime: effect.startTime,\n duration: effect.duration,\n trackIndex: -1, // Global effects apply to everything\n });\n }\n }\n\n // Sort by track index descending (bottom tracks first)\n // Legacy global effects (trackIndex: -1) go first as they are \"below\" everything\n this.activeGlobalEffects = active.sort((a, b) => (b.trackIndex ?? -1) - (a.trackIndex ?? -1));\n }\n\n private async applyGlobalEffects(timestamp: number): Promise<void> {\n // 1. Cleanup previous final effect sprite\n if (this.currentGlobalEffectSprite) {\n if (this.currentGlobalEffectSprite.parent) {\n this.currentGlobalEffectSprite.parent.removeChild(this.currentGlobalEffectSprite);\n }\n this.currentGlobalEffectSprite.destroy();\n this.currentGlobalEffectSprite = null;\n }\n\n if (\n this.activeGlobalEffects.length === 0 ||\n !this.pixiApp ||\n !this.clipContainer ||\n !this.clipsNormalContainer ||\n !this.clipsEffectContainer\n )\n return;\n\n const width = this.opts.width;\n const height = this.opts.height;\n let lastResultTexture: Texture | null = null;\n let processedClips = new Set<string>();\n\n // Intermediate textures for chain\n const intermediateTextures: RenderTexture[] = [];\n\n for (const effect of this.activeGlobalEffects) {\n const { key, startTime, duration, trackIndex, values } = effect;\n const elapsed = timestamp - startTime;\n const progress = Math.min(Math.max(elapsed / duration, 0), 1);\n\n if (progress < 0 || progress >= 1) continue;\n\n // Ensure effect container is ready for this pass\n this.clipsEffectContainer.visible = true;\n this.clipsEffectContainer.removeChildren();\n\n // If we have a previous result, add it bottom-most in the container\n if (lastResultTexture) {\n const prevSprite = new Sprite(lastResultTexture);\n prevSprite.label = \"PrevEffectResult\";\n prevSprite.width = width;\n prevSprite.height = height;\n this.clipsEffectContainer.addChild(prevSprite);\n }\n\n // Add clips that belong to this effect (below it)\n const effectTrackIndex = trackIndex ?? -1;\n for (const c of this.clips) {\n if (processedClips.has(c.id)) continue;\n\n const clipTrackIndex = this.getTrackIndex(c.id);\n\n // Check if clip is an adjustment layer itself\n const isEffectClip = c instanceof Effect;\n\n // Clip should be moved if it's below the current effect track\n // OR if it's a legacy effect (trackIndex -1) and we are processing it (but legacy usually apply to all)\n if (!isEffectClip && (effectTrackIndex === -1 || clipTrackIndex > effectTrackIndex)) {\n this.moveClipToEffectContainer(c, true);\n processedClips.add(c.id);\n }\n }\n\n // Apply effect filter\n let effectFilter = this.effectFilters.get(key);\n if (!effectFilter) {\n try {\n effectFilter = await makeEffect({\n name: key as any,\n renderer: this.pixiApp.renderer,\n values,\n });\n if (effectFilter) {\n this.effectFilters.set(key, effectFilter);\n } else {\n continue;\n }\n } catch (err) {\n console.error(err);\n continue;\n }\n }\n\n const inputTexture = RenderTexture.create({\n width,\n height,\n resolution: this.opts.previewScale,\n });\n intermediateTextures.push(inputTexture);\n\n this.pixiApp.renderer.render({\n container: this.clipsEffectContainer,\n target: inputTexture,\n clear: true,\n });\n\n const resultTexture = effectFilter.render({\n canvasTexture: inputTexture,\n progress,\n width,\n height,\n values,\n });\n\n // Hide input clips from this container after rendering to texture\n this.clipsEffectContainer.visible = false;\n\n lastResultTexture = resultTexture;\n }\n\n // Final composition (skip a result that is one of this frame's temporaries or already destroyed)\n const finalTexture = lastResultTexture as RenderTexture | null;\n if (\n finalTexture &&\n !intermediateTextures.includes(finalTexture) &&\n !finalTexture.destroyed &&\n (finalTexture as any)._source\n ) {\n const effectSprite = new Sprite(finalTexture);\n effectSprite.x = 0;\n effectSprite.y = 0;\n effectSprite.width = width;\n effectSprite.height = height;\n effectSprite.scale.set(1);\n effectSprite.zIndex = 5;\n\n this.clipContainer.addChild(effectSprite);\n this.currentGlobalEffectSprite = effectSprite;\n }\n\n // Cleanup input textures (but resultTexture might be used as input for NEXT frame or pass)\n // Actually, resultTexture from makeEffect is usually managed by the filter or temporary for this frame.\n for (const tex of intermediateTextures) {\n if (tex !== finalTexture && !tex.destroyed) tex.destroy(true);\n }\n }\n\n /**\n * Destroy the studio and clean up resources\n */\n destroy(): void {\n if (this.destroyed) return;\n this._destroyViewportEvents();\n window.removeEventListener(\"resize\", this.handleResize);\n if (this.bridge) {\n this.bridge.dispose();\n this.bridge = null;\n }\n this.destroyed = true;\n this.stop();\n this.clear();\n this.transitionRenderers.clear();\n\n if (this.transFromTexture) {\n this.transFromTexture.destroy(true);\n this.transFromTexture = null;\n }\n if (this.transToTexture) {\n this.transToTexture.destroy(true);\n this.transToTexture = null;\n }\n if (this.transBgGraphics) {\n this.transBgGraphics.destroy(true);\n this.transBgGraphics = null;\n }\n for (const sprite of this.transitionSprites.values()) {\n sprite.destroy();\n }\n this.transitionSprites.clear();\n\n if (this.pixiApp) {\n this.pixiApp.destroy(true, {\n children: true,\n texture: true,\n });\n this.pixiApp = null;\n }\n }\n\n /**\n * Select a clip and show transform controls\n * Delegated to InteractionManager\n */\n selectClip(clip: IClip, addToSelection: boolean = false): void {\n this.selection.selectClip(clip, addToSelection);\n }\n\n // createTransformer deleted (moved to manager)\n\n /**\n * Set the selection to a specific list of clips\n */\n public setSelection(clips: IClip[]): void {\n this.selection.setSelection(clips);\n }\n\n /**\n * Select clips by their IDs\n */\n selectClipsByIds(ids: string[]): void {\n this.selection.selectClipsByIds(ids);\n }\n\n /**\n * Deselect the current clip and hide transform controls\n */\n deselectClip(): void {\n this.selection.deselectClip();\n }\n\n /**\n * Toggle lock state of a clip\n */\n public async lockClip(clipId: string, locked: boolean): Promise<void> {\n const clip = this.timeline.getClipById(clipId);\n if (!clip) return;\n\n await this.timeline.updateClip(clipId, { locked });\n this.emit(\"clip:lock-changed\", { clip, locked });\n\n // If the clip is currently selected, recreate the transformer so it\n // shows/hides handles according to the new lock state without deselecting.\n if (this.selection.selectedClips.has(clip)) {\n this.selection.recreateTransformer();\n }\n\n await this.updateFrame(this.currentTime);\n }\n\n /**\n * Export current studio state to JSON\n * @param sourceUrlMap Optional map of clips to their source URLs (required for proper serialization)\n */\n exportToJSON(): ProjectJSON {\n return this.timeline.exportToJSON();\n }\n\n async loadFromJSON(json: ProjectJSON): Promise<void> {\n return this.timeline.loadFromJSON(json);\n }\n\n // End of class Studio (removed legacy commented out code)\n}\n"],"names":["LEVEL_NAMES","any2Str","val","_","v","getTimeStr","d","pad","n","ms","InternalLogger","args","level","consoleMethod","tag","time","logger","Log","logfn","fn","concatFloat32Array","buffers","result","buf","a","b","offset","concatPCMFragments","fragments","chanListPCM","i","j","extractPCM4AudioData","audioData","idx","chanBufSize","chanBuf","convertF32ToPlanar","convertS16ToF32Planar","pcmS16Data","numChannels","numSamples","planarData","channel","sample","pcmF32Data","extractPCM4AudioBuffer","audioBuffer","mixinPCM","audios","maxLen","data","bufIdx","ch0","ch1","trackIdx","c0","c1","audioResample","pcmData","curRate","target","chanCount","emptyPCM","len","p","waveResampler","ctx","abSource","ab","ringSliceFloat32Array","start","end","count","changePCMPlaybackRate","playbackRate","newLength","newPcmData","originalIndex","intIndex","frac","getEaseFactor","t","curve","clampedT","applyAudioFade","audio","endTimeMicro","clipDurationMicro","sampleRate","fadeIn","fadeOut","durationMicro","startTimeMicro","hasFadeIn","hasFadeOut","fadeInDurationMicro","fadeOutDurationMicro","chan","sampleClipTime","fadeMultiplier","fadeOutStartTime","CODEC_PREFERENCES","cachedCodec","isCodecSupported","config","getDefaultAudioCodec","fallback","getCachedAudioCodec","WEBCODECS_CODEC","resolveEncodableAudio","codecType","channelCount","requested","candidates","c","supported","vertexShader","fragmentShader","POINT_POS","TEX_COORD_POS","initShaderProgram","gl","vsSource","fsSource","loadShader","shaderProgram","type","source","shader","errMsg","updateTexture","img","texture","initTexture","internalFormat","width","height","border","srcFormat","srcType","pixel","initCanvas","opts","canvas","posBuffer","a_position","texCoordBuffer","a_texCoord","getSourceWH","imgSource","getKeyColor","r","g","createChromakey","keyColor","frame","setup","timerId","interval","createWorker","blob","url","handlerMap","runCount","worker","k","workerTimer","handler","groupId","fns","sleep","resolve","stop","createEl","tagName","arrayBufferToBase64","buffer","binary","bytes","renderTxt2Img","text","cssText","div","fontFaceStr","svgStr","renderTxt2ImgBitmap","imgEl","decodeImg","stream","init","imageDecoder","frameCount","EventEmitter","handlers","off","evt","ANIMATABLE_PROPERTIES","easings","createSlowMo","linearRatio","power","yoyoMode","lr","pow","t1","t3","tMod","getEasing","easing","KeyframeAnimation","options","f","num","progress","props","duration","delay","iterCount","disableGlobalEasing","offsetTime","cycleDuration","startFrame","endFrame","segmentProgress","easingSource","easedProgress","transform","prop","def","s","e","pixiProps","hasPixiProp","obj","key","prepareVars","vars","newVars","resolvedKf","kfKey","pixiVars","resolveValue","baseVal","parsed","getKeyframeKeys","to","kfKeys","resolveVars","from","baseSource","isOut","resolvedFrom","resolvedTo","keys","fromVal","toVal","isFromRelative","isToRelative","baseForTo","frameResolved","lastFrame","kf100","getAnimatedKeys","excludeKeys","getPixiProperty","gsap","PixiPlugin","PIXI","GsapAnimation","params","_time","orig","pixiOrig","needsReinit","currentActualTargets","hasAnchor","hasPivot","bounds","timelineTime","animTargets","durationInSeconds","stagger","staggerVal","tStart","tEnd","pixiFrom","pixiTo","textContainer","found","child","findCharacters","node","isRoot","results","oldX","oldY","w","h","cx","cy","animKeys","finalFrom","finalTo","WipeAnimation","direction","mode","angle","feather","isReveal","isFinished","rawProgress","parseColor","color","Color","isTransparent","resolveColor","hexToRgb","hex","rgb","createInvertTextContainer","textOnlyContainer","fill","container","Container","line","lineCopy","word","SplitBitmapText","style","TextStyle","copy","blockRect","box","blockSize","x","y","rx","ry","rw","rh","grow","size","pos","BlockRevealAnimation","elapsed","textOnly","blockColor","insideColor","block","invert","mask","Graphics","textIdx","blockIdx","invertIdx","newBlockIdx","clip","lineRects","drew","draw","left","BaseMaskAnimation","finalProgress","CircleRevealAnimation","RectExpandAnimation","origin","ox","oy","halfW","halfH","CenterExpandAnimation","axis","AngleWipeAnimation","StarRevealAnimation","points","innerRatio","outerR","innerR","totalPoints","coords","EdgeCropAnimation","AnimationRegistry","staggerFactory","name","factory","animationRegistry","BaseSprite","changed","oldAnim","matchingNew","anim","isReplaced","err","center","angleOffset","scale","scaleX","scaleY","keyFrame","numK","sortedAnims","updateProps","linearTimeFn","id","toRemove","index","newAnim","updates","it","startState","nextState","nextFrame","stateProcess","videoFrameToImageBitmap","video","bitmap","BaseClip","timestamp","state","outAudio","pcm","frameSource","borderRadius","shadow","stroke","_fps","main","animation","acc","animations","sceneWidth","sceneHeight","json","timing","currentStyle","newStyle","audioCodecPromise","getDefaultAudioConf","DEFAULT_AUDIO_CONF","AssetManager","hashBuffer","path","pendingWrite","file","job","marker","write","isLocalUrl","MediaCache","hit","pending","load","urls","unique","u","entry","cached","response","prev","GLOBAL_KEY","mediaCache","ResourceStatus","ResourceManager","promises","existingPromise","res","loadPromise","item","Audio","dataSource","src","_meta_t","clipMeta","parseStream2PCM","tickRet","trimmedTime","deltaTime","frameCnt","endIdx","volume","_main","objectUrl","reject","onLoadedData","onError","element","timeSeconds","retryErr","onSeeked","isPlaying","clipDuration","isWithinClip","clipDurationMs","timeMs","fadeOutStartMs","fragment","vertex","defaultOptions","OutlineFilter","Filter","thickness","borderColor","gpuProgram","GpuProgram","glProgram","GlProgram","UniformGroup","value","uniforms","FontManager","font","existing","loadedFace","CanvasTextMetrics","error","loadedUrl","fonts","fontName","loaded","face","fontManager","isFontReady","styleOptions","family","spec","getOrInstallFont","parts","Cache","BitmapFont","BaseTextClip","renderer","imageBitmap","extractedCanvas","clone1","clone2","anims","wasMask","isMask","effect","effectId","newEffectData","snapshotWidth","snapshotWordWrap","snapshotWordWrapWidth","snapshotBackground","textToRender","killAllTweens","subChild","words","strokeWidth","spaceWidth","measuredTextHeight","lineHeightMultiplier","fontSize","lineHeight","wrapWidth","liveBgPadX","lines","bgColorOpt","bgOpacity","bgBorderRadius","bgPadX","bgPadY","containerWidth","containerHeight","contentHeight","decorationGraphics","bgGraphics","_words","_textOnlyContainer","_spaceWidth","_measuredTextHeight","_lineHeightMultiplier","_fontSize","textCase","txt","_ww","_www","_lh","_ls","_f","rest","baseFontName","wordStr","wordText","strokeOpt","hasStroke","strokeColor","shadowOpt","offsetX","offsetY","shadowColor","shadowAlpha","shadowBlur","shadowFilterPadding","DropShadowFilter","spaceFs","spaceFamily","spaceWeight","spaceStyle","fontSpec","spaceMeasureStyle","metrics","textMeasureStyle","fontProps","tempSpace","currentLine","currentLineWidth","currentLineHeight","wordWidth","wordHeight","projectedWidth","bgLineHeight","maxLineWidth","totalHeight","contentWidth","snapshotBgPadX","innerTargetWidth","effectiveWidth","isAutoWidth","isAutoHeight","finalVAlign","startY","currentY","currentX","finalAlign","lineXStart","lineContainer","wordIndex","decoration","finalDecoration","lineThickness","lineColor","graphics","yOffset","parsedBgColor","filterPadding","shadowPadding","shadowOffset","shadowDistance","totalPad","paddedWidth","paddedHeight","RenderTexture","processed","hasUnderline","hasOverline","hasLinethrough","colorToNumber","originalOpts","ds","distance","colorOpt","gradient","FillGradient","ratio","colorNumber","fillColor","fillAlpha","rects","radius","alpha","threshold","passes","r1Right","r2Right","maxR","minX","r1","r2","midY","pLast","pFirst","p1","p2","anyApp","base","_chromaKey","_colorAdjustment","Caption","redistributeCaptionWords","o","allWords","makeWordText","segmentIndex","wt","fillToParse","initialColor","segment","segText","currentTimeUs","currentTimeMs","isActive","hasBeenActive","isFuture","wa","animationFactor","shouldApply","dur","textColor","textAlpha","opacityFactor","applyAlpha","parentContainer","bgLabel","existingBg","activeBgColor","bgColor","bgAlpha","padding","paddingX","sx","visualW","visualH","pillarX","pillarY","bg","newClip","caption","colors","positioning","context","trackCaptionConfig","captionOpts","isSet","anyStyle","resolvedCaption","Image","Texture","initWithImgBitmap","imgBitmap","meta","cur","firstVf","targetTime","hitIdx","vf","preSlice","postSlice","effectIndex","extractFileConfig","info","vTrack","videoDesc","parseVideoCodecDesc","codecInfo","getCodecInfo","aTrack","esdsBox","getESDSBoxFromMP4File","audioInfo","parseAudioInfoFromESDSBox","resolvedCodec","codec","track","mp4box","esds","decConfDesc","decSpecInfo","audioObjectType","sampleRateIdx","numberOfChannels","quickParseMP4File","reader","onReady","onSamples","mp4boxFile","cursor","CHUNK_SIZE","nextPos","parseMatrix","matrix","m","fixed","tx","ty","createVFRotater","rotationDeg","normRotation","isPortrait","rotatedWidth","rotatedHeight","newVF","CLIP_ID","isOTFile","Video","oFile","initByStream","tmpfile","otFile","mp4FileToSamples","videoSamples","audioSamples","decoderConf","headerBoxPos","parsedMatrix","videoFrameFinder","audioFrameFinder","genDecoder","codedWidth","codedHeight","genMeta","effectiveDuration","localFile","originFile","normalizedRotation","vDuration","aDuration","lastSampele","localFileReader","AudioFrameFinder","VideoFrameFinder","mp4Info","videoDeltaTS","audioDeltaTS","ftyp","moov","vc","ac","samples","normalizeTimescale","fixFirstBlackFrame","delta","sampleType","idrOffset","idrNALUOffset","conf","min","dec","aborter","hasValidFrame","readStartTime","chunks","videosamples2Chunks","readCost","first","last","rangSize","decodeGoP","keyIdx","encoderConf","rsVf","memoryUsageInfo","findIndexOfSamples","needResetTime","emitFrameCnt","remainFrameCnt","emitAudioFrames","createAudioChunksDecoder","pcmArr","outputCb","inputCnt","outputCnt","outputHandler","resampleQ","createPromiseQueue","needResample","adec","ad","handleDecodeError","prefixStr","chunk","onResult","rsCache","waitingIdx","updateRs","rs","emitIdx","emitRs","addIdx","task","emitCnt","chan0","chan1","gapCnt","u8Arr","dv","nalUnitType","MAX_BLACK_FRAME_OFFSET_US","firstKeyframe","keyframeCount","mem","Text","requestedHeight","isForcingSmaller","processedOpts","textObj","targetWidth","wordIdxInLine","newPaddedWidth","newPaddedHeight","textClipOpts","camelToWords","str","Effect","effectKey","Placeholder","centerX","centerY","rotation","scheduleNext","pre","post","Transition","transitionKey","ShapeClip","nanoid","hexStr","renderTexture","cloned","second","shape","DEFAULT_COLORS","Backdrop","cssColors","fillBase","Sprite","blur","BlurFilter","circle","blobColors","image","TilingSprite","ax","ay","ClipRegistry","klass","autoReadStream","cbs","stoped","run","done","SampleTransform","controller","reason","releasedSamplesCount","samplesCopy","fixMP4BoxFileDuration","inMP4File","sentBoxIdx","boxes","tracks","totalDuration","write2TmpFile","box2Buf","tmpFileWriter","moovPrevBoxes","moovBoxReady","moovIdx","postFile","initPromise","stopped","resultFile","startIdx","chunk2MP4SampleOpts","dts","fastConcatMP4","streams","outfile","dumpFile","concatStreamsToMP4BoxFile","outStream","vTrackId","vDTS","vCTS","aTrackId","aDTS","aCTS","lastVSamp","lastASamp","firstVDTS","firstVCTS","firstADTS","firstACTS","chunkType","videoTrackConf","audioTrackConf","trackId","offsetDTS","offsetCTS","normalizedDTS","normalizedCTS","lastSamp","normalizedVDTS","normalizedVCTS","videoToAudioRatio","fixFMP4Duration","createMP4AudioSampleDecoder","decoderConfig","cacheAD","adDecoder","ss","createMP4AudioSampleEncoder","encoderConfig","onOutput","adEncoder","lastData","createAudioData","audioFade","chanCnt","dataLen","fadeLen","mixinMP4AndAudio","mp4Stream","sendedBoxIdx","firstMoofReady","deltaBuf","canceled","exit","ctrl","stopOut","audioSampleDecoder","audioSampleEncoder","inputAudioPCM","audioOffset","mp4HasAudio","audioDecoderConf","safeAudioTrackConf","audioCtx","addInputAudio2Track","mixinAudioSampleAndInputPCM","getInputAudioSlice","firstSamp","pcmLength","audioDataBuf","pcmFragments","mp4AudioPCM","normalizeClipJSON","normalized","raw","normalizeClipStyleJSON","hasOffset","clipToJSON","jsonToClip","normalizedJson","ClipClass","schedulerChannel","yieldToScheduler","ENCODER_QUEUE_LIMIT","waitEncoderQueue","getQueueSize","ROTATION_MOVEMENT_FRAGMENT","ROTATION_MOVEMENT_UNIFORMS","SEPIA_FRAGMENT","SEPIA_UNIFORMS","GLITCH_FRAGMENT","GLITCH_UNIFORMS","PIXELATE_FRAGMENT","PIXELATE_UNIFORMS","RGB_GLITCH_FRAGMENT","RGB_GLITCH_UNIFORMS","RGB_SHIFT_FRAGMENT","RGB_SHIFT_UNIFORMS","HALFTONE_FRAGMENT","HALFTONE_UNIFORMS","SINEWAVE_FRAGMENT","SINEWAVE_UNIFORMS","SHINE_FRAGMENT","SHINE_UNIFORMS","BLINK_FRAGMENT","BLINK_UNIFORMS","SPRING_FRAGMENT","SPRING_UNIFORMS","DUOTONE_FRAGMENT","DUOTONE_UNIFORMS","TRITONE_FRAGMENT","TRITONE_UNIFORMS","HUE_SHIFT_FRAGMENT","HUE_SHIFT_UNIFORMS","WARP_TRANSITION_FRAGMENT","WARP_TRANSITION_UNIFORMS","SLIT_SCAN_FRAGMENT","SLIT_SCAN_UNIFORMS","SLIT_SCAN_GLITCH_FRAGMENT","SLIT_SCAN_GLITCH_UNIFORMS","PIXELATE_TRANSITION_FRAGMENT","PIXELATE_TRANSITION_UNIFORMS","FOCUS_TRANSITION_FRAGMENT","FOCUS_TRANSITION_UNIFORMS","INVERT_FRAGMENT","INVERT_UNIFORMS","GRAYSCALE_FRAGMENT","GRAYSCALE_UNIFORMS","VIGNETTE_FRAGMENT","VIGNETTE_UNIFORMS","CHROMATIC_FRAGMENT","CHROMATIC_UNIFORMS","SWIRL_MOVEMENT_FRAGMENT","SWIRL_MOVEMENT_UNIFORMS","DISTORT_EFFECT_FRAGMENT","DISTORT_UNIFORMS","PERSPECTIVE_SINGLE_FRAGMENT","PERSPECTIVE_SINGLE_UNIFORMS","DISTORT_SPIN_FRAGMENT","DISTORT_SPIN_UNIFORMS","DISTORT_GRID_FRAGMENT","DISTORT_GRID_UNIFORMS","MIRROR_TILE_FRAGMENT","MIRROR_TILE_UNIFORMS","FLASH_LOOP_FRAGMENT","FLASH_LOOP_UNIFORMS","FILM_STRIP_PRO_FRAGMENT","FILM_STRIP_PRO_UNIFORMS","INVERSE_APERTURE_FRAGMENT","INVERSE_APERTURE_UNIFORMS","CURTAIN_OPEN_FRAGMENT","CURTAIN_OPEN_UNIFORMS","CURTAIN_BLUR_FRAGMENT","CURTAIN_BLUR_UNIFORMS","DISTORT_V2_FRAGMENT","DISTORT_V2_UNIFORMS","NEON_FLASH_FRAGMENT","NEON_FLASH_UNIFORMS","WAVE_DISTORT_FRAGMENT","WAVE_DISTORT_UNIFORMS","SCALE_MOVE_BLUR_FRAGMENT","SCALE_MOVE_BLUR_UNIFORMS","PAPER_BREAK_REVEAL_FRAGMENT","PAPER_BREAK_REVEAL_UNIFORMS","LASER_FRAGMENT","LASER_UNIFORMS","WAVE_FRAGMENT","WAVE_UNIFORMS","SPARKS_FRAGMENT","SPARKS_UNIFORMS","TV_SCANLINES_FRAGMENT","TV_SCANLINES_UNIFORMS","HDR_FRAGMENT","HDR_UNIFORMS","BLACK_FLASH_FRAGMENT","BLACK_FLASH_UNIFORMS","BRIGHT_PULSE_FRAGMENT","BRIGHT_PULSE_UNIFORMS","CAMERA_MOVE_FRAGMENT","CAMERA_MOVE_UNIFORMS","HDR_V2_FRAGMENT","HDR_V2_UNIFORMS","FAST_ZOOM_FRAGMENT","FAST_ZOOM_UNIFORMS","CHROMA_KEY_FRAGMENT","SELECTIVE_HSL_FRAGMENT","FADE_IN_FRAGMENT","FADE_IN_UNIFORMS","FADE_OUT_FRAGMENT","FADE_OUT_UNIFORMS","clamp","max","getCurveValue","sorted","hasColorAdjustment","adjustment","getActiveSelectiveHsl","all","getAllSelectiveHsl","hsl","byColor","entries","targetColor","hue","saturation","lightness","applyColorAdjustmentToMatrix","animationBrightnessMultiplier","basic","curves","selectiveHsl","combinedSaturation","combinedHue","basicBrightness","shine","highlight","hslLightness","lightnessScore","brightness","contrast","sharpness","sharpnessContrast","fade","fadeFactor","fadeContrast","fadeSaturation","vignette","vignetteFactor","vignetteBrightness","grain","grainFactor","grainContrast","grainSaturation","temperature","redScale","blueScale","rgbMid","redMid","greenMid","blueMid","rgbContrast","updateSpriteTransform","sprite","opacity","zIndex","flip","top","PixiSpriteRenderer","_pixiApp","targetContainer","renderTransform","xOffset","scaleMultiplier","scaleXMultiplier","scaleYMultiplier","opacityMultiplier","blurOffset","motionBlurOffset","brightnessMultiplier","isMirrored","textureWidth","textureHeight","isCaption","isText","animPad","baseScaleX","baseScaleY","scaledW","scaledH","mirrors","dx","dy","sy","maskDef","dims","featherPx","ip","remapped","deg","xDistance","yDistance","tw","th","gc","lb","angleDeg","_feather","diagonal","revealedW","corners","alignment","blurFilter","worldScale","currentFilters","effectiveScale","motionBlur","ZoomBlurFilter","zoomBlurFilter","hasClipColorAdjustment","brightnessFilter","ColorMatrixFilter","activeHslList","baseFilters","selectiveHslFilters","activeHsl","hslUniforms","selectiveHslFilter","chromaKey","chromaFilter","program","chromaUniforms","transition","defaultParams","paramsTypes","getUniformType","glsl","RADIAL_SWIPE_FRAGMENT","GRIDFLIP_FRAGMENT","GRIDFLIP_UNIFORMS","CIRCLE_FRAGMENT","DIRECTIONAL_FRAGMENT","DIRECTIONAL_UNIFORMS","UNDULATING_BURN_OUT_FRAGMENT","UNDULATING_BURN_OUT_UNIFORMS","SQUARESWIRE_FRAGMENT","SQUARESWIRE_UNIFORMS","ROTATE_SCALE_FADE_FRAGMENT","ROTATE_SCALE_FADE_UNIFORMS","RANDOMSQUARES_FRAGMENT","RANDOMSQUARES_UNIFORMS","POLAR_FUNCTION_FRAGMENT","POLAR_FUNCTION_UNIFORMS","PIXELIZE_FRAGMENT","PIXELIZE_UNIFORMS","PERLIN_FRAGMENT","PERLIN_UNIFORMS","LUMA_FRAGMENT","LUMA_UNIFORMS","LUMINANCE_MELT_FRAGMENT","LUMINANCE_MELT_UNIFORMS","HEXAGONALIZE_FRAGMENT","HEXAGONALIZE_UNIFORMS","HEART_FRAGMENT","HEART_UNIFORMS","DISPLACEMENT_FRAGMENT","DISPLACEMENT_UNIFORMS","DIRECTIONALWIPE_FRAGMENT","DIRECTIONALWIPE_UNIFORMS","DIRECTIONALWARP_FRAGMENT","DIRECTIONALWARP_UNIFORMS","CROSSHATCH_FRAGMENT","CROSSHATCH_UNIFORMS","CIRCLEOPEN_FRAGMENT","CIRCLEOPEN_UNIFORMS","CANNABISLEAF_FRAGMENT","CANNABISLEAF_UNIFORMS","STEREOVIEWER_FRAGMENT","STEREOVIEWER_UNIFORMS","GLITCH_DISPLACE_FRAGMENT","CROSSZOOM_FRAGMENT","CROSSZOOM_UNIFORMS","CRAZY_PARAMETRIC_FUN_FRAGMENT","CRAZY_PARAMETRIC_FUN_UNIFORMS","BOW_TIE_HORIZONTAL_FRAGMENT","POLKA_DOTS_CURTAIN_FRAGMENT","STATIC_CUSTOM_TRANSITIONS","REGISTERED_TRANSITIONS","registerCustomTransition","unregisterCustomTransition","getAllTransitions","glTransitions","getTransitionOptions","registeredKeys","catalogEntry","getTransitionByKey","GL_TRANSITION_OPTIONS","makeTransition","transitions","allLocal","localKey","variants","variant","availableCount","availableNames","localNames","transitionSprite","transitionTexture","sourceFrom","ImageSource","sourceTo","isDisplacementTransition","sourceDisplacement","defaultDisplacementTexture","imageData","noise","transitionGlsl","transitionUniforms","uniform","transitionGridFlip","transitionCircle","transitionDirectional","transitionUndulatingBurnOut","transitionSquaresWire","transitionRotateScaleFade","transitionRandomSquares","transitionPolarFunction","transitionPixelate","transitionPerlin","transitionLuma","transitionLuminanceMelt","transitionHexagonalize","transitionHeart","transitionDisplacement","transitionDirectionalWipe","transitionDirectionalWarp","transitionCrosshatch","transitionCircleOpen","transitionCannabisLeaf","transitionStereoViewer","transitionGlitchDisplace","transitionCrossZoom","transitionCrazyParametricFun","transitionBowTieHorizontal","transitionPolkaDotsCurtain","transitionPixelize","filterResources","filter","values","shaderUniforms","applyClipStylesAndFilters","tex","rootContainer","tempSprite","pooled","combinedScaleX","combinedScaleY","sX","sY","mirrorLayout","filters","activeSelectiveHslList","activeSelectiveHsl","TransitionManager","pixiApp","clipId","root","mainSprite","getFrameCached","relTime","isFrameTexture","fromClip","toClip","clipsNormalContainer","clipsClaimedByTransition","onVideoState","relativeTime","transSprite","fromFrame","toFrame","transRenderer","transTexture","projectW","projectH","REGISTERED_EFFECTS","registerCustomEffect","unregisterCustomEffect","STATIC_EFFECTS","getAllEffects","getEffectOptions","GL_EFFECT_OPTIONS","FILTER_CLASSES","AdjustmentFilter","AdvancedBloomFilter","BackdropBlurFilter","BloomFilter","ColorMapFilter","ColorOverlayFilter","ConvolutionFilter","DotFilter","GlitchFilter","GlowFilter","GodrayFilter","GrayscaleFilter","HslAdjustmentFilter","KawaseBlurFilter","MotionBlurFilter","OldFilmFilter","PixelateFilter","RadialBlurFilter","ReflectionFilter","RGBSplitFilter","TiltShiftFilter","VALUES_FILTER_SPECIAL","VALUES_FILTER_SPECIAL_LIMITS","textureUrl","textureUrl2","makeEffect","specialEffects","FilterClass","Assets","effects","_opts","label","effectUniforms","effectSprite","effectTexture","canvasTexture","runtimeValues","finalValues","EffectManager","hasVideoTrack","sprites","spriteById","spriteIndexById","spriteRenderers","transitionSprites","clipsEffectContainer","postProcessContainer","activeGlobalEffects","lastResultTexture","processedClips","startTime","adjSprite","isAdjustmentLayer","prevSprite","effectIdx","sprIdx","effectCached","effectRenderFunc","resultSprite","createSpritesRender","transitionManager","effectManager","sortedSprites","mainSprDone","hasVideo","frameCache","spriteTime","textRenderer","tRoot","textTexture","exceededDuration","exceededDisplayToAfter","audioDurationMicro","isTransitionable","transitionStartTime","transitionEndTime","inTransition","fromRenderer","toRenderer","claimedByTransition","transitionSpritesMap","createAudioTrackBuf","framesPerChunk","fps","dataSize","minBufSize","channelBuf","writePos","ensureBufferCapacity","neededSize","newBuf","audioTimestamp","chunkDuration","placeholderData","getAudioData","hasNewData","readPos","chunkCount","remainingSamples","remainingFrames","trackAudios","getCanvasGl","createAVEncoder","outputAudio","muxer","timeSlice","gopSize","audioTrackBuf","COM_ID","Compositor","Application","logAttrs","videoCodec","bitrate","metaDataTags","format","audioCodec","audioSampleRate","hasVideoSprites","shouldCreateVideoTrack","recodemux","finiteDurations","maxTime","stopMuxer","prog","onProgress","onEnded","renderSprites","backgroundColor","jsonWidth","jsonHeight","encodeFrame","FRAMES_PER_YIELD","framesSinceYield","progressTimer","clips","prevClip","dimensionsChanged","clipZIndices","mutedTrackClipIds","totalTracks","trackIndex","cid","clipsArray","clipJSON","toStart","transitionStart","transitionEnd","transitionMeta","timeUs","spriteRender","base64","transparent","prevBgAlpha","StudioBridge","core","studio","onCore","event","onStudio","currentTime","handleSelectionFromStudio","ids","currentSelectedIds","patches","next","wasSyncing","currentStudioSelection","patch","generation","settings","coreClip","captionConfig","pathParts","wasLocked","subProp","fontUrl","fontFamily","trans","newValue","currentValue","trim","Wireframe","Handle","#isDragging","handle","callbacks","#draw","#onDown","#onMove","#onUp","primaryColor","Rectangle","Circle","isVertical","_e","SnappingManager","artboardWidth","artboardHeight","current","otherBounds","guides","targetsX","ob","objectPointsX","snappedX","objP","diff","minTargetY","maxTargetY","targetsY","objectPointsY","snappedY","minTargetX","maxTargetX","proposed","proposedWorld","rect","movingLeft","movingRight","movingTop","movingBottom","worldLeft","worldTop","worldWidth","worldHeight","worldRight","worldBottom","diffWorld","diffLocal","point","TMP","Matrix","Transformer","Point","#handles","#childStart","#pivotWorld","#angle","#startAngle","#opBounds","#scalePivotLocal","#localBounds","#tmpQuad","#midHandleStartDist","#midHandleStartDim","#minW","#minH","#snappingManager","#guidelines","#unsnappedPivotWorld","cb","#beginHandleDrag","#updateDrag","#endDrag","_c","#beginRotateDrag","#rotate","#bindEvents","Ticker","#initialized","#initBounds","contentBounds","#getContentBounds","globalPos","minY","maxX","maxY","localCenterX","localCenterY","newGlobalPivot","#refresh","findMainSprite","rawBounds","p3","p4","contentChildren","animContainer","tl","br","moveDx","moveDy","newPivotWorld","#calculateSnappedMove","#getOtherClipsBounds","boundsList","clipContainer","normalContainer","effectContainer","containers","parentScale","dxGlobalMouse","dyGlobalMouse","proposedParentPos","proposedBounds","snapDx","snapDy","#drawGuides","finalParentPosX","finalParentPosY","currentParentPos","#setScalePivot","pivot","cos","sin","localStart","#scale","global","pivotWorld","#calculateSnappedScale","isTextClip","isCaptionClip","#applyWorldDelta","#deltaScale","pivotLocal","mouseParent","localTransform","det","invDet","mouseLocalX","mouseLocalY","mouseLocal","#proposeScaledRect","proposedParent","corrected","da","live","#deltaRotate","guide","handleScale","visibleHandles","handles","hasRot","getRotationCursor","cornerX","cornerY","tangentAngle","totalAngle","svg","#drawSelectionOutlines","strokeStyle","preserveRatio","origW","origH","newW","newH","pivotOffsetX","pivotOffsetY","distX","distY","newX","newY","worldDelta","parent","parentInv","startWorld","newWorld","newLocal","SelectionManager","app","artboard","currentPos","selectionRect","intersectingClips","clipBounds","previewSet","singleClip","now","topmostClip","globalPoint","highestZIndex","localPoint","hw","hh","addToSelection","clipsToSelect","deselected","isLocked","rafId","ephemeralAngle","newDims","updatesList","animPadC","newWidth","newHeight","activeHandle","logicalTexW","logicalTexH","logicalWidth","logicalHeight","currentScaleX","preservedLeft","preservedTop","preservedWidth","animPadT","newTexture","animPadS","finalNewWidth","oldWidth","newFontSize","newRootX","styleUpdate","reflowAnimPad","flipFactor","newLeft","newTop","Transport","wasPlaying","seekTime","videoEl","frameDuration","nextTime","prevTime","render","elapsedMicroseconds","TimelineModel","newTrack","clipIds","newIndex","currentIndex","trackIds","newTracks","currentTracksMap","fromClipId","toClipId","clipA","clipB","transitionDuration","targetTrackId","existingTransitions","tc","existingTransition","transKey","tClip","clipOrClips","audioSource","newClips","addedClips","onPropsChange","interactionManager","existingRenderer","isVideo","actualTrackId","permanent","tracksToCheck","playbackInfo","updatedClips","clipUpdates","newClipFactory","toReplace","oldClip","clipIdx","trackClipIdx","oldRenderer","oldVideoSprite","oldListener","textOrCaption","calculatedDuration","clipIndex","prevClipId","clipPromises","urlsToPreload","clipToTrackId","intendedTrackId","transJSON","targetId","selectedClips","clipsToDelete","clipsToDuplicate","newClipIds","newTrackId","newTrackName","splitTime","selected","originalJson","splitOffset","splitOffsetInSource","newJson","origTo","origFrom","origDuration","originalEnd","trimFromSeconds","trimFromUs","trimOffsetInSource","newDuration","newDisplayFrom","newDisplayTo","sourceDuration","previousTracks","existingClipIds","validClipIds","fontsToLoad","playbackClip","listener","fromUs","toUs","durationToRemove","clipsToProcess","clipStart","clipEnd","secondPart","secondPartDisplayFrom","secondPartDisplayTo","secondPartTrimFrom","secondPartTrimTo","HistoryManager","project","newState","currentHistoryState","currentState","reverse","newObj","patchesToApply","oldValue","skip","lastKey","Studio","clipChanges","clipsToAdd","clipsToRemove","resizeTo","colorNum","spacing","containerWidthWithSpacing","containerHeightWithSpacing","baseScale","totalScale","originX","originY","prevZoom","nextZoom","prevTotalScale","nextTotalScale","artW","artH","prevOriginX","prevOriginY","relX","relY","scaleFactor","newOriginX","newOriginY","enabled","isTouchpad","cursorX","cursorY","zoomFactor","clipOrId","origWidth","origHeight","prevScale","prevX","prevY","frameToken","usedTransitionSprites","renderedTransitions","videoSprite","sortedClips","inactiveRenderer","playbackRelativeTime","clipDurationSeconds","fromRelativeTime","toRelativeTime","transitionClip","prevRenderer","prevVideoSprite","nextRenderer","nextVideoSprite","isSelected","textClip","captionClip","shapeClip","frameVideo","toEffect","prevClipDuration","prevRelativeTime","mirrorSprites","maskGraphics","strokeGraphics","shadowGraphics","active","endTime","intermediateTextures","effectTrackIndex","clipTrackIndex","effectFilter","inputTexture","resultTexture","finalTexture","locked"],"mappings":"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"}