From 06bb66b207801d483760c694e84cda2dea2052f5 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Tue, 22 Jul 2025 23:19:24 +0200 Subject: [PATCH] refactor(cms): migrate to mediabunny --- cms/package.json | 4 +- cms/utils/video-recorder.ts | 189 +++++++++++++----------------------- pnpm-lock.yaml | 132 +++++++++++++------------ 3 files changed, 138 insertions(+), 187 deletions(-) diff --git a/cms/package.json b/cms/package.json index 5b8ee3f1..f53875ca 100644 --- a/cms/package.json +++ b/cms/package.json @@ -16,12 +16,12 @@ "@sanity/ui": "^2.15.18", "@sanity/vision": "^4.0.0", "gsap": "^3.13.0", + "mediabunny": "^1.2.0", "modern-screenshot": "^4.6.0", "react": "^18.3.1", "react-dom": "^18.3.1", "sanity": "^4.0.0", - "styled-components": "^6.1.18", - "webm-muxer": "^5.1.3" + "styled-components": "^6.1.18" }, "devDependencies": { "@sanity/eslint-config-studio": "5.0.2", diff --git a/cms/utils/video-recorder.ts b/cms/utils/video-recorder.ts index 257857d7..c3d9d331 100644 --- a/cms/utils/video-recorder.ts +++ b/cms/utils/video-recorder.ts @@ -1,6 +1,6 @@ import { gsap } from 'gsap' import { domToBlob } from 'modern-screenshot' -import { Muxer, ArrayBufferTarget } from 'webm-muxer' +import { Output, WebMOutputFormat, BufferTarget, VideoSampleSource, AudioBufferSource, VideoSample } from 'mediabunny' import { ANIMATION_CONFIG, calculateVideoDuration, @@ -231,80 +231,81 @@ export async function recordVideo (options: PureWebCodecsRecorderOptions): Promi keyFrameEvery: 24, } - // Process audio if provided and encode it properly + // Process audio if provided let audioChannels: Float32Array[] | null = null - let audioEncoder: AudioEncoder | null = null - const audioSampleRate = 48000 - const audioFrameSize = 960 // Standard Opus frame size for 48kHz (20ms) if (audioTrack) { try { console.log('🎵 Processing audio track:', audioTrack.name) audioChannels = await processAudioTrack(audioTrack, duration, audioStartTime, audioVolume) - - if (audioChannels && audioChannels.length > 0) { - console.log('🎵 Setting up audio encoder for WebM muxing') - - // Create audio encoder for Opus - audioEncoder = new AudioEncoder({ - output: (chunk, metadata) => { - muxer.addAudioChunk(chunk, metadata) - }, - error: (error: Error) => { - console.warn('Audio encoding error:', error) - }, - }) - - // Configure audio encoder for Opus - audioEncoder.configure({ - codec: 'opus', - sampleRate: audioSampleRate, - numberOfChannels: 2, - bitrate: 128000, // 128 kbps - }) - - console.log('✅ Audio encoder configured') - } + console.log('✅ Audio processed successfully') } catch (error) { console.warn('Failed to process audio, continuing without audio:', error) audioChannels = null - audioEncoder = null } } - const target = new ArrayBufferTarget() - const muxer = new Muxer({ - target, - video: { - codec: 'V_VP9', - width, - height, - frameRate: targetFPS, - }, - audio: audioChannels - ? { - codec: 'A_OPUS', - sampleRate: 48000, - numberOfChannels: 2, - } - : undefined, - firstTimestampBehavior: 'offset', + const output = new Output({ + format: new WebMOutputFormat(), + target: new BufferTarget(), }) - let _encodedFrameCount = 0 + const videoSource = new VideoSampleSource({ + codec: 'vp9', + bitrate: 3000000, // 3 Mbps + }) - const encoder = new window.VideoEncoder({ - output: chunk => { - muxer.addVideoChunk(chunk) - _encodedFrameCount++ - }, - error: (error: Error) => { - throw error - }, + output.addVideoTrack(videoSource, { + frameRate: targetFPS, }) - encoder.configure(config) + // Create audio source if we have audio + let audioSource: AudioBufferSource | null = null + if (audioChannels && audioChannels.length > 0) { + audioSource = new AudioBufferSource({ + codec: 'opus', + bitrate: 128000, // 128 kbps + }) + output.addAudioTrack(audioSource) + } + + // Start the output + await output.start() + + // Process audio data if available + if (audioSource && audioChannels) { + try { + console.log('🎵 Adding audio data') + + // Convert our processed audio channels into an AudioBuffer + const audioSampleRate = 48000 + const audioContext = new AudioContext() + const audioBuffer = audioContext.createBuffer( + 2, // stereo + audioChannels[0].length, + audioSampleRate, + ) + + // Copy channel data (create new Float32Array with ArrayBuffer) + const leftChannel = new Float32Array(audioChannels[0]) + const rightChannel = new Float32Array(audioChannels[1]) + audioBuffer.copyToChannel(leftChannel, 0) + audioBuffer.copyToChannel(rightChannel, 1) + + // Close the context as we only needed it for buffer creation + await audioContext.close() + + // Add the audio buffer to the source + await audioSource.add(audioBuffer) + audioSource.close() + + console.log('✅ Audio data added') + } + catch (error) { + console.warn('Failed to add audio:', error) + } + } try { for (let frameIndex = 0; frameIndex < totalFrames; frameIndex++) { @@ -316,61 +317,6 @@ export async function recordVideo (options: PureWebCodecsRecorderOptions): Promi onProgress(progress) } - // Add audio frames if audio encoder is available - if (audioEncoder && audioChannels && frameIndex === 0) { - try { - console.log('🎵 Encoding audio frames') - - // Process audio in chunks that match the Opus frame size - const samplesPerFrame = audioFrameSize - const totalSamples = audioChannels[0].length - const totalAudioFrames = Math.ceil(totalSamples / samplesPerFrame) - - for (let audioFrameIndex = 0; audioFrameIndex < totalAudioFrames; audioFrameIndex++) { - const startSample = audioFrameIndex * samplesPerFrame - const endSample = Math.min(startSample + samplesPerFrame, totalSamples) - const frameSamples = endSample - startSample - - // Prepare planar audio data (separate channels, not interleaved) - const leftChannelData = new Float32Array(frameSamples) - const rightChannelData = new Float32Array(frameSamples) - - for (let i = 0; i < frameSamples; i++) { - // Clamp samples to prevent distortion - leftChannelData[i] = Math.max(-1, Math.min(1, audioChannels[0][startSample + i] || 0)) - rightChannelData[i] = Math.max(-1, Math.min(1, audioChannels[1] ? audioChannels[1][startSample + i] || 0 : leftChannelData[i])) - } - - // Create planar data buffer (left channel followed by right channel) - const planarData = new Float32Array(frameSamples * 2) - planarData.set(leftChannelData, 0) - planarData.set(rightChannelData, frameSamples) - - // Calculate timestamp for this audio frame - const audioTimestamp = (audioFrameIndex * samplesPerFrame / audioSampleRate) * 1000000 // microseconds - - // Create AudioData object with correct planar format - const audioData = new AudioData({ - format: 'f32-planar', - sampleRate: audioSampleRate, - numberOfChannels: 2, - numberOfFrames: frameSamples, - timestamp: audioTimestamp, - data: planarData, - }) - - // Encode audio frame - audioEncoder.encode(audioData) - audioData.close() - } - - console.log(`✅ Encoded ${totalAudioFrames} audio frames`) - } - catch (error) { - console.warn('Failed to encode audio:', error) - } - } - // Update GSAP timeline to exact time position (not progress) const currentTime = progress * duration timeline.time(currentTime) @@ -395,28 +341,27 @@ export async function recordVideo (options: PureWebCodecsRecorderOptions): Promi duration: frameDurationMicros, }) + const videoSample = new VideoSample(videoFrame) + const keyFrame = frameIndex % (config.keyFrameEvery || 24) === 0 - encoder.encode(videoFrame, { keyFrame }) + await videoSource.add(videoSample, { keyFrame }) videoFrame.close() imageBitmap.close() } - await encoder.flush() + videoSource.close() - if (audioEncoder) { - await audioEncoder.flush() - audioEncoder.close() - } - - muxer.finalize() + await output.finalize() - const webmBuffer = target.buffer + const webmBuffer = output.target.buffer + if (!webmBuffer) { + throw new Error('Failed to generate video buffer') + } const videoBlob = new Blob([webmBuffer], { type: 'video/webm' }) return videoBlob } finally { - encoder.close() destroy() } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3b3a286e..2c2d6859 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,10 +48,10 @@ importers: version: 3.6.3(patch_hash=093a000a83f2e8d36e283f95f1bf85f24beb4f8e2827be2c3a4846901b4a5740)(better-sqlite3@11.10.0)(magicast@0.3.5)(vue-component-type-helpers@2.2.10) '@nuxt/eslint': specifier: 1.6.0 - version: 1.6.0(@typescript-eslint/utils@8.37.0(eslint@9.31.0(jiti@2.4.2))(typescript@5.8.3))(@vue/compiler-sfc@3.5.17)(eslint-import-resolver-node@0.3.9)(eslint@9.31.0(jiti@2.4.2))(magicast@0.3.5)(typescript@5.8.3)(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) + version: 1.6.0(@typescript-eslint/utils@8.37.0(eslint@9.31.0(jiti@2.4.2))(typescript@5.8.3))(@vue/compiler-sfc@3.5.17)(eslint-import-resolver-node@0.3.9)(eslint@9.31.0(jiti@2.4.2))(magicast@0.3.5)(typescript@5.8.3)(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) '@nuxt/fonts': specifier: 0.11.4 - version: 0.11.4(db0@0.3.2(better-sqlite3@11.10.0))(ioredis@5.6.1)(magicast@0.3.5)(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) + version: 0.11.4(db0@0.3.2(better-sqlite3@11.10.0))(ioredis@5.6.1)(magicast@0.3.5)(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) '@nuxt/image': specifier: 1.10.0 version: 1.10.0(patch_hash=f38eb80d2a8ccf16df1dfc43348e681f41fa290145a5abff807e6502b2ebfaec)(db0@0.3.2(better-sqlite3@11.10.0))(ioredis@5.6.1)(magicast@0.3.5) @@ -84,7 +84,7 @@ importers: version: 2.0.12(vue@3.5.17(typescript@5.8.3)) '@unocss/nuxt': specifier: ^66.1.3 - version: 66.3.3(magicast@0.3.5)(postcss@8.5.6)(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))(webpack@5.99.9(esbuild@0.25.6)) + version: 66.3.3(magicast@0.3.5)(postcss@8.5.6)(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))(webpack@5.99.9(esbuild@0.25.6)) '@unocss/postcss': specifier: ^66.1.3 version: 66.3.3(postcss@8.5.6) @@ -132,10 +132,10 @@ importers: version: 0.1.1 nuxt: specifier: ^4.0.0-alpha.1 - version: 4.0.1(@parcel/watcher@2.5.1)(@types/node@24.0.15)(@vue/compiler-sfc@3.5.17)(better-sqlite3@11.10.0)(db0@0.3.2(better-sqlite3@11.10.0))(eslint@9.31.0(jiti@2.4.2))(ioredis@5.6.1)(magicast@0.3.5)(meow@13.2.0)(optionator@0.9.4)(rollup@4.45.1)(stylelint@16.22.0(typescript@5.8.3))(terser@5.43.1)(typescript@5.8.3)(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue-tsc@3.0.3(typescript@5.8.3))(yaml@2.8.0) + version: 4.0.1(@parcel/watcher@2.5.1)(@types/node@24.0.15)(@vue/compiler-sfc@3.5.17)(better-sqlite3@11.10.0)(db0@0.3.2(better-sqlite3@11.10.0))(eslint@9.31.0(jiti@2.4.2))(ioredis@5.6.1)(magicast@0.3.5)(meow@13.2.0)(optionator@0.9.4)(rollup@4.45.1)(stylelint@16.22.0(typescript@5.8.3))(terser@5.43.1)(typescript@5.8.3)(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue-tsc@3.0.3(typescript@5.8.3))(yaml@2.8.0) nuxt-og-image: specifier: 5.1.9 - version: 5.1.9(@unhead/vue@2.0.12(vue@3.5.17(typescript@5.8.3)))(magicast@0.3.5)(unstorage@1.16.1(db0@0.3.2(better-sqlite3@11.10.0))(ioredis@5.6.1))(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) + version: 5.1.9(@unhead/vue@2.0.12(vue@3.5.17(typescript@5.8.3)))(magicast@0.3.5)(unstorage@1.16.1(db0@0.3.2(better-sqlite3@11.10.0))(ioredis@5.6.1))(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) nuxt-security: specifier: 2.2.0 version: 2.2.0(magicast@0.3.5)(rollup@4.45.1) @@ -171,7 +171,7 @@ importers: version: 1.6.1 unocss: specifier: ^66.1.3 - version: 66.3.3(@unocss/webpack@66.3.3(webpack@5.99.9(esbuild@0.25.6)))(postcss@8.5.6)(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) + version: 66.3.3(@unocss/webpack@66.3.3(webpack@5.99.9(esbuild@0.25.6)))(postcss@8.5.6)(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) unplugin: specifier: ^2.3.5 version: 2.3.5 @@ -257,6 +257,9 @@ importers: gsap: specifier: ^3.13.0 version: 3.13.0 + mediabunny: + specifier: ^1.2.0 + version: 1.2.0 modern-screenshot: specifier: ^4.6.0 version: 4.6.5 @@ -272,9 +275,6 @@ importers: styled-components: specifier: ^6.1.18 version: 6.1.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - webm-muxer: - specifier: ^5.1.3 - version: 5.1.4 devDependencies: '@sanity/eslint-config-studio': specifier: 5.0.2 @@ -3122,6 +3122,9 @@ packages: '@rolldown/pluginutils@1.0.0-beta.19': resolution: {integrity: sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==} + '@rolldown/pluginutils@1.0.0-beta.27': + resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + '@rolldown/pluginutils@1.0.0-beta.28': resolution: {integrity: sha512-fe3/1HZ3qJmXvkGv1kacKq2b+x9gbcyF1hnmLBVrRFEQWoOcRapQjXf8+hgyxI0EJAbnKEtrp5yhohQCFCjycw==} @@ -4003,6 +4006,9 @@ packages: '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/dom-mediacapture-transform@0.1.11': + resolution: {integrity: sha512-Y2p+nGf1bF2XMttBnsVPHUWzRRZzqUoJAKmiP10b5umnO6DDrWI0BrGDJy1pOHoOULVmGSfFNkQrAlC5dcj6nQ==} + '@types/dom-webcodecs@0.1.15': resolution: {integrity: sha512-omOlCPvTWyPm4ZE5bZUhlSvnHM2ZWM2U+1cPiYFL/e8aV5O9MouELp+L4dMKNTON0nTeHqEg+KWDfFQMY5Wkaw==} @@ -4115,9 +4121,6 @@ packages: '@types/which@3.0.4': resolution: {integrity: sha512-liyfuo/106JdlgSchJzXEQCVArk0CvevqPote8F8HgWgJ3dRCcTHgJIsLDuee0kxk/mhbInzIZk3QWSZJ8R+2w==} - '@types/wicg-file-system-access@2020.9.8': - resolution: {integrity: sha512-ggMz8nOygG7d/stpH40WVaNvBwuyYLnrg5Mbyf6bmsj/8+gb6Ei4ZZ9/4PNpcPNTT8th9Q8sM8wYmWGjMWLX/A==} - '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} @@ -8073,6 +8076,9 @@ packages: media-tracks@0.3.3: resolution: {integrity: sha512-9P2FuUHnZZ3iji+2RQk7Zkh5AmZTnOG5fODACnjhCVveX1McY3jmCRHofIEI+yTBqplz7LXy48c7fQ3Uigp88w==} + mediabunny@1.2.0: + resolution: {integrity: sha512-XzGaADa1ptk8dKaRxJTuUa4D6Epl7P+Hyr4LG+imsYSpk7iD7H3qlHu274SctgKdDPxkve/wb5I8oC4uzKH8pw==} + mendoza@3.0.8: resolution: {integrity: sha512-iwxgEpSOx9BDLJMD0JAzNicqo9xdrvzt6w/aVwBKMndlA6z/DH41+o60H2uHB0vCR1Xr37UOgu9xFWJHvYsuKw==} engines: {node: '>=14.18'} @@ -11303,10 +11309,6 @@ packages: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} - webm-muxer@5.1.4: - resolution: {integrity: sha512-ditzgFVFbfqPaugkIr4mGhAdob5K9HY6Rzlh7TRsA368yA1sp/m5O7nQCcMLdgFDeNGtFPg8B+MeXLtpzKWX6Q==} - deprecated: This library is superseded by Mediabunny. Please migrate to it. - webpack-sources@3.3.3: resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} engines: {node: '>=10.13.0'} @@ -14230,11 +14232,11 @@ snapshots: '@nuxt/devalue@2.0.2': {} - '@nuxt/devtools-kit@2.6.2(magicast@0.3.5)(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))': + '@nuxt/devtools-kit@2.6.2(magicast@0.3.5)(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))': dependencies: '@nuxt/kit': 4.0.1(magicast@0.3.5) execa: 8.0.1 - vite: 7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) + vite: 7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) transitivePeerDependencies: - magicast @@ -14249,12 +14251,12 @@ snapshots: prompts: 2.4.2 semver: 7.7.2 - '@nuxt/devtools@2.6.2(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))': + '@nuxt/devtools@2.6.2(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))': dependencies: - '@nuxt/devtools-kit': 2.6.2(magicast@0.3.5)(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) + '@nuxt/devtools-kit': 2.6.2(magicast@0.3.5)(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) '@nuxt/devtools-wizard': 2.6.2 '@nuxt/kit': 4.0.1(magicast@0.3.5) - '@vue/devtools-core': 7.7.7(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) + '@vue/devtools-core': 7.7.7(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) '@vue/devtools-kit': 7.7.7 birpc: 2.5.0 consola: 3.4.2 @@ -14279,9 +14281,9 @@ snapshots: sirv: 3.0.1 structured-clone-es: 1.0.0 tinyglobby: 0.2.14 - vite: 7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) - vite-plugin-inspect: 11.3.0(@nuxt/kit@4.0.1(magicast@0.3.5))(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) - vite-plugin-vue-tracer: 1.0.0(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) + vite: 7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) + vite-plugin-inspect: 11.3.0(@nuxt/kit@4.0.1(magicast@0.3.5))(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) + vite-plugin-vue-tracer: 1.0.0(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) which: 5.0.0 ws: 8.18.3 transitivePeerDependencies: @@ -14330,10 +14332,10 @@ snapshots: - supports-color - typescript - '@nuxt/eslint@1.6.0(@typescript-eslint/utils@8.37.0(eslint@9.31.0(jiti@2.4.2))(typescript@5.8.3))(@vue/compiler-sfc@3.5.17)(eslint-import-resolver-node@0.3.9)(eslint@9.31.0(jiti@2.4.2))(magicast@0.3.5)(typescript@5.8.3)(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))': + '@nuxt/eslint@1.6.0(@typescript-eslint/utils@8.37.0(eslint@9.31.0(jiti@2.4.2))(typescript@5.8.3))(@vue/compiler-sfc@3.5.17)(eslint-import-resolver-node@0.3.9)(eslint@9.31.0(jiti@2.4.2))(magicast@0.3.5)(typescript@5.8.3)(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))': dependencies: '@eslint/config-inspector': 1.1.0(eslint@9.31.0(jiti@2.4.2)) - '@nuxt/devtools-kit': 2.6.2(magicast@0.3.5)(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) + '@nuxt/devtools-kit': 2.6.2(magicast@0.3.5)(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) '@nuxt/eslint-config': 1.6.0(@typescript-eslint/utils@8.37.0(eslint@9.31.0(jiti@2.4.2))(typescript@5.8.3))(@vue/compiler-sfc@3.5.17)(eslint-import-resolver-node@0.3.9)(eslint@9.31.0(jiti@2.4.2))(typescript@5.8.3) '@nuxt/eslint-plugin': 1.6.0(eslint@9.31.0(jiti@2.4.2))(typescript@5.8.3) '@nuxt/kit': 4.0.1(magicast@0.3.5) @@ -14358,9 +14360,9 @@ snapshots: - utf-8-validate - vite - '@nuxt/fonts@0.11.4(db0@0.3.2(better-sqlite3@11.10.0))(ioredis@5.6.1)(magicast@0.3.5)(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))': + '@nuxt/fonts@0.11.4(db0@0.3.2(better-sqlite3@11.10.0))(ioredis@5.6.1)(magicast@0.3.5)(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))': dependencies: - '@nuxt/devtools-kit': 2.6.2(magicast@0.3.5)(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) + '@nuxt/devtools-kit': 2.6.2(magicast@0.3.5)(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) '@nuxt/kit': 4.0.1(magicast@0.3.5) consola: 3.4.2 css-tree: 3.1.0 @@ -15183,6 +15185,8 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.19': {} + '@rolldown/pluginutils@1.0.0-beta.27': {} + '@rolldown/pluginutils@1.0.0-beta.28': {} '@rollup/plugin-alias@5.1.1(rollup@4.45.1)': @@ -16481,6 +16485,10 @@ snapshots: '@types/deep-eql@4.0.2': {} + '@types/dom-mediacapture-transform@0.1.11': + dependencies: + '@types/dom-webcodecs': 0.1.15 + '@types/dom-webcodecs@0.1.15': {} '@types/eslint-scope@3.7.7': @@ -16585,8 +16593,6 @@ snapshots: '@types/which@3.0.4': {} - '@types/wicg-file-system-access@2020.9.8': {} - '@types/yauzl@2.10.3': dependencies: '@types/node': 24.0.15 @@ -16797,13 +16803,13 @@ snapshots: unhead: 2.0.12 vue: 3.5.17(typescript@5.8.3) - '@unocss/astro@66.3.3(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))': + '@unocss/astro@66.3.3(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))': dependencies: '@unocss/core': 66.3.3 '@unocss/reset': 66.3.3 - '@unocss/vite': 66.3.3(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) + '@unocss/vite': 66.3.3(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) optionalDependencies: - vite: 7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) + vite: 7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) transitivePeerDependencies: - vue @@ -16845,7 +16851,7 @@ snapshots: transitivePeerDependencies: - vue - '@unocss/nuxt@66.3.3(magicast@0.3.5)(postcss@8.5.6)(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))(webpack@5.99.9(esbuild@0.25.6))': + '@unocss/nuxt@66.3.3(magicast@0.3.5)(postcss@8.5.6)(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))(webpack@5.99.9(esbuild@0.25.6))': dependencies: '@nuxt/kit': 4.0.1(magicast@0.3.5) '@unocss/config': 66.3.3 @@ -16858,9 +16864,9 @@ snapshots: '@unocss/preset-web-fonts': 66.3.3 '@unocss/preset-wind': 66.3.3 '@unocss/reset': 66.3.3 - '@unocss/vite': 66.3.3(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) + '@unocss/vite': 66.3.3(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) '@unocss/webpack': 66.3.3(webpack@5.99.9(esbuild@0.25.6)) - unocss: 66.3.3(@unocss/webpack@66.3.3(webpack@5.99.9(esbuild@0.25.6)))(postcss@8.5.6)(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) + unocss: 66.3.3(@unocss/webpack@66.3.3(webpack@5.99.9(esbuild@0.25.6)))(postcss@8.5.6)(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) transitivePeerDependencies: - magicast - postcss @@ -16958,7 +16964,7 @@ snapshots: dependencies: '@unocss/core': 66.3.3 - '@unocss/vite@66.3.3(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))': + '@unocss/vite@66.3.3(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))': dependencies: '@ampproject/remapping': 2.3.0 '@unocss/config': 66.3.3 @@ -16969,7 +16975,7 @@ snapshots: pathe: 2.0.3 tinyglobby: 0.2.14 unplugin-utils: 0.2.4 - vite: 7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) + vite: 7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) transitivePeerDependencies: - vue @@ -17240,14 +17246,14 @@ snapshots: '@vue/devtools-api@6.6.4': {} - '@vue/devtools-core@7.7.7(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))': + '@vue/devtools-core@7.7.7(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))': dependencies: '@vue/devtools-kit': 7.7.7 '@vue/devtools-shared': 7.7.7 mitt: 3.0.1 nanoid: 5.1.5 pathe: 2.0.3 - vite-hot-client: 2.1.0(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) + vite-hot-client: 2.1.0(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) vue: 3.5.17(typescript@5.8.3) transitivePeerDependencies: - vite @@ -21372,6 +21378,11 @@ snapshots: media-tracks@0.3.3: {} + mediabunny@1.2.0: + dependencies: + '@types/dom-mediacapture-transform': 0.1.11 + '@types/dom-webcodecs': 0.1.15 + mendoza@3.0.8: {} meow@12.1.1: {} @@ -22009,9 +22020,9 @@ snapshots: transitivePeerDependencies: - magicast - nuxt-og-image@5.1.9(@unhead/vue@2.0.12(vue@3.5.17(typescript@5.8.3)))(magicast@0.3.5)(unstorage@1.16.1(db0@0.3.2(better-sqlite3@11.10.0))(ioredis@5.6.1))(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)): + nuxt-og-image@5.1.9(@unhead/vue@2.0.12(vue@3.5.17(typescript@5.8.3)))(magicast@0.3.5)(unstorage@1.16.1(db0@0.3.2(better-sqlite3@11.10.0))(ioredis@5.6.1))(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)): dependencies: - '@nuxt/devtools-kit': 2.6.2(magicast@0.3.5)(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) + '@nuxt/devtools-kit': 2.6.2(magicast@0.3.5)(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) '@nuxt/kit': 4.0.1(magicast@0.3.5) '@resvg/resvg-js': 2.6.2 '@resvg/resvg-wasm': 2.6.2 @@ -22087,11 +22098,11 @@ snapshots: - magicast - vue - nuxt@4.0.1(@parcel/watcher@2.5.1)(@types/node@24.0.15)(@vue/compiler-sfc@3.5.17)(better-sqlite3@11.10.0)(db0@0.3.2(better-sqlite3@11.10.0))(eslint@9.31.0(jiti@2.4.2))(ioredis@5.6.1)(magicast@0.3.5)(meow@13.2.0)(optionator@0.9.4)(rollup@4.45.1)(stylelint@16.22.0(typescript@5.8.3))(terser@5.43.1)(typescript@5.8.3)(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue-tsc@3.0.3(typescript@5.8.3))(yaml@2.8.0): + nuxt@4.0.1(@parcel/watcher@2.5.1)(@types/node@24.0.15)(@vue/compiler-sfc@3.5.17)(better-sqlite3@11.10.0)(db0@0.3.2(better-sqlite3@11.10.0))(eslint@9.31.0(jiti@2.4.2))(ioredis@5.6.1)(magicast@0.3.5)(meow@13.2.0)(optionator@0.9.4)(rollup@4.45.1)(stylelint@16.22.0(typescript@5.8.3))(terser@5.43.1)(typescript@5.8.3)(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue-tsc@3.0.3(typescript@5.8.3))(yaml@2.8.0): dependencies: '@nuxt/cli': 3.26.4(magicast@0.3.5) '@nuxt/devalue': 2.0.2 - '@nuxt/devtools': 2.6.2(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) + '@nuxt/devtools': 2.6.2(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) '@nuxt/kit': 4.0.1(magicast@0.3.5) '@nuxt/schema': 4.0.1 '@nuxt/telemetry': 2.6.6(magicast@0.3.5) @@ -24919,9 +24930,9 @@ snapshots: dependencies: normalize-path: 2.1.1 - unocss@66.3.3(@unocss/webpack@66.3.3(webpack@5.99.9(esbuild@0.25.6)))(postcss@8.5.6)(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)): + unocss@66.3.3(@unocss/webpack@66.3.3(webpack@5.99.9(esbuild@0.25.6)))(postcss@8.5.6)(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)): dependencies: - '@unocss/astro': 66.3.3(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) + '@unocss/astro': 66.3.3(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) '@unocss/cli': 66.3.3 '@unocss/core': 66.3.3 '@unocss/postcss': 66.3.3(postcss@8.5.6) @@ -24939,10 +24950,10 @@ snapshots: '@unocss/transformer-compile-class': 66.3.3 '@unocss/transformer-directives': 66.3.3 '@unocss/transformer-variant-group': 66.3.3 - '@unocss/vite': 66.3.3(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) + '@unocss/vite': 66.3.3(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)) optionalDependencies: '@unocss/webpack': 66.3.3(webpack@5.99.9(esbuild@0.25.6)) - vite: 7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) + vite: 7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) transitivePeerDependencies: - postcss - supports-color @@ -25188,15 +25199,15 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - vite-dev-rpc@1.1.0(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)): + vite-dev-rpc@1.1.0(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)): dependencies: birpc: 2.5.0 - vite: 7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) - vite-hot-client: 2.1.0(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) + vite: 7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) + vite-hot-client: 2.1.0(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) - vite-hot-client@2.1.0(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)): + vite-hot-client@2.1.0(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)): dependencies: - vite: 7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) + vite: 7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) vite-node@3.2.4(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0): dependencies: @@ -25239,7 +25250,7 @@ snapshots: typescript: 5.8.3 vue-tsc: 3.0.3(typescript@5.8.3) - vite-plugin-inspect@11.3.0(@nuxt/kit@4.0.1(magicast@0.3.5))(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)): + vite-plugin-inspect@11.3.0(@nuxt/kit@4.0.1(magicast@0.3.5))(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)): dependencies: ansis: 4.1.0 debug: 4.4.1(supports-color@8.1.1) @@ -25249,21 +25260,21 @@ snapshots: perfect-debounce: 1.0.0 sirv: 3.0.1 unplugin-utils: 0.2.4 - vite: 7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) - vite-dev-rpc: 1.1.0(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) + vite: 7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) + vite-dev-rpc: 1.1.0(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)) optionalDependencies: '@nuxt/kit': 4.0.1(magicast@0.3.5) transitivePeerDependencies: - supports-color - vite-plugin-vue-tracer@1.0.0(vite@7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)): + vite-plugin-vue-tracer@1.0.0(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)): dependencies: estree-walker: 3.0.3 exsolve: 1.0.7 magic-string: 0.30.17 pathe: 2.0.3 source-map-js: 1.2.1 - vite: 7.0.3(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) + vite: 7.0.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0) vue: 3.5.17(typescript@5.8.3) vite-tsconfig-paths@5.1.4(typescript@5.8.3)(vite@6.3.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0)): @@ -25463,11 +25474,6 @@ snapshots: webidl-conversions@7.0.0: {} - webm-muxer@5.1.4: - dependencies: - '@types/dom-webcodecs': 0.1.15 - '@types/wicg-file-system-access': 2020.9.8 - webpack-sources@3.3.3: {} webpack-virtual-modules@0.6.2: {} -- 2.51.2