@framefields/compositions 0.0.0-stage → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENCE +202 -0
- package/dist/index.d.mts +81 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +898 -0
- package/dist/index.mjs.map +1 -0
- package/dist/layer-logic-DBs4NHoi.mjs +162 -0
- package/dist/layer-logic-DBs4NHoi.mjs.map +1 -0
- package/dist/program/index.d.mts +3401 -0
- package/dist/program/index.d.mts.map +1 -0
- package/dist/program/index.mjs +5454 -0
- package/dist/program/index.mjs.map +1 -0
- package/dist/server.d.mts +2 -0
- package/dist/server.mjs +3 -0
- package/dist/timing-CHy-6wsp.d.mts +53 -0
- package/dist/timing-CHy-6wsp.d.mts.map +1 -0
- package/package.json +63 -3
- package/README.md +0 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["durationMs","localSamplesCount","localChannels"],"sources":["../src/compositions/canvas-composition.ts","../src/compositions/composition-state.ts","../src/utils/normalization.ts","../src/utils/audio-extractor.ts"],"sourcesContent":["import {\n\ttype ConnectedInput,\n\ttype FrameContext,\n\ttype FrameSignal,\n\tgetActiveMediaMetadata,\n\tgetMediaType,\n\tisSignal,\n\tupdateClockSignals,\n\ttype VirtualMediaData,\n} from \"@framefields/core\";\nimport {\n\ttype GPUCommandEncoder,\n\ttype GPUTexture,\n\ttype GPUTextureView,\n\ttype NodeRenderProps,\n\twebgpuRegistry,\n} from \"@framefields/node-sdk\";\nimport {\n\tdrawCaptionNode,\n\tdrawGifNode,\n\tdrawImageNode,\n\tdrawLottieNode,\n\tdrawParagraphNode,\n\tdrawSignalNode,\n\tdrawSvgNode,\n\tdrawVideoNode,\n\ttype RenderContextValue,\n\tsignalRegistry,\n} from \"@framefields/webgpu-renderers\";\nimport { computeRenderParams } from \"../utils/apply-operations.js\";\n\n// Cache segment ranges per (segments reference) to avoid recomputation each frame\nconst segmentRangeCache = new WeakMap<\n\tobject,\n\t{ fps: number; ranges: { seg: any; start: number; duration: number }[] }\n>();\n\nfunction getCachedSegmentRanges(\n\tsegments: any[],\n\tfps: number,\n): { seg: any; start: number; duration: number }[] {\n\tconst cached = segmentRangeCache.get(segments);\n\tif (cached && cached.fps === fps) {\n\t\treturn cached.ranges;\n\t}\n\n\tlet currentStart = 0;\n\tconst ranges = segments.map((seg: any) => {\n\t\tconst durSec = (seg.endSec ?? 0) - seg.startSec;\n\t\tconst durFrames = Math.max(1, Math.round(durSec * fps));\n\t\tconst start = currentStart;\n\t\tcurrentStart += durFrames;\n\t\treturn { seg, start, duration: durFrames };\n\t});\n\n\tsegmentRangeCache.set(segments, { fps, ranges });\n\treturn ranges;\n}\n\n// Pool FrameContext objects to reduce GC pressure\nconst frameCtxPool: FrameContext[] = [];\n\nfunction acquireFrameContext(): FrameContext {\n\treturn frameCtxPool.pop() ?? ({} as FrameContext);\n}\n\n/**\n * Effect operations carry every config field as a signal. Hand node renderers\n * the plain value for this frame (nested objects/arrays included), keeping only\n * GPU-bound signals intact since those are consumed as textures.\n */\nfunction resolveSignalOperation(\n\tvirtualMedia: VirtualMediaData,\n\tframeCtx: FrameContext,\n): VirtualMediaData {\n\tconst op = virtualMedia.operation as Record<string, unknown>;\n\tconst resolved: Record<string, unknown> = { ...op };\n\tfor (const [key, sig] of Object.entries(\n\t\top.signals as Record<string, unknown>,\n\t)) {\n\t\tif (isSignal(sig) && !(sig as FrameSignal<unknown>).gpuBinding) {\n\t\t\tresolved[key] = sig.get(frameCtx);\n\t\t}\n\t}\n\treturn { ...virtualMedia, operation: resolved } as VirtualMediaData;\n}\n\nexport async function drawCompositionTree(\n\tctx: RenderContextValue,\n\tencoder: GPUCommandEncoder,\n\ttargetView: GPUTextureView,\n\ttargetTexture: GPUTexture,\n\ttargetWidth: number,\n\ttargetHeight: number,\n\tvirtualMedia: VirtualMediaData,\n\tprops: NodeRenderProps,\n\tinheritedSeekOffset = 0,\n\tinheritedClockOffset = 0,\n): Promise<void> {\n\tconst fps = props.fps ?? 24;\n\tconst op = virtualMedia.operation as any;\n\tif (!op) return;\n\n\tconst isCompositor = op.op === \"Compositor\";\n\n\tconst frame = props.frame ?? 0;\n\tconst segments = op.timeline?.segments || [];\n\tconst nodeStartFrame = op.startFrame ?? op.timeline?.startFrame ?? 0;\n\tconst localFrame = frame - nodeStartFrame;\n\n\tconst isTimelineProvider =\n\t\top.timeline !== undefined ||\n\t\top.startFrame !== undefined ||\n\t\top.op === \"compose\";\n\n\tconst resolvedDurationMs = isTimelineProvider\n\t\t? (getActiveMediaMetadata(virtualMedia)?.durationMs ??\n\t\t\tprops.durationMs ??\n\t\t\tundefined)\n\t\t: (props.durationMs ??\n\t\t\tgetActiveMediaMetadata(virtualMedia)?.durationMs ??\n\t\t\tundefined);\n\n\tconst isLeafNode =\n\t\top.op === \"source\" || op.op === \"text\" || op.op === \"caption\";\n\tif (!isLeafNode) {\n\t\tupdateClockSignals(frame, fps, resolvedDurationMs);\n\t}\n\n\tconst frameCtx = acquireFrameContext();\n\tframeCtx.frame = frame;\n\tframeCtx.fps = fps;\n\tframeCtx.time = fps > 0 ? frame / fps : 0;\n\tframeCtx.duration = (resolvedDurationMs ?? 0) / 1000;\n\tframeCtx.durationMs = resolvedDurationMs ?? 0;\n\tframeCtx.progress =\n\t\tresolvedDurationMs && resolvedDurationMs > 0\n\t\t\t? Math.max(0, Math.min(1, ((frame / fps) * 1000) / resolvedDurationMs))\n\t\t\t: 0;\n\tframeCtx.deltaTime = fps > 0 ? 1 / fps : 0;\n\n\tconst resolvedElapsedMs = isTimelineProvider\n\t\t? ((localFrame !== undefined && fps !== undefined\n\t\t\t\t? (localFrame / fps) * 1000\n\t\t\t\t: undefined) ?? props.elapsedMs)\n\t\t: (props.elapsedMs ??\n\t\t\t(localFrame !== undefined && fps !== undefined\n\t\t\t\t? (localFrame / fps) * 1000\n\t\t\t\t: undefined));\n\n\tconst effectiveLocalFrame =\n\t\tlocalFrame + Math.round(inheritedSeekOffset * fps);\n\n\tlet activeSeg: any = null;\n\tlet windowStartFrame = 0;\n\n\tif (segments.length > 0) {\n\t\tconst segmentWithRange = getCachedSegmentRanges(segments, fps);\n\n\t\tconst active = segmentWithRange.find(\n\t\t\t({ start, duration }: { start: number; duration: number }) =>\n\t\t\t\teffectiveLocalFrame >= start && effectiveLocalFrame < start + duration,\n\t\t);\n\n\t\tif (active) {\n\t\t\tactiveSeg = active.seg;\n\t\t\twindowStartFrame = active.start;\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\t}\n\n\tconst segmentLocalFrame = localFrame - windowStartFrame;\n\tconst segmentSeekOffset = activeSeg\n\t\t? activeSeg.startSec - windowStartFrame / fps\n\t\t: 0;\n\tconst accumulatedSeekOffsetSec = inheritedSeekOffset + segmentSeekOffset;\n\tconst accumulatedClockOffsetSec =\n\t\tinheritedClockOffset + windowStartFrame / fps;\n\tif (typeof op.onRequestFrame === \"function\") {\n\t\top.onRequestFrame(frameCtx);\n\t} else if (op.effect && typeof op.effect.notifyFrame === \"function\") {\n\t\top.effect.notifyFrame(frameCtx);\n\t}\n\n\tconst CustomRenderer = webgpuRegistry.get(op.op);\n\n\tif (CustomRenderer) {\n\t\tif (op.signals) {\n\t\t\tvirtualMedia = resolveSignalOperation(virtualMedia, frameCtx);\n\t\t}\n\t\tconst inputs = op?.inputs as Record<string, ConnectedInput> | undefined;\n\t\tif (inputs) {\n\t\t\tfor (const entry of Object.values(inputs)) {\n\t\t\t\tif (entry?.connectionValid && entry?.outputItem?.type === \"LUT\") {\n\t\t\t\t\tconst lutVirtualMedia = entry.outputItem\n\t\t\t\t\t\t.data as VirtualMediaData | null;\n\t\t\t\t\tif (\n\t\t\t\t\t\tlutVirtualMedia &&\n\t\t\t\t\t\ttypeof lutVirtualMedia === \"object\" &&\n\t\t\t\t\t\tlutVirtualMedia.operation\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst lutW = lutVirtualMedia.metadata?.width ?? targetWidth;\n\t\t\t\t\t\tconst lutH = lutVirtualMedia.metadata?.height ?? targetHeight;\n\t\t\t\t\t\tconst dummyTex = ctx.renderer.getTemporaryTexture(lutW, lutH);\n\t\t\t\t\t\tconst dummyView = dummyTex.createView();\n\t\t\t\t\t\tawait drawCompositionTree(\n\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\tencoder,\n\t\t\t\t\t\t\tdummyView,\n\t\t\t\t\t\t\tdummyTex,\n\t\t\t\t\t\t\tlutW,\n\t\t\t\t\t\t\tlutH,\n\t\t\t\t\t\t\tlutVirtualMedia,\n\t\t\t\t\t\t\t{ ...props, virtualMedia: lutVirtualMedia },\n\t\t\t\t\t\t\taccumulatedSeekOffsetSec,\n\t\t\t\t\t\t\taccumulatedClockOffsetSec,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} else if (\n\t\t\t\t\tentry?.connectionValid &&\n\t\t\t\t\tentry?.outputItem?.type === \"Signal\"\n\t\t\t\t) {\n\t\t\t\t\tconst sigData = entry.outputItem.data as\n\t\t\t\t\t\t| Record<string, unknown>\n\t\t\t\t\t\t| undefined;\n\t\t\t\t\tif (sigData && typeof sigData === \"object\") {\n\t\t\t\t\t\tawait signalRegistry.ensureAudioSourcesExtracted(\n\t\t\t\t\t\t\tctx.device,\n\t\t\t\t\t\t\t(sigData.signalConfig as Record<string, unknown> | undefined) ??\n\t\t\t\t\t\t\t\tsigData,\n\t\t\t\t\t\t\tfps,\n\t\t\t\t\t\t\tprops.renderId,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst pass = ctx.renderer.beginFrame(\n\t\t\tencoder,\n\t\t\ttargetView,\n\t\t\t{ r: 0, g: 0, b: 0, a: 0 },\n\t\t\ttargetWidth,\n\t\t\ttargetHeight,\n\t\t\t\"load\",\n\t\t);\n\t\tlet passEnded = false;\n\t\tconst originalEnd = pass.end.bind(pass);\n\t\tpass.end = () => {\n\t\t\tif (!passEnded) {\n\t\t\t\toriginalEnd();\n\t\t\t\tpassEnded = true;\n\t\t\t}\n\t\t};\n\t\tconst renderArgs = {\n\t\t\tctx,\n\t\t\tencoder,\n\t\t\tpass,\n\t\t\ttargetView,\n\t\t\ttargetTexture,\n\t\t\ttargetWidth,\n\t\t\ttargetHeight,\n\t\t\tprops: {\n\t\t\t\t...props,\n\t\t\t\tvirtualMedia,\n\t\t\t\tinheritedSeekOffset: accumulatedSeekOffsetSec,\n\t\t\t\tinheritedClockOffset: accumulatedClockOffsetSec,\n\t\t\t\tdurationMs: resolvedDurationMs,\n\t\t\t\telapsedMs: resolvedElapsedMs,\n\t\t\t},\n\t\t\tdrawChild: async (\n\t\t\t\tchild: VirtualMediaData,\n\t\t\t\toverrides?: Partial<NodeRenderProps>,\n\t\t\t\ttargetViewOverride?: GPUTextureView,\n\t\t\t\ttargetTextureOverride?: GPUTexture,\n\t\t\t\ttargetWidthOverride?: number,\n\t\t\t\ttargetHeightOverride?: number,\n\t\t\t) => {\n\t\t\t\tawait drawCompositionTree(\n\t\t\t\t\tctx,\n\t\t\t\t\tencoder,\n\t\t\t\t\ttargetViewOverride ?? targetView,\n\t\t\t\t\ttargetTextureOverride ?? targetTexture,\n\t\t\t\t\ttargetWidthOverride ?? targetWidth,\n\t\t\t\t\ttargetHeightOverride ?? targetHeight,\n\t\t\t\t\tchild,\n\t\t\t\t\t{\n\t\t\t\t\t\t...props,\n\t\t\t\t\t\tdurationMs: resolvedDurationMs,\n\t\t\t\t\t\telapsedMs: resolvedElapsedMs,\n\t\t\t\t\t\tvirtualMedia: child,\n\t\t\t\t\t\t...overrides,\n\t\t\t\t\t\t// Merge, never replace: the caller knows which of its own\n\t\t\t\t\t\t// textures are still live (a compositor's canvas, its groups).\n\t\t\t\t\t\texcludeTextures: [\n\t\t\t\t\t\t\t...(props.excludeTextures || []),\n\t\t\t\t\t\t\t...(overrides?.excludeTextures || []),\n\t\t\t\t\t\t\ttargetTextureOverride ?? targetTexture,\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t\tisCompositor ? 0 : accumulatedSeekOffsetSec,\n\t\t\t\t\taccumulatedClockOffsetSec,\n\t\t\t\t);\n\t\t\t},\n\t\t};\n\t\tawait CustomRenderer(renderArgs);\n\t\trenderArgs.pass.end();\n\t\treturn;\n\t}\n\n\tif (op.op === \"LUT\") {\n\t\treturn;\n\t}\n\n\tif (\n\t\top.op === \"Signal\" ||\n\t\top.op === \"SignalMath\" ||\n\t\top.dataType === \"Signal\"\n\t) {\n\t\tconst pass = ctx.renderer.beginFrame(\n\t\t\tencoder,\n\t\t\ttargetView,\n\t\t\t{ r: 0, g: 0, b: 0, a: 0 },\n\t\t\ttargetWidth,\n\t\t\ttargetHeight,\n\t\t\t\"load\",\n\t\t);\n\n\t\tawait drawSignalNode(ctx, encoder, pass, {\n\t\t\tnodeId:\n\t\t\t\t(op.nodeId as string) ||\n\t\t\t\t(op.signalConfig?.nodeId as string) ||\n\t\t\t\tprops.renderId,\n\t\t\tfunc: op.func,\n\t\t\tamplitude: Number(op.amplitude ?? 1),\n\t\t\tfrequency: Number(op.frequency ?? 1),\n\t\t\tphase: Number(op.phase ?? 0),\n\t\t\toffset: Number(op.offset ?? 0),\n\t\t\tsignalConfig: { ...op.signalConfig, ...op },\n\t\t\tframe,\n\t\t\tfps,\n\t\t\telapsedMs: resolvedElapsedMs,\n\t\t\tdurationMs: resolvedDurationMs ?? 0,\n\t\t\twidth: targetWidth,\n\t\t\theight: targetHeight,\n\t\t\tdrawChild: async (\n\t\t\t\tchild: any,\n\t\t\t\tchildProps: any,\n\t\t\t\tchildView: GPUTextureView,\n\t\t\t\tchildTex: GPUTexture,\n\t\t\t\tchildW: number,\n\t\t\t\tchildH: number,\n\t\t\t) => {\n\t\t\t\tawait drawCompositionTree(\n\t\t\t\t\tctx,\n\t\t\t\t\tencoder,\n\t\t\t\t\tchildView,\n\t\t\t\t\tchildTex,\n\t\t\t\t\tchildW,\n\t\t\t\t\tchildH,\n\t\t\t\t\tchild,\n\t\t\t\t\t{\n\t\t\t\t\t\t...props,\n\t\t\t\t\t\tdurationMs: resolvedDurationMs,\n\t\t\t\t\t\telapsedMs: resolvedElapsedMs,\n\t\t\t\t\t\t...childProps,\n\t\t\t\t\t\texcludeTextures: [\n\t\t\t\t\t\t\t...(props.excludeTextures || []),\n\t\t\t\t\t\t\t...(childProps?.excludeTextures || []),\n\t\t\t\t\t\t\tchildTex,\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t},\n\t\t});\n\n\t\tpass.end();\n\t\treturn;\n\t}\n\n\tif (op.op === \"source\" || op.op === \"text\" || op.op === \"caption\") {\n\t\tconst pass = ctx.renderer.beginFrame(\n\t\t\tencoder,\n\t\t\ttargetView,\n\t\t\t{ r: 0, g: 0, b: 0, a: 0 },\n\t\t\ttargetWidth,\n\t\t\ttargetHeight,\n\t\t\t\"load\",\n\t\t);\n\n\t\tif (op.op === \"source\") {\n\t\t\tconst mediaType = getMediaType(virtualMedia);\n\t\t\tconst params = computeRenderParams(virtualMedia);\n\n\t\t\tif (params.sourceUrl) {\n\t\t\t\tconst containerWidth = props.containerWidth ?? ctx.surface.width;\n\t\t\t\tconst containerHeight = props.containerHeight ?? ctx.surface.height;\n\n\t\t\t\tif (mediaType === \"Image\") {\n\t\t\t\t\tawait drawImageNode(ctx, pass, {\n\t\t\t\t\t\tsrc: params.sourceUrl,\n\t\t\t\t\t\tdstRect: {\n\t\t\t\t\t\t\tx: 0,\n\t\t\t\t\t\t\ty: 0,\n\t\t\t\t\t\t\twidth: containerWidth,\n\t\t\t\t\t\t\theight: containerHeight,\n\t\t\t\t\t\t},\n\t\t\t\t\t\topacity: Number(op.opacity ?? 1) * Number(props.opacity ?? 1),\n\t\t\t\t\t\tisHeadless: props.isHeadless,\n\t\t\t\t\t});\n\t\t\t\t} else if (mediaType === \"SVG\") {\n\t\t\t\t\tawait drawSvgNode(ctx, pass, {\n\t\t\t\t\t\tsrc: params.sourceUrl,\n\t\t\t\t\t\tdstRect: {\n\t\t\t\t\t\t\tx: 0,\n\t\t\t\t\t\t\ty: 0,\n\t\t\t\t\t\t\twidth: containerWidth,\n\t\t\t\t\t\t\theight: containerHeight,\n\t\t\t\t\t\t},\n\t\t\t\t\t\topacity: Number(op.opacity ?? 1),\n\t\t\t\t\t\tisHeadless: props.isHeadless,\n\t\t\t\t\t});\n\t\t\t\t} else if (mediaType === \"Lottie\") {\n\t\t\t\t\tawait drawLottieNode(ctx, pass, {\n\t\t\t\t\t\tsrc: params.sourceUrl,\n\t\t\t\t\t\tdstRect: {\n\t\t\t\t\t\t\tx: 0,\n\t\t\t\t\t\t\ty: 0,\n\t\t\t\t\t\t\twidth: containerWidth,\n\t\t\t\t\t\t\theight: containerHeight,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tframe:\n\t\t\t\t\t\t\tsegmentLocalFrame + Math.round(accumulatedSeekOffsetSec * fps),\n\t\t\t\t\t\tfps,\n\t\t\t\t\t\topacity: Number(op.opacity ?? 1) * Number(props.opacity ?? 1),\n\t\t\t\t\t\tisHeadless: props.isHeadless,\n\t\t\t\t\t});\n\t\t\t\t} else if (mediaType === \"GIF\") {\n\t\t\t\t\tawait drawGifNode(ctx, pass, {\n\t\t\t\t\t\tsrc: params.sourceUrl,\n\t\t\t\t\t\tdstRect: {\n\t\t\t\t\t\t\tx: 0,\n\t\t\t\t\t\t\ty: 0,\n\t\t\t\t\t\t\twidth: containerWidth,\n\t\t\t\t\t\t\theight: containerHeight,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tframe:\n\t\t\t\t\t\t\tsegmentLocalFrame + Math.round(accumulatedSeekOffsetSec * fps),\n\t\t\t\t\t\tfps,\n\t\t\t\t\t\topacity: Number(op.opacity ?? 1) * Number(props.opacity ?? 1),\n\t\t\t\t\t\tisHeadless: props.isHeadless,\n\t\t\t\t\t});\n\t\t\t\t} else if (mediaType === \"Text\") {\n\t\t\t\t\tconst opText = { ...op } as any;\n\t\t\t\t\tdrawParagraphNode(ctx, pass, {\n\t\t\t\t\t\ttext: opText.text || \"\",\n\t\t\t\t\t\tdstRect: {\n\t\t\t\t\t\t\tx: Number(opText.x ?? 0),\n\t\t\t\t\t\t\ty: Number(opText.y ?? 0),\n\t\t\t\t\t\t\twidth: Number(opText.width ?? containerWidth),\n\t\t\t\t\t\t\theight: Number(opText.height ?? containerHeight),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfontFamily: opText.fontFamily,\n\t\t\t\t\t\tfontSize: Number(opText.fontSize ?? 48),\n\t\t\t\t\t\tcolor: opText.fill ?? opText.color ?? \"white\",\n\t\t\t\t\t\twidth: opText.width ? Number(opText.width) : undefined,\n\t\t\t\t\t\theight: opText.height ? Number(opText.height) : undefined,\n\t\t\t\t\t\tlineHeight: Number(opText.lineHeight ?? 1.2),\n\t\t\t\t\t\talign: opText.align,\n\t\t\t\t\t\tverticalAlign: opText.verticalAlign,\n\t\t\t\t\t\tfontWeight: opText.fontWeight,\n\t\t\t\t\t\tfontStyle: opText.fontStyle,\n\t\t\t\t\t\tletterSpacing: opText.letterSpacing,\n\t\t\t\t\t\tshadows: opText.shadows,\n\t\t\t\t\t\ttextBackgroundColor: opText.textBackgroundColor,\n\t\t\t\t\t\tborderRadius:\n\t\t\t\t\t\t\topText.borderRadius != null\n\t\t\t\t\t\t\t\t? Number(opText.borderRadius)\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\tpadding:\n\t\t\t\t\t\t\topText.padding != null ? Number(opText.padding) : undefined,\n\t\t\t\t\t\tstroke: opText.stroke,\n\t\t\t\t\t\tstrokeWidth:\n\t\t\t\t\t\t\t(opText.strokeWidth ?? opText.strokeThickness)\n\t\t\t\t\t\t\t\t? Number(opText.strokeWidth ?? opText.strokeThickness)\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\tstrokeAlign: opText.strokeAlign,\n\t\t\t\t\t\topacity: Number(opText.opacity ?? 1) * Number(props.opacity ?? 1),\n\t\t\t\t\t\tisHeadless: props.isHeadless,\n\t\t\t\t\t\tanimation: opText.animation ?? opText.textAnimation,\n\t\t\t\t\t\tanimators: opText.animators,\n\t\t\t\t\t\tpathOptions: opText.pathOptions,\n\t\t\t\t\t\ttypewriter: opText.typewriter,\n\t\t\t\t\t\tmarquee: opText.marquee,\n\t\t\t\t\t\ttextProgress:\n\t\t\t\t\t\t\topText.textProgress != null\n\t\t\t\t\t\t\t\t? Number(opText.textProgress)\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\tsignals: props.signals ?? opText.signals,\n\t\t\t\t\t\tfirstMargin:\n\t\t\t\t\t\t\topText.firstMargin != null\n\t\t\t\t\t\t\t\t? Number(opText.firstMargin)\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\tlastMargin:\n\t\t\t\t\t\t\topText.lastMargin != null ? Number(opText.lastMargin) : undefined,\n\t\t\t\t\t\tbaselineShift:\n\t\t\t\t\t\t\topText.baselineShift != null\n\t\t\t\t\t\t\t\t? Number(opText.baselineShift)\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\tframe: localFrame,\n\t\t\t\t\t\tfps,\n\t\t\t\t\t\tdurationMs: resolvedDurationMs,\n\t\t\t\t\t\telapsedMs: resolvedElapsedMs,\n\t\t\t\t\t\tisVideoMode: props.isVideoMode,\n\t\t\t\t\t});\n\t\t\t\t} else if (mediaType === \"Video\") {\n\t\t\t\t\tconst finalPlaybackRate = Math.max(\n\t\t\t\t\t\t0.01,\n\t\t\t\t\t\t(Number(props.playbackRateOverride) || 1) *\n\t\t\t\t\t\t\t(Number(params.speed) || 1),\n\t\t\t\t\t);\n\t\t\t\t\tconst effectiveTrimSec = Math.max(\n\t\t\t\t\t\t0,\n\t\t\t\t\t\t(Number(props.trimStartOverride) || 0) +\n\t\t\t\t\t\t\t(Number(params.trimStartSec) || 0) +\n\t\t\t\t\t\t\taccumulatedSeekOffsetSec,\n\t\t\t\t\t);\n\t\t\t\t\tconst rawTimestampSec =\n\t\t\t\t\t\t(segmentLocalFrame / fps) * finalPlaybackRate + effectiveTrimSec;\n\t\t\t\t\tconst timestampSec = Math.max(\n\t\t\t\t\t\t0,\n\t\t\t\t\t\tNumber.isFinite(rawTimestampSec) ? rawTimestampSec : 0,\n\t\t\t\t\t);\n\n\t\t\t\t\tawait drawVideoNode(ctx, pass, {\n\t\t\t\t\t\tnodeId: props.renderId,\n\t\t\t\t\t\tframeKey: `${props.renderId ?? \"video\"}-${params.sourceUrl}-${Math.round(timestampSec * fps)}`,\n\t\t\t\t\t\tsourceUrl: params.sourceUrl,\n\t\t\t\t\t\ttimestampSec,\n\t\t\t\t\t\tdstRect: {\n\t\t\t\t\t\t\tx: 0,\n\t\t\t\t\t\t\ty: 0,\n\t\t\t\t\t\t\twidth: containerWidth,\n\t\t\t\t\t\t\theight: containerHeight,\n\t\t\t\t\t\t},\n\t\t\t\t\t\topacity: Number(op.opacity ?? 1) * Number(props.opacity ?? 1),\n\t\t\t\t\t\tisHeadless: props.isHeadless,\n\t\t\t\t\t\tisPlaying: props.isPlaying,\n\t\t\t\t\t\tforceWait: props.forceWait,\n\t\t\t\t\t});\n\t\t\t\t} else if (mediaType === \"Caption\") {\n\t\t\t\t\tconst opCap = { ...op, ...props } as any;\n\t\t\t\t\tawait drawCaptionNode(ctx, pass, {\n\t\t\t\t\t\trenderId: props.renderId,\n\t\t\t\t\t\tsrc: params.sourceUrl,\n\t\t\t\t\t\tdstRect: {\n\t\t\t\t\t\t\tx: 0,\n\t\t\t\t\t\t\ty: 0,\n\t\t\t\t\t\t\twidth: containerWidth,\n\t\t\t\t\t\t\theight: containerHeight,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tframe: localFrame,\n\t\t\t\t\t\tfps,\n\t\t\t\t\t\tfontFamily: opCap.fontFamily,\n\t\t\t\t\t\tfontSize: Number(opCap.fontSize ?? 48),\n\t\t\t\t\t\tcolor: opCap.fill ?? opCap.color ?? \"white\",\n\t\t\t\t\t\tlineHeight: Number(opCap.lineHeight ?? 1.2),\n\t\t\t\t\t\talign:\n\t\t\t\t\t\t\topCap.align === \"start\"\n\t\t\t\t\t\t\t\t? \"left\"\n\t\t\t\t\t\t\t\t: opCap.align === \"end\"\n\t\t\t\t\t\t\t\t\t? \"right\"\n\t\t\t\t\t\t\t\t\t: (opCap.align ?? \"center\"),\n\t\t\t\t\t\ttextAlignVertical: opCap.verticalAlign ?? opCap.textAlignVertical,\n\t\t\t\t\t\tfontWeight: opCap.fontWeight,\n\t\t\t\t\t\tfontStyle: opCap.fontStyle,\n\t\t\t\t\t\tletterSpacing: opCap.letterSpacing,\n\t\t\t\t\t\tshadows: opCap.shadows,\n\t\t\t\t\t\ttextBackgroundColor: opCap.background ?? opCap.textBackgroundColor,\n\t\t\t\t\t\tborderRadius:\n\t\t\t\t\t\t\t(opCap.borderRadius ?? opCap.strokeRadius) != null\n\t\t\t\t\t\t\t\t? Number(opCap.borderRadius ?? opCap.strokeRadius)\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\tstrokeRadius:\n\t\t\t\t\t\t\t(opCap.strokeRadius ?? opCap.borderRadius) != null\n\t\t\t\t\t\t\t\t? Number(opCap.strokeRadius ?? opCap.borderRadius)\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\tstroke: opCap.stroke,\n\t\t\t\t\t\tstrokeWidth:\n\t\t\t\t\t\t\t(opCap.strokeWidth ?? opCap.strokeThickness) != null\n\t\t\t\t\t\t\t\t? Number(opCap.strokeWidth ?? opCap.strokeThickness)\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\tmaxWidth: opCap.maxWidth,\n\t\t\t\t\t\tpadding: opCap.padding != null ? Number(opCap.padding) : undefined,\n\t\t\t\t\t\topacity: Number(opCap.opacity ?? 1) * Number(props.opacity ?? 1),\n\t\t\t\t\t\tisHeadless: props.isHeadless,\n\t\t\t\t\t\tisVideoMode: props.isVideoMode,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (op.op === \"text\") {\n\t\t\tconst opText = { ...op } as any;\n\t\t\tconst containerWidth = props.containerWidth ?? ctx.surface.width;\n\t\t\tconst containerHeight = props.containerHeight ?? ctx.surface.height;\n\t\t\tdrawParagraphNode(ctx, pass, {\n\t\t\t\trenderId: props.renderId,\n\t\t\t\ttext: opText.text || \"\",\n\t\t\t\tdstRect: {\n\t\t\t\t\tx: Number(opText.x ?? 0),\n\t\t\t\t\ty: Number(opText.y ?? 0),\n\t\t\t\t\twidth: Number(opText.width ?? containerWidth),\n\t\t\t\t\theight: Number(opText.height ?? containerHeight),\n\t\t\t\t},\n\t\t\t\tspans: opText.spans,\n\t\t\t\tfontFamily: opText.fontFamily,\n\t\t\t\tfontSize: Number(opText.fontSize ?? 48),\n\t\t\t\tcolor: opText.fill ?? opText.color ?? \"white\",\n\t\t\t\twidth: opText.width ? Number(opText.width) : undefined,\n\t\t\t\theight: opText.height ? Number(opText.height) : undefined,\n\t\t\t\tlineHeight: Number(opText.lineHeight ?? 1.2),\n\t\t\t\talign: opText.align,\n\t\t\t\tverticalAlign: opText.verticalAlign,\n\t\t\t\tfontWeight: opText.fontWeight,\n\t\t\t\tfontStyle: opText.fontStyle,\n\t\t\t\tletterSpacing: opText.letterSpacing,\n\t\t\t\tshadows: opText.shadows,\n\t\t\t\ttextBackgroundColor: opText.textBackgroundColor,\n\t\t\t\tborderRadius:\n\t\t\t\t\t(opText.borderRadius ?? opText.strokeRadius) != null\n\t\t\t\t\t\t? Number(opText.borderRadius ?? opText.strokeRadius)\n\t\t\t\t\t\t: undefined,\n\t\t\t\tstrokeRadius:\n\t\t\t\t\t(opText.strokeRadius ?? opText.borderRadius) != null\n\t\t\t\t\t\t? Number(opText.strokeRadius ?? opText.borderRadius)\n\t\t\t\t\t\t: undefined,\n\t\t\t\tpadding: opText.padding != null ? Number(opText.padding) : undefined,\n\t\t\t\tstroke: opText.stroke,\n\t\t\t\tstrokeWidth:\n\t\t\t\t\t(opText.strokeWidth ?? opText.strokeThickness)\n\t\t\t\t\t\t? Number(opText.strokeWidth ?? opText.strokeThickness)\n\t\t\t\t\t\t: undefined,\n\t\t\t\tstrokeAlign: opText.strokeAlign,\n\t\t\t\topacity: Number(opText.opacity ?? 1) * Number(props.opacity ?? 1),\n\t\t\t\tisHeadless: props.isHeadless,\n\t\t\t\tanimation: opText.animation ?? opText.textAnimation,\n\t\t\t\tanimators: opText.animators,\n\t\t\t\tpathOptions: opText.pathOptions,\n\t\t\t\ttypewriter: opText.typewriter,\n\t\t\t\tmarquee: opText.marquee,\n\t\t\t\tsignals: props.signals ?? opText.signals,\n\t\t\t\tfirstMargin:\n\t\t\t\t\topText.firstMargin != null ? Number(opText.firstMargin) : undefined,\n\t\t\t\tlastMargin:\n\t\t\t\t\topText.lastMargin != null ? Number(opText.lastMargin) : undefined,\n\t\t\t\tbaselineShift:\n\t\t\t\t\topText.baselineShift != null\n\t\t\t\t\t\t? Number(opText.baselineShift)\n\t\t\t\t\t\t: undefined,\n\t\t\t\tframe: localFrame,\n\t\t\t\tfps,\n\t\t\t\tdurationMs: resolvedDurationMs,\n\t\t\t\telapsedMs: resolvedElapsedMs,\n\t\t\t\tisVideoMode: props.isVideoMode,\n\t\t\t});\n\t\t}\n\n\t\tpass.end();\n\t}\n\n\tif (virtualMedia.children && virtualMedia.children.length > 0) {\n\t\tfor (let i = 0; i < virtualMedia.children.length; i++) {\n\t\t\tconst child = virtualMedia.children[i];\n\t\t\tif (child) {\n\t\t\t\tawait drawCompositionTree(\n\t\t\t\t\tctx,\n\t\t\t\t\tencoder,\n\t\t\t\t\ttargetView,\n\t\t\t\t\ttargetTexture,\n\t\t\t\t\ttargetWidth,\n\t\t\t\t\ttargetHeight,\n\t\t\t\t\tchild,\n\t\t\t\t\t{\n\t\t\t\t\t\t...props,\n\t\t\t\t\t\tdurationMs: resolvedDurationMs,\n\t\t\t\t\t\telapsedMs: resolvedElapsedMs,\n\t\t\t\t\t\tvirtualMedia: child,\n\t\t\t\t\t\trenderId: `${props.renderId}-c${i}`,\n\t\t\t\t\t},\n\t\t\t\t\tisCompositor ? 0 : accumulatedSeekOffsetSec,\n\t\t\t\t\taccumulatedClockOffsetSec,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { VirtualMediaData } from \"@framefields/core\";\n\nconst DEFAULT_STATE = { frame: 0, fps: 30, isPlaying: false };\n\nclass CompositionStateStore {\n\tprivate states = new Map<\n\t\tstring,\n\t\t{ frame: number; fps: number; isPlaying: boolean }\n\t>();\n\tprivate listeners = new Map<string, Set<() => void>>();\n\n\tsetState(key: string, frame: number, fps: number, isPlaying?: boolean) {\n\t\tconst current = this.states.get(key);\n\t\tconst resolvedPlaying =\n\t\t\tisPlaying !== undefined ? isPlaying : (current?.isPlaying ?? false);\n\t\tif (\n\t\t\tcurrent?.frame === frame &&\n\t\t\tcurrent?.fps === fps &&\n\t\t\tcurrent?.isPlaying === resolvedPlaying\n\t\t)\n\t\t\treturn;\n\t\tthis.states.set(key, { frame, fps, isPlaying: resolvedPlaying });\n\t\tthis.notify(key);\n\t}\n\n\tgetState(key: string) {\n\t\tif (this.states.has(key)) return this.states.get(key)!;\n\t\tfor (const [storeKey, value] of this.states.entries()) {\n\t\t\tif (key.startsWith(storeKey)) return value;\n\t\t}\n\t\treturn DEFAULT_STATE;\n\t}\n\n\tsubscribe(key: string, listener: () => void) {\n\t\tif (!this.listeners.has(key)) this.listeners.set(key, new Set());\n\t\tthis.listeners.get(key)!.add(listener);\n\t\treturn () => {\n\t\t\tconst set = this.listeners.get(key);\n\t\t\tset?.delete(listener);\n\t\t\tif (set?.size === 0) {\n\t\t\t\tthis.listeners.delete(key);\n\t\t\t\tthis.states.delete(key);\n\t\t\t}\n\t\t};\n\t}\n\n\tclearKey(key: string) {\n\t\tthis.states.delete(key);\n\t}\n\n\tprivate notify(key: string) {\n\t\tfor (const [listenerKey, set] of this.listeners.entries()) {\n\t\t\tif (listenerKey === key || listenerKey.startsWith(key)) {\n\t\t\t\tset.forEach((l) => l());\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport const compositionStateStore = new CompositionStateStore();\n\nexport interface SceneProps {\n\tviewportWidth: number;\n\tviewportHeight: number;\n\tcontainerWidth?: number;\n\tcontainerHeight?: number;\n\tvirtualMedia?: VirtualMediaData;\n\tbackgroundColor?: string;\n\ttype?: \"Video\" | \"Audio\" | \"Image\";\n\tvolume?: number;\n\trenderId?: string;\n\tframe?: number;\n\tfps?: number;\n\t[key: string]: unknown;\n}\n","import {\n\tgetActiveMediaMetadata,\n\ttype VirtualMediaData,\n} from \"@framefields/core\";\nimport { secondsToFrames } from \"./timing.js\";\n\n/**\n * NormalizationContext carries the accumulated offsets and limits\n * as we traverse down the virtual media tree.\n */\ninterface NormalizationContext {\n\ttimeOffsetSec: number;\n\tdurationLimitMs?: number;\n}\n\n/**\n * normalizeTimeline recurses through the virtual media tree and \"absorbs\"\n * generic timeline-shifting operations into standard properties\n * of their children.\n */\nexport function normalizeTimeline(\n\tvv: VirtualMediaData,\n\tfps: number,\n\tcontext: NormalizationContext = { timeOffsetSec: 0 },\n): VirtualMediaData {\n\tif (!vv) return vv;\n\tconst { operation, metadata = {}, children = [] } = vv;\n\tconst { timeOffsetSec, durationLimitMs } = context;\n\n\tif (!operation) {\n\t\treturn {\n\t\t\t...vv,\n\t\t\tchildren: (children || []).map((child) =>\n\t\t\t\tnormalizeTimeline(child, fps, context),\n\t\t\t),\n\t\t};\n\t}\n\n\tconst timeline = operation.timeline;\n\tconst segments = timeline?.segments || [];\n\n\t// 1. Calculate Total Duration based on segments\n\tlet totalDurationMs = getActiveMediaMetadata(vv)?.durationMs ?? 0;\n\tif (segments.length > 0) {\n\t\tconst totalSegmentsFrames = segments.reduce(\n\t\t\t(acc: number, seg: { startSec: number; endSec?: number }) => {\n\t\t\t\tconst durSec = seg.endSec != null ? seg.endSec - seg.startSec : 0;\n\t\t\t\tconst durFrames = Math.max(1, Math.round(durSec * fps));\n\t\t\t\treturn acc + durFrames;\n\t\t\t},\n\t\t\t0,\n\t\t);\n\t\tif (totalSegmentsFrames > 0) {\n\t\t\ttotalDurationMs = (totalSegmentsFrames / fps) * 1000;\n\t\t}\n\t}\n\n\t// 2. Prepare Coordinate System (Shifted startFrame)\n\tconst newOperation = { ...operation };\n\tconst rawStartFrame = timeline?.startFrame ?? newOperation.startFrame;\n\n\tif (typeof rawStartFrame === \"number\") {\n\t\tconst offsetFrames = secondsToFrames(timeOffsetSec, fps);\n\t\tnewOperation.startFrame = rawStartFrame - offsetFrames;\n\t}\n\n\t// 3. Metadata Standardization\n\tconst newMetadata = {\n\t\t...metadata,\n\t\tdurationMs: totalDurationMs,\n\t};\n\n\t// 4. Recurse into children\n\t// A node resets the coordinate system for its children if it has a startFrame or is a compose op.\n\tconst isTimelineProvider =\n\t\ttypeof rawStartFrame === \"number\" || newOperation.op === \"compose\";\n\n\tconst childContext: NormalizationContext = isTimelineProvider\n\t\t? { timeOffsetSec: 0, durationLimitMs: undefined }\n\t\t: { timeOffsetSec: timeOffsetSec, durationLimitMs: durationLimitMs };\n\n\tconst newChildren = (children || []).map((child) =>\n\t\tnormalizeTimeline(child, fps, childContext),\n\t);\n\n\treturn {\n\t\tmetadata: newMetadata,\n\t\toperation: newOperation,\n\t\tchildren: newChildren,\n\t};\n}\n","import {\n\tgetActiveMediaMetadata,\n\tgetMediaType,\n\ttype VirtualMediaData,\n} from \"@framefields/core\";\nimport { type AudioProcessor, audioRegistry } from \"@framefields/node-sdk\";\nimport { inputStore, shaderStore } from \"@framefields/webgpu-renderers\";\nimport { AudioSampleSink } from \"mediabunny\";\nimport { computeRenderParams } from \"./apply-operations.js\";\nimport { normalizeTimeline } from \"./normalization.js\";\n\n// Progress chatter (every decode step) is debug output: shown only with LOG_LEVEL=debug or trace.\nconst verbose =\n\ttypeof process !== \"undefined\" &&\n\t/^(debug|trace)$/i.test(process.env?.LOG_LEVEL ?? \"\");\n\n// Fallback logger for browser environment. In Node.js environment, we dynamically load @framefields/server-utils to avoid bundling it on the frontend.\nlet mediaLogger = {\n\tdebug: (msg: unknown, ...args: unknown[]) => {\n\t\tif (!verbose) return;\n\t\tif (typeof msg === \"object\" && msg !== null) {\n\t\t\tconsole.info(\"[AudioExtractor]\", msg, ...args);\n\t\t} else {\n\t\t\tconsole.info(`[AudioExtractor] ${msg}`, ...args);\n\t\t}\n\t},\n\twarn: (msg: unknown, ...args: unknown[]) => {\n\t\tif (typeof msg === \"object\" && msg !== null) {\n\t\t\tconsole.warn(\"[AudioExtractor]\", msg, ...args);\n\t\t} else {\n\t\t\tconsole.warn(`[AudioExtractor] ${msg}`, ...args);\n\t\t}\n\t},\n\terror: (msg: unknown, ...args: unknown[]) => {\n\t\tif (typeof msg === \"object\" && msg !== null) {\n\t\t\tconsole.error(\"[AudioExtractor]\", msg, ...args);\n\t\t} else {\n\t\t\tconsole.error(`[AudioExtractor] ${msg}`, ...args);\n\t\t}\n\t},\n};\n\nif (\n\ttypeof window === \"undefined\" ||\n\t(typeof process !== \"undefined\" && process.versions?.node)\n) {\n\timport(\n\t\t/* webpackIgnore: true */ /* @vite-ignore */ \"@framefields/server-utils\"\n\t)\n\t\t.then((m) => {\n\t\t\tif (m.mediaLogger) {\n\t\t\t\tmediaLogger = m.mediaLogger;\n\t\t\t}\n\t\t})\n\t\t.catch(() => {});\n}\n\nconst yieldToMain = (): Promise<void> => {\n\tif (typeof window === \"undefined\") {\n\t\treturn Promise.resolve();\n\t}\n\tconst sched = (globalThis as Record<string, unknown>).scheduler as\n\t\t| { yield?: () => Promise<void> }\n\t\t| undefined;\n\treturn typeof sched?.yield === \"function\"\n\t\t? sched.yield()\n\t\t: new Promise<void>((resolve) => setTimeout(resolve, 0));\n};\n\nconst waitForDelayRender = async (timeoutMs = 30_000): Promise<void> => {\n\tawait new Promise((resolve) => setTimeout(resolve, 100));\n\n\tconst start = Date.now();\n\treturn new Promise<void>((resolve) => {\n\t\tconst check = () => {\n\t\t\tconst browserHandles: unknown[] =\n\t\t\t\ttypeof window !== \"undefined\" &&\n\t\t\t\t(window as unknown as { renderer_delayRenderHandles?: unknown[] })\n\t\t\t\t\t.renderer_delayRenderHandles\n\t\t\t\t\t? (\n\t\t\t\t\t\t\twindow as unknown as {\n\t\t\t\t\t\t\t\trenderer_delayRenderHandles: unknown[];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t).renderer_delayRenderHandles\n\t\t\t\t\t: [];\n\n\t\t\tconst globalDelays =\n\t\t\t\ttypeof globalThis !== \"undefined\"\n\t\t\t\t\t? (globalThis as any).__GATEWAI_DELAYS__\n\t\t\t\t\t: null;\n\n\t\t\tconst hasBrowserDelays = browserHandles.length > 0;\n\t\t\tconst hasGlobalDelays =\n\t\t\t\tglobalDelays instanceof Set && globalDelays.size > 0;\n\n\t\t\tif (!hasBrowserDelays && !hasGlobalDelays) {\n\t\t\t\tresolve();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (Date.now() - start > timeoutMs) {\n\t\t\t\tmediaLogger.warn(\n\t\t\t\t\t`[AudioExtractor] waitForDelayRender timed out waiting for handles: ${JSON.stringify(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbrowserHandles,\n\t\t\t\t\t\t\tglobalDelays: globalDelays ? Array.from(globalDelays) : [],\n\t\t\t\t\t\t},\n\t\t\t\t\t)}`,\n\t\t\t\t);\n\t\t\t\tresolve();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsetTimeout(check, 50);\n\t\t};\n\t\tcheck();\n\t});\n};\n\nexport interface AudioClip {\n\tsourceUrl: string;\n\tdestStartFrame: number;\n\ttrimStartSec: number;\n\tdurationFrames: number;\n\tspeed: number;\n\tvolume: number;\n}\n\n/**\n * Decodes all audio samples from a given source URL into raw Float32 mono/stereo channel buffers.\n */\nexport async function decodeAudioSource(\n\turl: string,\n): Promise<{ channels: Float32Array[]; sampleRate: number } | null> {\n\tmediaLogger.debug(\n\t\t`[AudioExtractor] decodeAudioSource started for url: ${url}`,\n\t);\n\ttry {\n\t\tconst isBrowser =\n\t\t\ttypeof window !== \"undefined\" &&\n\t\t\ttypeof window.document !== \"undefined\" &&\n\t\t\t!(\n\t\t\t\ttypeof process !== \"undefined\" &&\n\t\t\t\tprocess.versions &&\n\t\t\t\tprocess.versions.node\n\t\t\t);\n\t\tif (isBrowser) {\n\t\t\tmediaLogger.debug(\n\t\t\t\t`[AudioExtractor] Browser detected. Fetching arrayBuffer for ${url}...`,\n\t\t\t);\n\t\t\tconst AudioContextClass =\n\t\t\t\twindow.AudioContext || (window as any).webkitAudioContext;\n\t\t\tif (!AudioContextClass) {\n\t\t\t\tthrow new Error(\"AudioContext is not supported in this browser\");\n\t\t\t}\n\t\t\tconst audioCtx = new AudioContextClass();\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(url);\n\t\t\t\tmediaLogger.debug(\n\t\t\t\t\t`[AudioExtractor] Fetch response status for ${url}: ${response.status} (${response.statusText})`,\n\t\t\t\t);\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Failed to fetch audio source: ${response.statusText}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst arrayBuffer = await response.arrayBuffer();\n\t\t\t\tmediaLogger.debug(\n\t\t\t\t\t`[AudioExtractor] Fetched ${arrayBuffer.byteLength} bytes. Decoding audio data...`,\n\t\t\t\t);\n\t\t\t\tconst audioBuffer = await audioCtx.decodeAudioData(arrayBuffer);\n\t\t\t\tmediaLogger.debug(\n\t\t\t\t\t`[AudioExtractor] Decoded successfully: ${audioBuffer.numberOfChannels} channels, sampleRate: ${audioBuffer.sampleRate}, duration: ${audioBuffer.duration}s`,\n\t\t\t\t);\n\n\t\t\t\tconst channels: Float32Array[] = [];\n\t\t\t\tfor (let c = 0; c < audioBuffer.numberOfChannels; c++) {\n\t\t\t\t\tchannels.push(new Float32Array(audioBuffer.getChannelData(c)));\n\t\t\t\t}\n\t\t\t\treturn { channels, sampleRate: audioBuffer.sampleRate };\n\t\t\t} finally {\n\t\t\t\tvoid audioCtx.close();\n\t\t\t\tmediaLogger.debug(`[AudioExtractor] AudioContext closed for ${url}`);\n\t\t\t}\n\t\t}\n\n\t\tlet inputAcquired = false;\n\t\ttry {\n\t\t\tmediaLogger.debug(\n\t\t\t\t`[AudioExtractor] Server / Node.js detected. Acquiring from inputStore for ${url}...`,\n\t\t\t);\n\t\t\tconst input = await inputStore.acquire(url);\n\t\t\tinputAcquired = true;\n\t\t\tmediaLogger.debug(\n\t\t\t\t`[AudioExtractor] inputStore acquired. Retrieving primary audio track...`,\n\t\t\t);\n\t\t\tconst track = await input.getPrimaryAudioTrack();\n\t\t\tif (!track) {\n\t\t\t\tmediaLogger.warn(\n\t\t\t\t\t`[AudioExtractor] No primary audio track found in input for ${url}`,\n\t\t\t\t);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst sink = new AudioSampleSink(track);\n\t\t\tconst generator = sink.samples(0);\n\n\t\t\tconst decodedPlanes: Float32Array[][] = [];\n\t\t\tlet totalFrames = 0;\n\t\t\tlet sampleRate = 48000;\n\t\t\tlet numChannels = 1;\n\n\t\t\tmediaLogger.debug(\n\t\t\t\t`[AudioExtractor] Starting mediabunny generator loop for ${url}...`,\n\t\t\t);\n\t\t\tfor await (const sample of generator) {\n\t\t\t\tsampleRate = sample.sampleRate;\n\t\t\t\tnumChannels = sample.numberOfChannels;\n\t\t\t\tconst sampleFrames = sample.numberOfFrames;\n\n\t\t\t\tif (decodedPlanes.length === 0) {\n\t\t\t\t\tfor (let c = 0; c < numChannels; c++) {\n\t\t\t\t\t\tdecodedPlanes.push([]);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (let c = 0; c < numChannels; c++) {\n\t\t\t\t\tlet planeBuffer: Float32Array;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst allocSize = sample.allocationSize({\n\t\t\t\t\t\t\tplaneIndex: c,\n\t\t\t\t\t\t\tformat: \"f32-planar\",\n\t\t\t\t\t\t});\n\t\t\t\t\t\tplaneBuffer = new Float32Array(allocSize / 4);\n\t\t\t\t\t\tsample.copyTo(planeBuffer, {\n\t\t\t\t\t\t\tplaneIndex: c,\n\t\t\t\t\t\t\tformat: \"f32-planar\",\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Fallback: copy in sample's native format and normalize to float32 [-1, 1]\n\t\t\t\t\t\tconst allocSize = sample.allocationSize({ planeIndex: c });\n\t\t\t\t\t\tif (sample.format === \"s16\" || sample.format === \"s16-planar\") {\n\t\t\t\t\t\t\tconst int16Buffer = new Int16Array(allocSize / 2);\n\t\t\t\t\t\t\tsample.copyTo(int16Buffer, { planeIndex: c });\n\t\t\t\t\t\t\tplaneBuffer = new Float32Array(int16Buffer.length);\n\t\t\t\t\t\t\tfor (let i = 0; i < int16Buffer.length; i++) {\n\t\t\t\t\t\t\t\tplaneBuffer[i] = (int16Buffer[i] ?? 0) / 32768;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\tsample.format === \"s32\" ||\n\t\t\t\t\t\t\tsample.format === \"s32-planar\"\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tconst int32Buffer = new Int32Array(allocSize / 4);\n\t\t\t\t\t\t\tsample.copyTo(int32Buffer, { planeIndex: c });\n\t\t\t\t\t\t\tplaneBuffer = new Float32Array(int32Buffer.length);\n\t\t\t\t\t\t\tfor (let i = 0; i < int32Buffer.length; i++) {\n\t\t\t\t\t\t\t\tplaneBuffer[i] = (int32Buffer[i] ?? 0) / 2147483648;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\tsample.format === \"u8\" ||\n\t\t\t\t\t\t\tsample.format === \"u8-planar\"\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tconst u8Buffer = new Uint8Array(allocSize);\n\t\t\t\t\t\t\tsample.copyTo(u8Buffer, { planeIndex: c });\n\t\t\t\t\t\t\tplaneBuffer = new Float32Array(u8Buffer.length);\n\t\t\t\t\t\t\tfor (let i = 0; i < u8Buffer.length; i++) {\n\t\t\t\t\t\t\t\tplaneBuffer[i] = ((u8Buffer[i] ?? 128) - 128) / 128;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tplaneBuffer = new Float32Array(allocSize / 4);\n\t\t\t\t\t\t\tsample.copyTo(planeBuffer, { planeIndex: c });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdecodedPlanes[c].push(planeBuffer);\n\t\t\t\t}\n\n\t\t\t\ttotalFrames += sampleFrames;\n\t\t\t\tsample.close();\n\t\t\t}\n\t\t\tmediaLogger.debug(\n\t\t\t\t`[AudioExtractor] Generator loop finished. Decoded total frames: ${totalFrames}`,\n\t\t\t);\n\n\t\t\tif (totalFrames === 0 || decodedPlanes.length === 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst channels = decodedPlanes.map((planes) => {\n\t\t\t\tconst merged = new Float32Array(totalFrames);\n\t\t\t\tlet offset = 0;\n\t\t\t\tfor (const plane of planes) {\n\t\t\t\t\tmerged.set(plane, offset);\n\t\t\t\t\toffset += plane.length;\n\t\t\t\t}\n\t\t\t\treturn merged;\n\t\t\t});\n\n\t\t\treturn { channels, sampleRate };\n\t\t} catch (err) {\n\t\t\tif (typeof process !== \"undefined\" && process.versions?.node) {\n\t\t\t\ttry {\n\t\t\t\t\tconst { execSync } = await import(\"node:child_process\");\n\t\t\t\t\tconst stdout = execSync(\n\t\t\t\t\t\t`ffmpeg -v error -i \"${url}\" -f f32le -ar 48000 -ac 2 pipe:1`,\n\t\t\t\t\t\t{ maxBuffer: 100 * 1024 * 1024 },\n\t\t\t\t\t);\n\t\t\t\t\tconst totalSamples = stdout.byteLength / 4;\n\t\t\t\t\tconst numFrames = totalSamples / 2;\n\t\t\t\t\tconst interleaved = new Float32Array(\n\t\t\t\t\t\tstdout.buffer,\n\t\t\t\t\t\tstdout.byteOffset,\n\t\t\t\t\t\ttotalSamples,\n\t\t\t\t\t);\n\t\t\t\t\tconst left = new Float32Array(numFrames);\n\t\t\t\t\tconst right = new Float32Array(numFrames);\n\t\t\t\t\tfor (let i = 0; i < numFrames; i++) {\n\t\t\t\t\t\tleft[i] = interleaved[i * 2];\n\t\t\t\t\t\tright[i] = interleaved[i * 2 + 1];\n\t\t\t\t\t}\n\t\t\t\t\treturn { channels: [left, right], sampleRate: 48000 };\n\t\t\t\t} catch (ffmpegErr) {\n\t\t\t\t\tmediaLogger.warn(\n\t\t\t\t\t\t{ ffmpegErr },\n\t\t\t\t\t\t`[AudioExtractor] ffmpeg fallback decode failed for ${url}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tmediaLogger.error(\n\t\t\t\t{ err },\n\t\t\t\t`[AudioExtractor] Failed to decode source ${url}`,\n\t\t\t);\n\t\t\treturn null;\n\t\t} finally {\n\t\t\tif (inputAcquired) {\n\t\t\t\tinputStore.release(url);\n\t\t\t}\n\t\t}\n\t} catch (err) {\n\t\tmediaLogger.error(\n\t\t\t{ err },\n\t\t\t`[AudioExtractor] Failed to decode source ${url}`,\n\t\t);\n\t\treturn null;\n\t}\n}\n\n/**\n * Resamples a PCM buffer using linear interpolation to target sample rate & speed.\n */\nasync function resampleAndStretchPCM(\n\tinputChannel: Float32Array,\n\tsourceSampleRate: number,\n\ttargetSampleRate: number,\n\tspeed: number,\n\toutputLength: number,\n\ttrimOffsetSamples: number,\n): Promise<Float32Array> {\n\tconst output = new Float32Array(outputLength);\n\tconst resampleRatio = sourceSampleRate / targetSampleRate;\n\tconst factor = resampleRatio * speed;\n\n\tconst YIELD_INTERVAL = 100_000;\n\n\tfor (let i = 0; i < outputLength; i++) {\n\t\tif (i > 0 && i % YIELD_INTERVAL === 0) {\n\t\t\tawait yieldToMain();\n\t\t}\n\t\tconst srcIndex = trimOffsetSamples + i * factor;\n\t\tconst indexFloor = Math.floor(srcIndex);\n\t\tconst indexCeil = Math.ceil(srcIndex);\n\n\t\tif (indexFloor < 0) {\n\t\t\toutput[i] = 0;\n\t\t\tcontinue;\n\t\t}\n\t\tif (indexFloor >= inputChannel.length) {\n\t\t\tbreak; // Out of bounds of source media\n\t\t}\n\n\t\tconst weight = srcIndex - indexFloor;\n\t\tconst sampleFloor = inputChannel[indexFloor] ?? 0;\n\t\tconst sampleCeil =\n\t\t\tindexCeil >= 0 && indexCeil < inputChannel.length\n\t\t\t\t? (inputChannel[indexCeil] ?? sampleFloor)\n\t\t\t\t: sampleFloor;\n\n\t\tconst val = sampleFloor + weight * (sampleCeil - sampleFloor);\n\t\toutput[i] = Number.isFinite(val) ? val : 0;\n\t}\n\n\treturn output;\n}\n\n/**\n * Recursively parses the VirtualMediaData tree and mixes all active audio tracks\n * into a single unified stereo PCM stream (Float32Array channels).\n */\nexport async function mixAudioTracks(\n\tvirtualMedia: VirtualMediaData,\n\tfps: number,\n\ttargetSampleRate = 48000,\n\tdevice?: GPUDevice,\n\trenderId?: string,\n): Promise<{ channels: Float32Array[]; sampleRate: number }> {\n\tmediaLogger.debug(\n\t\t`[AudioExtractor] mixAudioTracks started. FPS: ${fps}, targetSampleRate: ${targetSampleRate}`,\n\t);\n\tawait waitForDelayRender();\n\n\t// Register all signals from the composition tree\n\tshaderStore.registerSignalsFromComposition(renderId, virtualMedia);\n\n\tconst durationMs = getActiveMediaMetadata(virtualMedia)?.durationMs || 1000;\n\tconst totalDurationSec = durationMs / 1000;\n\tconst totalTargetSamples = Math.ceil(totalDurationSec * targetSampleRate);\n\tmediaLogger.debug(\n\t\t`[AudioExtractor] Composition total duration: ${durationMs}ms (${totalDurationSec}s). Total mixed samples to allocate: ${totalTargetSamples}`,\n\t);\n\n\t// Output mixed buffer is stereo\n\tconst outputLeft = new Float32Array(totalTargetSamples);\n\tconst outputRight = new Float32Array(totalTargetSamples);\n\tconst mixedChannels = [outputLeft, outputRight];\n\n\t// Map to cache decoded sources so we don't decode multiple clips of the same file twice\n\tconst decodedCache = new Map<\n\t\tstring,\n\t\t{ channels: Float32Array[]; sampleRate: number } | null\n\t>();\n\n\tasync function traverse(\n\t\tnode: VirtualMediaData,\n\t\tinheritedSeekSec: number,\n\t\tinheritedClockFrames: number,\n\t\tinheritedVolume: number,\n\t\tinheritedSpeed: number,\n\t\tinheritedDurationFrames: number | null,\n\t): Promise<Float32Array[] | null> {\n\t\tif (!node) return null;\n\t\tconst op = node.operation;\n\t\tif (!op) {\n\t\t\tconst durationMs = getActiveMediaMetadata(node)?.durationMs ?? 0;\n\t\t\tconst durationFrames = Math.round((durationMs / 1000) * fps);\n\t\t\tconst actualDurationFrames =\n\t\t\t\tinheritedDurationFrames !== null\n\t\t\t\t\t? durationFrames > 0\n\t\t\t\t\t\t? Math.min(inheritedDurationFrames, durationFrames)\n\t\t\t\t\t\t: inheritedDurationFrames\n\t\t\t\t\t: durationFrames;\n\n\t\t\tconst localSamplesCount = Math.ceil(\n\t\t\t\t(actualDurationFrames / fps) * targetSampleRate,\n\t\t\t);\n\t\t\tif (localSamplesCount <= 0) return null;\n\n\t\t\tconst localLeft = new Float32Array(localSamplesCount);\n\t\t\tconst localRight = new Float32Array(localSamplesCount);\n\t\t\tconst localChannels = [localLeft, localRight];\n\n\t\t\tfor (const child of node.children) {\n\t\t\t\tconst childChannels = await traverse(\n\t\t\t\t\tchild,\n\t\t\t\t\tinheritedSeekSec,\n\t\t\t\t\tinheritedClockFrames,\n\t\t\t\t\tinheritedVolume,\n\t\t\t\t\tinheritedSpeed,\n\t\t\t\t\tactualDurationFrames,\n\t\t\t\t);\n\t\t\t\tif (childChannels) {\n\t\t\t\t\tconst childOp = child.operation;\n\t\t\t\t\tconst childStartFrame =\n\t\t\t\t\t\tchildOp?.startFrame ?? childOp?.timeline?.startFrame ?? 0;\n\t\t\t\t\tconst childStartSample = Math.round(\n\t\t\t\t\t\t(childStartFrame / fps) * targetSampleRate,\n\t\t\t\t\t);\n\t\t\t\t\tfor (let c = 0; c < 2; c++) {\n\t\t\t\t\t\tconst dest = localChannels[c];\n\t\t\t\t\t\tconst src = childChannels[c];\n\t\t\t\t\t\tconst len = Math.min(src.length, dest.length - childStartSample);\n\t\t\t\t\t\tfor (let i = 0; i < len; i++) {\n\t\t\t\t\t\t\tif (childStartSample + i >= 0) {\n\t\t\t\t\t\t\t\tdest[childStartSample + i] += src[i];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn localChannels;\n\t\t}\n\n\t\tconst volume =\n\t\t\tinheritedVolume *\n\t\t\t(op.volume ?? 1) *\n\t\t\t(op.opacity === 0 ? 0 : 1) *\n\t\t\t((op as Record<string, unknown>).muted ? 0 : 1);\n\t\tconst speedMultiplier = inheritedSpeed;\n\n\t\tconst nodeStartFrame = op.startFrame ?? op.timeline?.startFrame ?? 0;\n\t\tconst localClockFrames = inheritedClockFrames + nodeStartFrame;\n\n\t\tconst segments = op.timeline?.segments || [];\n\n\t\tconst nodeDurationMs = getActiveMediaMetadata(node)?.durationMs ?? 0;\n\t\tconst nodeDurationFrames = Math.round((nodeDurationMs / 1000) * fps);\n\t\tconst nodeActualDurationFrames =\n\t\t\tinheritedDurationFrames !== null\n\t\t\t\t? nodeDurationFrames > 0\n\t\t\t\t\t? Math.min(inheritedDurationFrames, nodeDurationFrames)\n\t\t\t\t\t: inheritedDurationFrames\n\t\t\t\t: nodeDurationFrames;\n\t\tconst localSamplesCount = Math.ceil(\n\t\t\t(nodeActualDurationFrames / fps) * targetSampleRate,\n\t\t);\n\t\tif (localSamplesCount <= 0) return null;\n\n\t\tconst localLeft = new Float32Array(localSamplesCount);\n\t\tconst localRight = new Float32Array(localSamplesCount);\n\t\tconst localChannels = [localLeft, localRight];\n\n\t\tconst processSegment = async (\n\t\t\tseg: { startSec: number; endSec?: number } | null,\n\t\t\twindowStartFrameOffset: number,\n\t\t) => {\n\t\t\tconst segSeekSec = seg ? seg.startSec : 0;\n\t\t\tconst totalSeekSec = inheritedSeekSec + segSeekSec;\n\t\t\tconst totalClockFrames = localClockFrames + windowStartFrameOffset;\n\n\t\t\tlet segDurationFrames = 0;\n\t\t\tif (seg) {\n\t\t\t\tsegDurationFrames = Math.max(\n\t\t\t\t\t1,\n\t\t\t\t\tMath.round(((seg.endSec ?? 0) - seg.startSec) * fps),\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tsegDurationFrames = nodeDurationFrames;\n\t\t\t}\n\n\t\t\tconst actualDurationFrames =\n\t\t\t\tinheritedDurationFrames !== null\n\t\t\t\t\t? Math.min(inheritedDurationFrames, segDurationFrames)\n\t\t\t\t\t: segDurationFrames;\n\n\t\t\tconst segmentStartSample = Math.round(\n\t\t\t\t(windowStartFrameOffset / fps) * targetSampleRate,\n\t\t\t);\n\n\t\t\t// If we are on a source clip (audio/video file)\n\t\t\tif (op.op === \"source\") {\n\t\t\t\tconst mediaType = getMediaType(node);\n\t\t\t\tconst params = computeRenderParams(node);\n\t\t\t\tif (\n\t\t\t\t\tparams.sourceUrl &&\n\t\t\t\t\t(mediaType === \"Audio\" || mediaType === \"Video\") &&\n\t\t\t\t\tvolume > 0\n\t\t\t\t) {\n\t\t\t\t\tconst finalSpeed = Math.max(\n\t\t\t\t\t\t0.5,\n\t\t\t\t\t\tspeedMultiplier * (Number(params.speed) || 1),\n\t\t\t\t\t);\n\t\t\t\t\tconst effectiveTrimSec = Math.max(\n\t\t\t\t\t\t0,\n\t\t\t\t\t\t(Number(params.trimStartSec) || 0) + totalSeekSec,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Load and decode from cache or file\n\t\t\t\t\tlet decoded = decodedCache.get(params.sourceUrl);\n\t\t\t\t\tif (decoded === undefined) {\n\t\t\t\t\t\tdecoded = await decodeAudioSource(params.sourceUrl);\n\t\t\t\t\t\tdecodedCache.set(params.sourceUrl, decoded);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (decoded) {\n\t\t\t\t\t\tconst clipDurationSec = actualDurationFrames / fps;\n\t\t\t\t\t\tconst clipSamplesCount = Math.min(\n\t\t\t\t\t\t\tlocalSamplesCount - segmentStartSample,\n\t\t\t\t\t\t\tMath.ceil(clipDurationSec * targetSampleRate),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tclipSamplesCount > 0 &&\n\t\t\t\t\t\t\tsegmentStartSample < localSamplesCount\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tconst trimOffsetSamples = Math.round(\n\t\t\t\t\t\t\t\teffectiveTrimSec * decoded.sampleRate,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t// Resample left & right channels\n\t\t\t\t\t\t\tconst srcLeft = decoded.channels[0];\n\t\t\t\t\t\t\tconst srcRight =\n\t\t\t\t\t\t\t\tdecoded.channels.length > 1\n\t\t\t\t\t\t\t\t\t? decoded.channels[1]\n\t\t\t\t\t\t\t\t\t: decoded.channels[0]; // fallback to mono\n\n\t\t\t\t\t\t\tconst stretchedLeft = await resampleAndStretchPCM(\n\t\t\t\t\t\t\t\tsrcLeft,\n\t\t\t\t\t\t\t\tdecoded.sampleRate,\n\t\t\t\t\t\t\t\ttargetSampleRate,\n\t\t\t\t\t\t\t\tfinalSpeed,\n\t\t\t\t\t\t\t\tclipSamplesCount,\n\t\t\t\t\t\t\t\ttrimOffsetSamples,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tconst stretchedRight = await resampleAndStretchPCM(\n\t\t\t\t\t\t\t\tsrcRight,\n\t\t\t\t\t\t\t\tdecoded.sampleRate,\n\t\t\t\t\t\t\t\ttargetSampleRate,\n\t\t\t\t\t\t\t\tfinalSpeed,\n\t\t\t\t\t\t\t\tclipSamplesCount,\n\t\t\t\t\t\t\t\ttrimOffsetSamples,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t// Add to local mix with volume scaling\n\t\t\t\t\t\t\tfor (let i = 0; i < clipSamplesCount; i++) {\n\t\t\t\t\t\t\t\tconst outIndex = segmentStartSample + i;\n\t\t\t\t\t\t\t\tlocalLeft[outIndex] += stretchedLeft[i] * volume;\n\t\t\t\t\t\t\t\tlocalRight[outIndex] += stretchedRight[i] * volume;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tawait yieldToMain();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Traverse children recursively\n\t\t\tif (node.children) {\n\t\t\t\tfor (const child of node.children) {\n\t\t\t\t\tconst childChannels = await traverse(\n\t\t\t\t\t\tchild,\n\t\t\t\t\t\ttotalSeekSec,\n\t\t\t\t\t\ttotalClockFrames,\n\t\t\t\t\t\tvolume,\n\t\t\t\t\t\tspeedMultiplier,\n\t\t\t\t\t\tactualDurationFrames,\n\t\t\t\t\t);\n\t\t\t\t\tif (childChannels) {\n\t\t\t\t\t\tconst childOp = child.operation;\n\t\t\t\t\t\tconst childStartFrame =\n\t\t\t\t\t\t\tchildOp?.startFrame ?? childOp?.timeline?.startFrame ?? 0;\n\t\t\t\t\t\tconst childStartSample = Math.round(\n\t\t\t\t\t\t\t(childStartFrame / fps) * targetSampleRate,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst destStartSample = segmentStartSample + childStartSample;\n\t\t\t\t\t\tfor (let c = 0; c < 2; c++) {\n\t\t\t\t\t\t\tconst dest = localChannels[c];\n\t\t\t\t\t\t\tconst src = childChannels[c];\n\t\t\t\t\t\t\tconst len = Math.min(src.length, dest.length - destStartSample);\n\t\t\t\t\t\t\tfor (let i = 0; i < len; i++) {\n\t\t\t\t\t\t\t\tif (destStartSample + i >= 0) {\n\t\t\t\t\t\t\t\t\tdest[destStartSample + i] += src[i];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// -- Plugin Processing Hook --\n\t\t\tconst pluginProcessor = audioRegistry.get(op.op) as AudioProcessor | null;\n\t\t\tif (pluginProcessor) {\n\t\t\t\ttry {\n\t\t\t\t\tconst clipDurationSec = actualDurationFrames / fps;\n\t\t\t\t\tconst clipSamplesCount = Math.min(\n\t\t\t\t\t\tlocalSamplesCount - segmentStartSample,\n\t\t\t\t\t\tMath.ceil(clipDurationSec * targetSampleRate),\n\t\t\t\t\t);\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tclipSamplesCount > 0 &&\n\t\t\t\t\t\tsegmentStartSample < localSamplesCount &&\n\t\t\t\t\t\tsegmentStartSample >= 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst slicedChannels = localChannels.map((ch) =>\n\t\t\t\t\t\t\tch.subarray(\n\t\t\t\t\t\t\t\tsegmentStartSample,\n\t\t\t\t\t\t\t\tsegmentStartSample + clipSamplesCount,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst elapsedMs = (totalClockFrames / fps + totalSeekSec) * 1000;\n\t\t\t\t\t\tconst durationMs =\n\t\t\t\t\t\t\tgetActiveMediaMetadata(node)?.durationMs ?? undefined;\n\t\t\t\t\t\tawait pluginProcessor(slicedChannels, targetSampleRate, node, {\n\t\t\t\t\t\t\tdevice,\n\t\t\t\t\t\t\tframe: totalClockFrames,\n\t\t\t\t\t\t\tfps,\n\t\t\t\t\t\t\trenderId,\n\t\t\t\t\t\t\telapsedMs,\n\t\t\t\t\t\t\tdurationMs,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} catch (pluginErr) {\n\t\t\t\t\tmediaLogger.error(\n\t\t\t\t\t\t{ err: pluginErr },\n\t\t\t\t\t\t`[AudioExtractor] Custom plugin for operation '${op.op}' failed`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tif (segments.length > 0) {\n\t\t\tlet currentStart = 0;\n\t\t\tfor (const seg of segments) {\n\t\t\t\tconst durSec = (seg.endSec ?? 0) - seg.startSec;\n\t\t\t\tconst durFrames = Math.max(1, Math.round(durSec * fps));\n\t\t\t\tawait processSegment(seg, currentStart);\n\t\t\t\tcurrentStart += durFrames;\n\t\t\t}\n\t\t} else {\n\t\t\tawait processSegment(null, 0);\n\t\t}\n\n\t\treturn localChannels;\n\t}\n\n\tconst normalized = normalizeTimeline(virtualMedia, fps);\n\tconst rootChannels = await traverse(normalized, 0, 0, 1, 1, null);\n\tif (rootChannels) {\n\t\tfor (let c = 0; c < 2; c++) {\n\t\t\tconst dest = mixedChannels[c];\n\t\t\tconst src = rootChannels[c];\n\t\t\tconst len = Math.min(src.length, dest.length);\n\t\t\tfor (let i = 0; i < len; i++) {\n\t\t\t\tdest[i] = src[i];\n\t\t\t}\n\t\t}\n\t}\n\n\t// Clear decoder cache\n\tdecodedCache.clear();\n\n\t// Calculate master mix peak across all channels to prevent multi-track summation distortion\n\tlet mixPeak = 0;\n\tfor (let i = 0; i < totalTargetSamples; i++) {\n\t\tconst l = Math.abs(outputLeft[i] ?? 0);\n\t\tconst r = Math.abs(outputRight[i] ?? 0);\n\t\tif (l > mixPeak) mixPeak = l;\n\t\tif (r > mixPeak) mixPeak = r;\n\t}\n\n\t// Automatic gain ceiling: if multi-track summation exceeds -0.5 dB (0.95), scale smoothly\n\tconst autoGain = mixPeak > 0.95 ? 0.92 / mixPeak : 1.0;\n\n\t// Soft-knee limiting & non-finite float sanitation (transparent saturation instead of harsh square-wave clipping)\n\tfor (let i = 0; i < totalTargetSamples; i++) {\n\t\tconst l = (outputLeft[i] ?? 0) * autoGain;\n\t\tconst r = (outputRight[i] ?? 0) * autoGain;\n\t\toutputLeft[i] = Number.isFinite(l) ? Math.tanh(l) : 0;\n\t\toutputRight[i] = Number.isFinite(r) ? Math.tanh(r) : 0;\n\t}\n\n\treturn {\n\t\tchannels: mixedChannels,\n\t\tsampleRate: targetSampleRate,\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { DEFAULT_DURATION_MS, getActiveMediaMetadata, resolveMediaMimeType } from "@framefields/core";
|
|
2
|
+
import { getEnv, resolveMediaSourceUrl } from "@framefields/client-utils";
|
|
3
|
+
import { interpolate, spring } from "@framefields/renderers";
|
|
4
|
+
|
|
5
|
+
//#region src/utils/apply-operations.ts
|
|
6
|
+
const BASE_URL = getEnv("BASE_URL");
|
|
7
|
+
const CDN_DOMAIN = getEnv("R2_CUSTOM_DOMAIN");
|
|
8
|
+
function getFontUrl(name) {
|
|
9
|
+
if (CDN_DOMAIN) return `https://${CDN_DOMAIN}/fonts/${name}/font_file.ttf`;
|
|
10
|
+
return `${BASE_URL}/api/v1/fonts/load/${name}`;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Compute render parameters for the CURRENT node only — does NOT recurse into
|
|
14
|
+
* children. Each node in the VirtualMedia tree is responsible for exactly its
|
|
15
|
+
* own operation; `SingleClipComposition` drives traversal via React recursion.
|
|
16
|
+
*
|
|
17
|
+
* This is the correct function to use inside the renderer.
|
|
18
|
+
*/
|
|
19
|
+
function computeRenderParams(vv) {
|
|
20
|
+
const op = vv.operation;
|
|
21
|
+
const baseMeta = getActiveMediaMetadata(vv);
|
|
22
|
+
const params = {
|
|
23
|
+
sourceUrl: void 0,
|
|
24
|
+
trimStartSec: 0,
|
|
25
|
+
trimEndSec: null,
|
|
26
|
+
speed: 1,
|
|
27
|
+
cropRegion: null,
|
|
28
|
+
flipH: false,
|
|
29
|
+
flipV: false,
|
|
30
|
+
rotation: 0,
|
|
31
|
+
effectiveDurationSec: 0,
|
|
32
|
+
mimeType: resolveMediaMimeType(vv) || null
|
|
33
|
+
};
|
|
34
|
+
switch (op.op) {
|
|
35
|
+
case "text":
|
|
36
|
+
params.sourceUrl = void 0;
|
|
37
|
+
break;
|
|
38
|
+
default:
|
|
39
|
+
params.sourceUrl = resolveMediaSourceUrl(vv);
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
const sourceDurationSec = (baseMeta?.durationMs ?? 0) / 1e3;
|
|
43
|
+
params.effectiveDurationSec = ((params.trimEndSec ?? sourceDurationSec) - params.trimStartSec) / params.speed;
|
|
44
|
+
return params;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/utils/timing.ts
|
|
49
|
+
function framesToSeconds(frames, fps) {
|
|
50
|
+
return frames / fps;
|
|
51
|
+
}
|
|
52
|
+
function secondsToFrames(seconds, fps) {
|
|
53
|
+
return Math.round(seconds * fps);
|
|
54
|
+
}
|
|
55
|
+
function formatTimecode(seconds) {
|
|
56
|
+
const mins = Math.floor(seconds / 60);
|
|
57
|
+
const secs = Math.floor(seconds % 60);
|
|
58
|
+
const ms = Math.floor(seconds % 1 * 100);
|
|
59
|
+
return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}.${ms.toString().padStart(2, "0")}`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region src/utils/layer-logic.ts
|
|
64
|
+
const isStaticVisualMedia = (type) => type === "Image" || type === "SVG" || type === "Text";
|
|
65
|
+
const resolveLayerDuration = (layerDurationInMS, metaDurationMs, defaultDuration = DEFAULT_DURATION_MS, type) => {
|
|
66
|
+
if (type === "Caption") return metaDurationMs && metaDurationMs > 0 ? metaDurationMs : layerDurationInMS || defaultDuration;
|
|
67
|
+
const isStatic = isStaticVisualMedia(type);
|
|
68
|
+
if (layerDurationInMS && metaDurationMs && !isStatic) return Math.min(layerDurationInMS, metaDurationMs);
|
|
69
|
+
return layerDurationInMS || metaDurationMs || defaultDuration;
|
|
70
|
+
};
|
|
71
|
+
const calculateLayerTransform = (layer, frame, fps, viewport) => {
|
|
72
|
+
const relativeFrame = frame - (layer.startFrame ?? 0);
|
|
73
|
+
let x = layer.x ?? 0;
|
|
74
|
+
let y = layer.y ?? 0;
|
|
75
|
+
let scale = layer.scale ?? 1;
|
|
76
|
+
let rotation = layer.rotation ?? 0;
|
|
77
|
+
let opacity = layer.opacity ?? 1;
|
|
78
|
+
const volume = layer.volume ?? 1;
|
|
79
|
+
const layerDurationMs = resolveLayerDuration(layer.durationInMS, layer.virtualMedia?.metadata?.durationMs ?? void 0, DEFAULT_DURATION_MS, layer.type);
|
|
80
|
+
const duration = Math.round(layerDurationMs / 1e3 * fps);
|
|
81
|
+
const animations = layer.type === "Text" || layer.type === "Caption" ? [] : layer.animations ?? [];
|
|
82
|
+
if (animations.length === 0) return {
|
|
83
|
+
x,
|
|
84
|
+
y,
|
|
85
|
+
scale,
|
|
86
|
+
rotation,
|
|
87
|
+
opacity,
|
|
88
|
+
volume
|
|
89
|
+
};
|
|
90
|
+
animations.forEach((anim) => {
|
|
91
|
+
const durFrames = anim.value * fps;
|
|
92
|
+
const isOut = anim.type.includes("-out");
|
|
93
|
+
const startAnimFrame = isOut ? duration - durFrames : 0;
|
|
94
|
+
const endAnimFrame = isOut ? duration : durFrames;
|
|
95
|
+
if (relativeFrame < startAnimFrame || relativeFrame > endAnimFrame) return;
|
|
96
|
+
const progress = interpolate(relativeFrame, [startAnimFrame, endAnimFrame], [0, 1], {
|
|
97
|
+
extrapolateLeft: "clamp",
|
|
98
|
+
extrapolateRight: "clamp"
|
|
99
|
+
});
|
|
100
|
+
switch (anim.type) {
|
|
101
|
+
case "fade-in":
|
|
102
|
+
opacity *= progress;
|
|
103
|
+
break;
|
|
104
|
+
case "fade-out":
|
|
105
|
+
opacity *= 1 - progress;
|
|
106
|
+
break;
|
|
107
|
+
case "slide-in-left":
|
|
108
|
+
x += -1 * viewport.w * (1 - progress);
|
|
109
|
+
break;
|
|
110
|
+
case "slide-in-right":
|
|
111
|
+
x += 1 * viewport.w * (1 - progress);
|
|
112
|
+
break;
|
|
113
|
+
case "slide-in-top":
|
|
114
|
+
y += -1 * viewport.h * (1 - progress);
|
|
115
|
+
break;
|
|
116
|
+
case "slide-in-bottom":
|
|
117
|
+
y += 1 * viewport.h * (1 - progress);
|
|
118
|
+
break;
|
|
119
|
+
case "zoom-in":
|
|
120
|
+
scale *= interpolate(progress, [0, 1], [0, 1]);
|
|
121
|
+
break;
|
|
122
|
+
case "zoom-out":
|
|
123
|
+
scale *= interpolate(progress, [0, 1], [1, 0]);
|
|
124
|
+
break;
|
|
125
|
+
case "rotate-cw":
|
|
126
|
+
rotation += 360 * progress;
|
|
127
|
+
break;
|
|
128
|
+
case "rotate-ccw":
|
|
129
|
+
rotation += -360 * progress;
|
|
130
|
+
break;
|
|
131
|
+
case "bounce": {
|
|
132
|
+
const bounceVal = spring({
|
|
133
|
+
frame: relativeFrame - startAnimFrame,
|
|
134
|
+
fps,
|
|
135
|
+
config: {
|
|
136
|
+
damping: 10,
|
|
137
|
+
mass: .5,
|
|
138
|
+
stiffness: 100
|
|
139
|
+
},
|
|
140
|
+
durationInFrames: durFrames
|
|
141
|
+
});
|
|
142
|
+
scale *= bounceVal;
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
case "shake":
|
|
146
|
+
x += 20 * Math.sin(relativeFrame * 10 * 2 * Math.PI / durFrames) * (1 - progress);
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
return {
|
|
151
|
+
x,
|
|
152
|
+
y,
|
|
153
|
+
scale,
|
|
154
|
+
rotation,
|
|
155
|
+
opacity,
|
|
156
|
+
volume
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
//#endregion
|
|
161
|
+
export { framesToSeconds as a, getFontUrl as c, formatTimecode as i, isStaticVisualMedia as n, secondsToFrames as o, resolveLayerDuration as r, computeRenderParams as s, calculateLayerTransform as t };
|
|
162
|
+
//# sourceMappingURL=layer-logic-DBs4NHoi.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layer-logic-DBs4NHoi.mjs","names":[],"sources":["../src/utils/apply-operations.ts","../src/utils/timing.ts","../src/utils/layer-logic.ts"],"sourcesContent":["import { getEnv, resolveMediaSourceUrl } from \"@framefields/client-utils\";\nimport {\n\tgetActiveMediaMetadata,\n\tresolveMediaMimeType,\n\ttype VirtualMediaData,\n} from \"@framefields/core\";\n\nexport type CropRegion = {\n\tleftPct: number;\n\ttopPct: number;\n\twidthPct: number;\n\theightPct: number;\n};\n\nexport type RenderParams = {\n\tsourceUrl: string | undefined;\n\ttrimStartSec: number;\n\ttrimEndSec: number | null;\n\tspeed: number;\n\tcropRegion: CropRegion | null;\n\tflipH: boolean;\n\tflipV: boolean;\n\trotation: number;\n\teffectiveDurationSec: number;\n\tmimeType: string | null;\n};\n\nconst BASE_URL = getEnv(\"BASE_URL\") as string;\nconst CDN_DOMAIN = getEnv(\"R2_CUSTOM_DOMAIN\") as string;\n\nexport function getFontUrl(name: string) {\n\tif (CDN_DOMAIN) {\n\t\treturn `https://${CDN_DOMAIN}/fonts/${name}/font_file.ttf`;\n\t}\n\treturn `${BASE_URL}/api/v1/fonts/load/${name}`;\n}\n\n/**\n * Compute render parameters for the CURRENT node only — does NOT recurse into\n * children. Each node in the VirtualMedia tree is responsible for exactly its\n * own operation; `SingleClipComposition` drives traversal via React recursion.\n *\n * This is the correct function to use inside the renderer.\n */\nexport function computeRenderParams(vv: VirtualMediaData): RenderParams {\n\tconst op = vv.operation;\n\tconst baseMeta = getActiveMediaMetadata(vv);\n\n\tconst params: RenderParams = {\n\t\tsourceUrl: undefined,\n\t\ttrimStartSec: 0,\n\t\ttrimEndSec: null,\n\t\tspeed: 1.0,\n\t\tcropRegion: null,\n\t\tflipH: false,\n\t\tflipV: false,\n\t\trotation: 0,\n\t\teffectiveDurationSec: 0,\n\t\tmimeType: resolveMediaMimeType(vv) || null,\n\t};\n\n\tswitch (op.op) {\n\t\tcase \"text\":\n\t\t\t// Rendered as a DOM element by the caller; no media URL needed.\n\t\t\tparams.sourceUrl = undefined;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tparams.sourceUrl = resolveMediaSourceUrl(vv);\n\t\t\tbreak;\n\t}\n\n\tconst sourceDurationSec = (baseMeta?.durationMs ?? 0) / 1000;\n\tparams.effectiveDurationSec =\n\t\t((params.trimEndSec ?? sourceDurationSec) - params.trimStartSec) /\n\t\tparams.speed;\n\n\treturn params;\n}\n","export function framesToSeconds(frames: number, fps: number): number {\n\treturn frames / fps;\n}\n\nexport function secondsToFrames(seconds: number, fps: number): number {\n\treturn Math.round(seconds * fps);\n}\n\nexport function formatTimecode(seconds: number): string {\n\tconst mins = Math.floor(seconds / 60);\n\tconst secs = Math.floor(seconds % 60);\n\tconst ms = Math.floor((seconds % 1) * 100);\n\treturn `${mins.toString().padStart(2, \"0\")}:${secs.toString().padStart(2, \"0\")}.${ms.toString().padStart(2, \"0\")}`;\n}\n","import type { ExtendedLayer } from \"@framefields/core\";\nimport { DEFAULT_DURATION_MS } from \"@framefields/core\";\nimport { interpolate, spring } from \"@framefields/renderers\";\n\nexport const isStaticVisualMedia = (type?: string): boolean =>\n\ttype === \"Image\" || type === \"SVG\" || type === \"Text\";\n\nexport const resolveLayerDuration = (\n\tlayerDurationInMS?: number,\n\tmetaDurationMs?: number,\n\tdefaultDuration: number = DEFAULT_DURATION_MS,\n\ttype?: string,\n): number => {\n\tif (type === \"Caption\") {\n\t\treturn metaDurationMs && metaDurationMs > 0\n\t\t\t? metaDurationMs\n\t\t\t: layerDurationInMS || defaultDuration;\n\t}\n\n\tconst isStatic = isStaticVisualMedia(type);\n\tif (layerDurationInMS && metaDurationMs && !isStatic) {\n\t\treturn Math.min(layerDurationInMS, metaDurationMs);\n\t}\n\n\treturn layerDurationInMS || metaDurationMs || defaultDuration;\n};\n\nexport const calculateLayerTransform = (\n\tlayer: ExtendedLayer,\n\tframe: number,\n\tfps: number,\n\tviewport: { w: number; h: number },\n) => {\n\tconst relativeFrame = frame - (layer.startFrame ?? 0);\n\tlet x = layer.x ?? 0;\n\tlet y = layer.y ?? 0;\n\tlet scale = layer.scale ?? 1;\n\tlet rotation = layer.rotation ?? 0;\n\tlet opacity = layer.opacity ?? 1;\n\tconst volume = layer.volume ?? 1;\n\n\tconst layerDurationMs = resolveLayerDuration(\n\t\tlayer.durationInMS,\n\t\tlayer.virtualMedia?.metadata?.durationMs ?? undefined,\n\t\tDEFAULT_DURATION_MS,\n\t\tlayer.type,\n\t);\n\n\tconst duration = Math.round((layerDurationMs / 1000) * fps);\n\tconst animations =\n\t\tlayer.type === \"Text\" || layer.type === \"Caption\"\n\t\t\t? []\n\t\t\t: (layer.animations ?? []);\n\tif (animations.length === 0)\n\t\treturn { x, y, scale, rotation, opacity, volume };\n\n\tanimations.forEach((anim) => {\n\t\tconst durFrames = anim.value * fps;\n\t\tconst isOut = anim.type.includes(\"-out\");\n\t\tconst startAnimFrame = isOut ? duration - durFrames : 0;\n\t\tconst endAnimFrame = isOut ? duration : durFrames;\n\t\tif (relativeFrame < startAnimFrame || relativeFrame > endAnimFrame) return;\n\n\t\tconst progress = interpolate(\n\t\t\trelativeFrame,\n\t\t\t[startAnimFrame, endAnimFrame],\n\t\t\t[0, 1],\n\t\t\t{ extrapolateLeft: \"clamp\", extrapolateRight: \"clamp\" },\n\t\t);\n\n\t\tswitch (anim.type) {\n\t\t\tcase \"fade-in\":\n\t\t\t\topacity *= progress;\n\t\t\t\tbreak;\n\t\t\tcase \"fade-out\":\n\t\t\t\topacity *= 1 - progress;\n\t\t\t\tbreak;\n\t\t\tcase \"slide-in-left\":\n\t\t\t\tx += -1 * viewport.w * (1 - progress);\n\t\t\t\tbreak;\n\t\t\tcase \"slide-in-right\":\n\t\t\t\tx += 1 * viewport.w * (1 - progress);\n\t\t\t\tbreak;\n\t\t\tcase \"slide-in-top\":\n\t\t\t\ty += -1 * viewport.h * (1 - progress);\n\t\t\t\tbreak;\n\t\t\tcase \"slide-in-bottom\":\n\t\t\t\ty += 1 * viewport.h * (1 - progress);\n\t\t\t\tbreak;\n\t\t\tcase \"zoom-in\":\n\t\t\t\tscale *= interpolate(progress, [0, 1], [0, 1]);\n\t\t\t\tbreak;\n\t\t\tcase \"zoom-out\":\n\t\t\t\tscale *= interpolate(progress, [0, 1], [1, 0]);\n\t\t\t\tbreak;\n\t\t\tcase \"rotate-cw\":\n\t\t\t\trotation += 360 * progress;\n\t\t\t\tbreak;\n\t\t\tcase \"rotate-ccw\":\n\t\t\t\trotation += -360 * progress;\n\t\t\t\tbreak;\n\t\t\tcase \"bounce\": {\n\t\t\t\tconst bounceVal = spring({\n\t\t\t\t\tframe: relativeFrame - startAnimFrame,\n\t\t\t\t\tfps,\n\t\t\t\t\tconfig: { damping: 10, mass: 0.5, stiffness: 100 },\n\t\t\t\t\tdurationInFrames: durFrames,\n\t\t\t\t});\n\t\t\t\tscale *= bounceVal;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"shake\": {\n\t\t\t\tx +=\n\t\t\t\t\t20 *\n\t\t\t\t\tMath.sin((relativeFrame * 10 * 2 * Math.PI) / durFrames) *\n\t\t\t\t\t(1 - progress);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\n\treturn { x, y, scale, rotation, opacity, volume };\n};\n"],"mappings":"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"}
|