@framefields/node-mask-math 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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderers-B_QRX8uG.mjs","names":[],"sources":["../src/shared/config.ts","../src/renderers/webgpu-renderer.ts","../src/renderers/index.ts"],"sourcesContent":["import {\n\tconfigBuilder,\n\tImageResultSchema,\n\tVideoResultSchema,\n} from \"@framefields/node-sdk\";\nimport { z } from \"zod\";\n\nexport const MAX_RADIUS = 200;\n\nexport const MaskOperationEnum = z.enum([\n\t\"Union\",\n\t\"Intersect\",\n\t\"Subtract\",\n\t\"Difference\",\n\t\"Invert\",\n\t\"Dilate\",\n\t\"Erode\",\n\t\"Choke\",\n\t\"Feather\",\n]);\n\nexport type MaskOperation = z.infer<typeof MaskOperationEnum>;\n\nexport const MaskChannelEnum = z.enum([\n\t\"Alpha\",\n\t\"Luminance\",\n\t\"Red\",\n\t\"Green\",\n\t\"Blue\",\n]);\n\nexport type MaskChannel = z.infer<typeof MaskChannelEnum>;\n\nexport const MaskOutputFormatEnum = z.enum([\n\t\"WhiteWithAlpha\",\n\t\"GrayscaleRGB\",\n\t\"AlphaOnly\",\n\t\"PassthroughRGB\",\n]);\n\nexport type MaskOutputFormat = z.infer<typeof MaskOutputFormatEnum>;\n\nexport const maskMathConfig = configBuilder()\n\t.field(\"operation\", MaskOperationEnum.default(\"Union\"), {\n\t\tlabel: \"Operation\",\n\t\tdescription:\n\t\t\t\"Morphological or Boolean set operation applied to input alpha masks.\",\n\t})\n\t.field(\"radius\", z.number().min(0).max(MAX_RADIUS).default(0), {\n\t\tbindable: true,\n\t\tdataTypes: [\"Number\", \"Signal\"],\n\t\tlabel: \"Radius / Width (px)\",\n\t\tdescription:\n\t\t\t\"Kernel radius in pixels for Dilate, Erode, Choke, or Feather operations.\",\n\t})\n\t.field(\n\t\t\"threshold\",\n\t\tz.number().multipleOf(0.01).min(0.0).max(1.0).default(0.5),\n\t\t{\n\t\t\tbindable: true,\n\t\t\tdataTypes: [\"Number\", \"Signal\"],\n\t\t\tlabel: \"Threshold\",\n\t\t\tdescription:\n\t\t\t\t\"Cutoff threshold level (0.0–1.0) for binarization step or non-linear choke.\",\n\t\t},\n\t)\n\t.field(\n\t\t\"clampMin\",\n\t\tz.number().multipleOf(0.01).min(0.0).max(1.0).default(0.0),\n\t\t{\n\t\t\tbindable: true,\n\t\t\tdataTypes: [\"Number\", \"Signal\"],\n\t\t\tlabel: \"Clamp Min\",\n\t\t\tdescription: \"Minimum alpha matte cutoff limit (0.0–1.0).\",\n\t\t},\n\t)\n\t.field(\n\t\t\"clampMax\",\n\t\tz.number().multipleOf(0.01).min(0.0).max(1.0).default(1.0),\n\t\t{\n\t\t\tbindable: true,\n\t\t\tdataTypes: [\"Number\", \"Signal\"],\n\t\t\tlabel: \"Clamp Max\",\n\t\t\tdescription: \"Maximum alpha matte cutoff limit (0.0–1.0).\",\n\t\t},\n\t)\n\t.field(\"channelA\", MaskChannelEnum.default(\"Alpha\"), {\n\t\tlabel: \"Mask A Channel\",\n\t\tdescription:\n\t\t\t\"Source channel to extract mask from Mask A (Alpha, Luminance, Red, Green, Blue).\",\n\t})\n\t.field(\"channelB\", MaskChannelEnum.default(\"Alpha\"), {\n\t\tlabel: \"Mask B Channel\",\n\t\tdescription:\n\t\t\t\"Source channel to extract mask from Mask B (Alpha, Luminance, Red, Green, Blue).\",\n\t})\n\t.field(\"binarize\", z.boolean().default(false), {\n\t\tlabel: \"Binarize\",\n\t\tdescription:\n\t\t\t\"When enabled, outputs crisp 1-bit binary matte based on threshold.\",\n\t})\n\t.field(\"invertResult\", z.boolean().default(false), {\n\t\tlabel: \"Invert Result\",\n\t\tdescription: \"Inverts final matte output.\",\n\t})\n\t.field(\"outputFormat\", MaskOutputFormatEnum.default(\"WhiteWithAlpha\"), {\n\t\tlabel: \"Output Format\",\n\t\tdescription:\n\t\t\t\"WhiteWithAlpha (rgba(1,1,1,a)), GrayscaleRGB (rgba(a,a,a,1)), AlphaOnly (rgba(0,0,0,a)), PassthroughRGB (Mask A RGB with new alpha).\",\n\t})\n\t.build();\n\nexport const MaskMathNodeConfigSchema = maskMathConfig.schema;\n\nexport type MaskMathNodeConfig = z.infer<typeof MaskMathNodeConfigSchema>;\n\nexport const MaskMathResultSchema = z.union([\n\tImageResultSchema,\n\tVideoResultSchema,\n]);\n\nexport type MaskMathResult = z.infer<typeof MaskMathResultSchema>;\n\nexport const MASK_MATH_OUTPUT_TYPE_MAP: Record<\n\tstring,\n\t\"Image\" | \"Video\" | \"GIF\"\n> = {\n\tVideo: \"Video\",\n\tLottie: \"Video\",\n\tGIF: \"GIF\",\n\tImage: \"Image\",\n\tSVG: \"Image\",\n};\n","/// <reference types=\"webgpu\" />\nimport type { VirtualMediaData } from \"@framefields/core\";\nimport type { WebGPUNodeRenderer } from \"@framefields/node-sdk\";\nimport { signalRegistry } from \"@framefields/webgpu-renderers\";\nimport {\n\tMAX_RADIUS,\n\ttype MaskChannel,\n\ttype MaskMathOp,\n\ttype MaskMathSignalData,\n\ttype MaskOperation,\n\ttype MaskOutputFormat,\n} from \"../shared/index.js\";\n\nconst OPERATION_MAP: Record<MaskOperation, number> = {\n\tUnion: 0,\n\tIntersect: 1,\n\tSubtract: 2,\n\tDifference: 3,\n\tInvert: 4,\n\tDilate: 5,\n\tErode: 6,\n\tChoke: 7,\n\tFeather: 8,\n};\n\nconst CHANNEL_MAP: Record<MaskChannel, number> = {\n\tAlpha: 0,\n\tLuminance: 1,\n\tRed: 2,\n\tGreen: 3,\n\tBlue: 4,\n};\n\nconst OUTPUT_FORMAT_MAP: Record<MaskOutputFormat, number> = {\n\tWhiteWithAlpha: 0,\n\tGrayscaleRGB: 1,\n\tAlphaOnly: 2,\n\tPassthroughRGB: 3,\n};\n\nconst WGSL_MASKMATH = `\nstruct MaskMathUniforms {\n\tdirX : f32,\n\tdirY : f32,\n\tradius : f32,\n\tthreshold : f32,\n\n\tclampMin : f32,\n\tclampMax : f32,\n\toperation : f32,\n\tchannelA : f32,\n\n\tchannelB : f32,\n\tbinarize : f32,\n\tinvertResult : f32,\n\toutputFormat : f32,\n\n\thasMaskB : f32,\n\thasRadiusSig : f32,\n\thasThreshSig : f32,\n\thasClampMinSig : f32,\n\n\thasClampMaxSig : f32,\n\tisSecondPass : f32,\n\tpad0 : f32,\n\tpad1 : f32,\n};\n\n@group(0) @binding(0) var<uniform> u : MaskMathUniforms;\n\n@group(1) @binding(0) var texA : texture_2d<f32>;\n@group(1) @binding(1) var texB : texture_2d<f32>;\n@group(1) @binding(2) var origTexA : texture_2d<f32>;\n@group(1) @binding(3) var samp : sampler;\n\n@group(2) @binding(0) var radiusSigTex : texture_2d<f32>;\n@group(2) @binding(1) var threshSigTex : texture_2d<f32>;\n@group(2) @binding(2) var clampMinSigTex : texture_2d<f32>;\n@group(2) @binding(3) var clampMaxSigTex : texture_2d<f32>;\n@group(2) @binding(4) var signalSamp : sampler;\n\nstruct VSOut {\n\t@builtin(position) pos : vec4<f32>,\n\t@location(0) uv : vec2<f32>,\n};\n\n@vertex fn vs(@builtin(vertex_index) vi: u32) -> VSOut {\n\tvar pos = array<vec2<f32>, 4>(\n\t\tvec2<f32>(-1.0, 1.0),\n\t\tvec2<f32>(1.0, 1.0),\n\t\tvec2<f32>(-1.0, -1.0),\n\t\tvec2<f32>(1.0, -1.0)\n\t);\n\tvar uv = array<vec2<f32>, 4>(\n\t\tvec2<f32>(0.0, 0.0),\n\t\tvec2<f32>(1.0, 0.0),\n\t\tvec2<f32>(0.0, 1.0),\n\t\tvec2<f32>(1.0, 1.0)\n\t);\n\treturn VSOut(vec4<f32>(pos[vi], 0.0, 1.0), uv[vi]);\n}\n\nfn extractChannel(color : vec4<f32>, chCode : f32) -> f32 {\n\tif (chCode < 0.5) {\n\t\t// Alpha\n\t\treturn color.a;\n\t} else if (chCode < 1.5) {\n\t\t// Luminance\n\t\tlet luma = dot(color.rgb, vec3<f32>(0.2126, 0.7152, 0.0722));\n\t\tif (color.a > 1e-4) {\n\t\t\treturn min(1.0, luma / color.a);\n\t\t}\n\t\treturn luma;\n\t} else if (chCode < 2.5) {\n\t\t// Red\n\t\tif (color.a > 1e-4) {\n\t\t\treturn min(1.0, color.r / color.a);\n\t\t}\n\t\treturn color.r;\n\t} else if (chCode < 3.5) {\n\t\t// Green\n\t\tif (color.a > 1e-4) {\n\t\t\treturn min(1.0, color.g / color.a);\n\t\t}\n\t\treturn color.g;\n\t} else {\n\t\t// Blue\n\t\tif (color.a > 1e-4) {\n\t\t\treturn min(1.0, color.b / color.a);\n\t\t}\n\t\treturn color.b;\n\t}\n}\n\n@fragment fn fs(in : VSOut) -> @location(0) vec4<f32> {\n\tlet dimensions = vec2<f32>(textureDimensions(texA));\n\tlet texelSize = 1.0 / max(dimensions, vec2<f32>(1.0, 1.0));\n\n\tvar radius = u.radius;\n\tif (u.hasRadiusSig > 0.5) {\n\t\tradius = clamp(textureSampleLevel(radiusSigTex, signalSamp, vec2<f32>(0.5, 0.5), 0.0).r, 0.0, 200.0);\n\t}\n\tvar threshold = u.threshold;\n\tif (u.hasThreshSig > 0.5) {\n\t\tthreshold = clamp(textureSampleLevel(threshSigTex, signalSamp, vec2<f32>(0.5, 0.5), 0.0).r, 0.0, 1.0);\n\t}\n\tvar clampMin = u.clampMin;\n\tif (u.hasClampMinSig > 0.5) {\n\t\tclampMin = clamp(textureSampleLevel(clampMinSigTex, signalSamp, vec2<f32>(0.5, 0.5), 0.0).r, 0.0, 1.0);\n\t}\n\tvar clampMax = u.clampMax;\n\tif (u.hasClampMaxSig > 0.5) {\n\t\tclampMax = clamp(textureSampleLevel(clampMaxSigTex, signalSamp, vec2<f32>(0.5, 0.5), 0.0).r, 0.0, 1.0);\n\t}\n\n\tlet op = u.operation;\n\tlet direction = vec2<f32>(u.dirX, u.dirY);\n\n\tvar val = 0.0;\n\n\tif (u.isSecondPass <= 0.5) {\n\t\t// -------------------------------------------------------------\n\t\t// PASS 1: Horizontal pass / Boolean operation\n\t\t// -------------------------------------------------------------\n\t\tlet sampleA = textureSampleLevel(texA, samp, in.uv, 0.0);\n\t\tlet sampleB = textureSampleLevel(texB, samp, in.uv, 0.0);\n\n\t\tlet a = extractChannel(sampleA, u.channelA);\n\t\tlet b = select(0.0, extractChannel(sampleB, u.channelB), u.hasMaskB > 0.5);\n\n\t\tif (op < 0.5) {\n\t\t\t// Union (A + B)\n\t\t\tval = select(a, clamp(a + b, 0.0, 1.0), u.hasMaskB > 0.5);\n\t\t} else if (op < 1.5) {\n\t\t\t// Intersect (min(A, B))\n\t\t\tval = select(a, min(a, b), u.hasMaskB > 0.5);\n\t\t} else if (op < 2.5) {\n\t\t\t// Subtract (clamp(A - B, 0, 1))\n\t\t\tval = select(a, clamp(a - b, 0.0, 1.0), u.hasMaskB > 0.5);\n\t\t} else if (op < 3.5) {\n\t\t\t// Difference (|A - B|)\n\t\t\tval = select(a, abs(a - b), u.hasMaskB > 0.5);\n\t\t} else if (op < 4.5) {\n\t\t\t// Invert (1 - A)\n\t\t\tval = 1.0 - a;\n\t\t} else if (op < 5.5) {\n\t\t\t// Dilate (Horizontal Max)\n\t\t\tif (radius <= 0.0) {\n\t\t\t\tval = a;\n\t\t\t} else {\n\t\t\t\tlet stepScale = max(1.0, radius / 20.0);\n\t\t\t\tlet sampleRadius = min(i32(ceil(radius / stepScale)), 48);\n\t\t\t\tvar maxVal = a;\n\t\t\t\tfor (var i = -sampleRadius; i <= sampleRadius; i++) {\n\t\t\t\t\tlet offset = vec2<f32>(f32(i) * stepScale) * direction * texelSize;\n\t\t\t\t\tlet s = textureSampleLevel(texA, samp, in.uv + offset, 0.0);\n\t\t\t\t\tmaxVal = max(maxVal, extractChannel(s, u.channelA));\n\t\t\t\t}\n\t\t\t\tval = maxVal;\n\t\t\t}\n\t\t} else if (op < 7.5) {\n\t\t\t// Erode & Choke (Horizontal Min)\n\t\t\tif (radius <= 0.0) {\n\t\t\t\tval = a;\n\t\t\t} else {\n\t\t\t\tlet stepScale = max(1.0, radius / 20.0);\n\t\t\t\tlet sampleRadius = min(i32(ceil(radius / stepScale)), 48);\n\t\t\t\tvar minVal = a;\n\t\t\t\tfor (var i = -sampleRadius; i <= sampleRadius; i++) {\n\t\t\t\t\tlet offset = vec2<f32>(f32(i) * stepScale) * direction * texelSize;\n\t\t\t\t\tlet s = textureSampleLevel(texA, samp, in.uv + offset, 0.0);\n\t\t\t\t\tminVal = min(minVal, extractChannel(s, u.channelA));\n\t\t\t\t}\n\t\t\t\tval = minVal;\n\t\t\t}\n\t\t} else {\n\t\t\t// Feather (Horizontal Gaussian Blur)\n\t\t\tif (radius <= 0.0) {\n\t\t\t\tval = a;\n\t\t\t} else {\n\t\t\t\tlet spatial_sigma = max(0.1, radius / 2.0);\n\t\t\t\tlet stepScale = max(1.0, spatial_sigma / 20.0);\n\t\t\t\tlet effectiveSigma = spatial_sigma / stepScale;\n\t\t\t\tlet sampleRadius = min(i32(ceil(3.0 * effectiveSigma)), 48);\n\t\t\t\tvar accum = 0.0;\n\t\t\t\tvar totalWeight = 0.0;\n\t\t\t\tfor (var i = -sampleRadius; i <= sampleRadius; i++) {\n\t\t\t\t\tlet offset = vec2<f32>(f32(i) * stepScale) * direction * texelSize;\n\t\t\t\t\tlet x = f32(i) * stepScale;\n\t\t\t\t\tlet weight = exp(-0.5 * (x / spatial_sigma) * (x / spatial_sigma));\n\t\t\t\t\tlet s = textureSampleLevel(texA, samp, in.uv + offset, 0.0);\n\t\t\t\t\taccum += extractChannel(s, u.channelA) * weight;\n\t\t\t\t\ttotalWeight += weight;\n\t\t\t\t}\n\t\t\t\tval = accum / max(totalWeight, 1e-5);\n\t\t\t}\n\t\t}\n\n\t\treturn vec4<f32>(val, val, val, val);\n\t}\n\n\t// -------------------------------------------------------------\n\t// PASS 2: Vertical pass & Post-processing (clamp, binarize, format)\n\t// -------------------------------------------------------------\n\tlet samplePass1 = textureSampleLevel(texA, samp, in.uv, 0.0);\n\tvar matte = samplePass1.r;\n\n\t// 1. Spatial kernel processing (Dilate, Erode, Choke, Feather) when radius > 0\n\tif (radius > 0.0) {\n\t\tif (op >= 4.5 && op < 5.5) {\n\t\t\t// Dilate (Vertical Max)\n\t\t\tlet stepScale = max(1.0, radius / 20.0);\n\t\t\tlet sampleRadius = min(i32(ceil(radius / stepScale)), 48);\n\t\t\tvar maxVal = matte;\n\t\t\tfor (var i = -sampleRadius; i <= sampleRadius; i++) {\n\t\t\t\tlet offset = vec2<f32>(f32(i) * stepScale) * direction * texelSize;\n\t\t\t\tlet s = textureSampleLevel(texA, samp, in.uv + offset, 0.0);\n\t\t\t\tmaxVal = max(maxVal, s.r);\n\t\t\t}\n\t\t\tmatte = maxVal;\n\t\t} else if (op >= 5.5 && op < 7.5) {\n\t\t\t// Erode & Choke (Vertical Min)\n\t\t\tlet stepScale = max(1.0, radius / 20.0);\n\t\t\tlet sampleRadius = min(i32(ceil(radius / stepScale)), 48);\n\t\t\tvar minVal = matte;\n\t\t\tfor (var i = -sampleRadius; i <= sampleRadius; i++) {\n\t\t\t\tlet offset = vec2<f32>(f32(i) * stepScale) * direction * texelSize;\n\t\t\t\tlet s = textureSampleLevel(texA, samp, in.uv + offset, 0.0);\n\t\t\t\tminVal = min(minVal, s.r);\n\t\t\t}\n\t\t\tmatte = minVal;\n\t\t} else if (op >= 7.5) {\n\t\t\t// Feather (Vertical Gaussian Blur)\n\t\t\tlet spatial_sigma = max(0.1, radius / 2.0);\n\t\t\tlet stepScale = max(1.0, spatial_sigma / 20.0);\n\t\t\tlet effectiveSigma = spatial_sigma / stepScale;\n\t\t\tlet sampleRadius = min(i32(ceil(3.0 * effectiveSigma)), 48);\n\t\t\tvar accum = 0.0;\n\t\t\tvar totalWeight = 0.0;\n\t\t\tfor (var i = -sampleRadius; i <= sampleRadius; i++) {\n\t\t\t\tlet offset = vec2<f32>(f32(i) * stepScale) * direction * texelSize;\n\t\t\t\tlet x = f32(i) * stepScale;\n\t\t\t\tlet weight = exp(-0.5 * (x / spatial_sigma) * (x / spatial_sigma));\n\t\t\t\tlet s = textureSampleLevel(texA, samp, in.uv + offset, 0.0);\n\t\t\t\taccum += s.r * weight;\n\t\t\t\ttotalWeight += weight;\n\t\t\t}\n\t\t\tmatte = accum / max(totalWeight, 1e-5);\n\t\t}\n\t}\n\n\t// 2. Choke non-linear threshold contraction curve (applies even if radius == 0)\n\tif (op >= 6.5 && op < 7.5) {\n\t\tlet threshRange = max(0.01, 1.0 - threshold);\n\t\tmatte = clamp((matte - threshold) / threshRange, 0.0, 1.0);\n\t}\n\n\t// Range clamping\n\tlet lowerLimit = min(clampMin, clampMax);\n\tlet upperLimit = max(clampMin, clampMax);\n\tmatte = clamp(matte, lowerLimit, upperLimit);\n\n\t// Optional Binarization\n\tif (u.binarize > 0.5) {\n\t\tmatte = select(0.0, 1.0, matte >= threshold);\n\t}\n\n\t// Optional Inversion\n\tif (u.invertResult > 0.5) {\n\t\tmatte = 1.0 - matte;\n\t}\n\n\t// Output format conversion\n\tlet fmt = u.outputFormat;\n\tif (fmt < 0.5) {\n\t\t// WhiteWithAlpha: vec4(matte, matte, matte, matte) (premultiplied standard mask)\n\t\treturn vec4<f32>(matte, matte, matte, matte);\n\t} else if (fmt < 1.5) {\n\t\t// GrayscaleRGB: vec4(matte, matte, matte, 1.0)\n\t\treturn vec4<f32>(matte, matte, matte, 1.0);\n\t} else if (fmt < 2.5) {\n\t\t// AlphaOnly: vec4(0.0, 0.0, 0.0, matte)\n\t\treturn vec4<f32>(0.0, 0.0, 0.0, matte);\n\t} else {\n\t\t// PassthroughRGB: Mask A color with new alpha\n\t\tlet origCol = textureSampleLevel(origTexA, samp, in.uv, 0.0);\n\t\tif (origCol.a < 1e-4) {\n\t\t\treturn vec4<f32>(0.0, 0.0, 0.0, 0.0);\n\t\t}\n\t\tlet unpremult = origCol.rgb / origCol.a;\n\t\treturn vec4<f32>(unpremult * matte, matte);\n\t}\n}\n`;\n\ninterface DeviceMaskMathResources {\n\tuniformLayout: GPUBindGroupLayout;\n\ttextureLayout: GPUBindGroupLayout;\n\tsignalTextureLayout: GPUBindGroupLayout;\n\tpipeline: GPURenderPipeline;\n}\n\nconst deviceResourceCache = new WeakMap<GPUDevice, DeviceMaskMathResources>();\n\nfunction getMaskMathResources(\n\tdevice: GPUDevice,\n\ttargetFormat: GPUTextureFormat,\n): DeviceMaskMathResources {\n\tconst cached = deviceResourceCache.get(device);\n\tif (cached) return cached;\n\n\tconst uniformLayout = device.createBindGroupLayout({\n\t\tentries: [\n\t\t\t{\n\t\t\t\tbinding: 0,\n\t\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\t\tbuffer: { type: \"uniform\" },\n\t\t\t},\n\t\t],\n\t});\n\n\tconst textureLayout = device.createBindGroupLayout({\n\t\tentries: [\n\t\t\t{\n\t\t\t\tbinding: 0,\n\t\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\t\ttexture: { sampleType: \"float\" },\n\t\t\t},\n\t\t\t{\n\t\t\t\tbinding: 1,\n\t\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\t\ttexture: { sampleType: \"float\" },\n\t\t\t},\n\t\t\t{\n\t\t\t\tbinding: 2,\n\t\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\t\ttexture: { sampleType: \"float\" },\n\t\t\t},\n\t\t\t{\n\t\t\t\tbinding: 3,\n\t\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\t\tsampler: { type: \"filtering\" },\n\t\t\t},\n\t\t],\n\t});\n\n\tconst signalTextureLayout = device.createBindGroupLayout({\n\t\tentries: [\n\t\t\t{\n\t\t\t\tbinding: 0,\n\t\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\t\ttexture: { sampleType: \"float\" },\n\t\t\t},\n\t\t\t{\n\t\t\t\tbinding: 1,\n\t\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\t\ttexture: { sampleType: \"float\" },\n\t\t\t},\n\t\t\t{\n\t\t\t\tbinding: 2,\n\t\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\t\ttexture: { sampleType: \"float\" },\n\t\t\t},\n\t\t\t{\n\t\t\t\tbinding: 3,\n\t\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\t\ttexture: { sampleType: \"float\" },\n\t\t\t},\n\t\t\t{\n\t\t\t\tbinding: 4,\n\t\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\t\tsampler: { type: \"filtering\" },\n\t\t\t},\n\t\t],\n\t});\n\n\tconst shaderModule = device.createShaderModule({\n\t\tcode: WGSL_MASKMATH,\n\t});\n\n\tconst pipelineLayout = device.createPipelineLayout({\n\t\tbindGroupLayouts: [uniformLayout, textureLayout, signalTextureLayout],\n\t});\n\n\tconst pipeline = device.createRenderPipeline({\n\t\tlayout: pipelineLayout,\n\t\tvertex: {\n\t\t\tmodule: shaderModule,\n\t\t\tentryPoint: \"vs\",\n\t\t},\n\t\tfragment: {\n\t\t\tmodule: shaderModule,\n\t\t\tentryPoint: \"fs\",\n\t\t\ttargets: [{ format: targetFormat }],\n\t\t},\n\t\tprimitive: {\n\t\t\ttopology: \"triangle-strip\",\n\t\t},\n\t});\n\n\tconst res: DeviceMaskMathResources = {\n\t\tuniformLayout,\n\t\ttextureLayout,\n\t\tsignalTextureLayout,\n\t\tpipeline,\n\t};\n\tdeviceResourceCache.set(device, res);\n\treturn res;\n}\n\nexport const WebGPURenderer: WebGPUNodeRenderer = async (args) => {\n\tconst {\n\t\tctx,\n\t\tencoder,\n\t\tpass,\n\t\ttargetView,\n\t\ttargetTexture,\n\t\ttargetWidth,\n\t\ttargetHeight,\n\t\tprops,\n\t\tdrawChild,\n\t} = args;\n\n\tconst op = props.virtualMedia?.operation as MaskMathOp | undefined;\n\tif (op?.op !== \"MaskMath\" || !op) return;\n\n\tconst childMedia = props.virtualMedia?.children?.[0];\n\tif (!childMedia) return;\n\n\t// End incoming pass\n\tpass.end();\n\n\tconst frame = props.frame ?? 0;\n\tconst fps = props.fps || 30;\n\tconst width = targetWidth;\n\tconst height = targetHeight;\n\n\tconst resolveField = (\n\t\thandleId: string | null | undefined,\n\t\tfallbackVal: number,\n\t\tclampMin = 0,\n\t\tclampMax = 1000,\n\t): {\n\t\tval: number;\n\t\thasStaticSig: boolean;\n\t\tsd: MaskMathSignalData | null;\n\t\thandleId?: string | null;\n\t} => {\n\t\tif (handleId && op.inputs?.[handleId]?.connectionValid) {\n\t\t\tconst outputItem = op.inputs[handleId].outputItem;\n\t\t\tif (outputItem?.type === \"Number\") {\n\t\t\t\tconst numVal =\n\t\t\t\t\ttypeof outputItem.data === \"number\"\n\t\t\t\t\t\t? outputItem.data\n\t\t\t\t\t\t: ((outputItem.data as { value?: number })?.value ?? fallbackVal);\n\t\t\t\treturn {\n\t\t\t\t\tval: Math.max(clampMin, Math.min(clampMax, numVal)),\n\t\t\t\t\thasStaticSig: false,\n\t\t\t\t\tsd: null,\n\t\t\t\t\thandleId,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (outputItem?.type === \"Signal\" && outputItem.data) {\n\t\t\t\treturn {\n\t\t\t\t\tval: fallbackVal,\n\t\t\t\t\thasStaticSig: true,\n\t\t\t\t\tsd: outputItem.data as MaskMathSignalData,\n\t\t\t\t\thandleId,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tval: Math.max(clampMin, Math.min(clampMax, fallbackVal)),\n\t\t\thasStaticSig: false,\n\t\t\tsd: null,\n\t\t\thandleId,\n\t\t};\n\t};\n\n\tconst radiusRes = resolveField(\n\t\top.radiusHandleId,\n\t\tNumber(op.radius ?? 0),\n\t\t0,\n\t\tMAX_RADIUS,\n\t);\n\tconst thresholdRes = resolveField(\n\t\top.thresholdHandleId,\n\t\tNumber(op.threshold ?? 0.5),\n\t\t0.0,\n\t\t1.0,\n\t);\n\tconst clampMinRes = resolveField(\n\t\top.clampMinHandleId,\n\t\tNumber(op.clampMin ?? 0.0),\n\t\t0.0,\n\t\t1.0,\n\t);\n\tconst clampMaxRes = resolveField(\n\t\top.clampMaxHandleId,\n\t\tNumber(op.clampMax ?? 1.0),\n\t\t0.0,\n\t\t1.0,\n\t);\n\n\t// 1. Render primary Mask A child media\n\tconst tmpATex = ctx.renderer.getTemporaryTexture(width, height, [\n\t\t...(props.excludeTextures || []),\n\t\ttargetTexture,\n\t]);\n\tconst tmpAView = tmpATex.createView();\n\n\tconst childAPass = ctx.renderer.beginFrame(\n\t\tencoder,\n\t\ttmpAView,\n\t\t{ r: 0, g: 0, b: 0, a: 0 },\n\t\twidth,\n\t\theight,\n\t\t\"clear\",\n\t);\n\tchildAPass.end();\n\n\tctx.renderer.pushScissor({ x: 0, y: 0, width, height });\n\tctx.renderer.pushIdentity();\n\tawait drawChild(\n\t\tchildMedia,\n\t\t{\n\t\t\t...props,\n\t\t\tvirtualMedia: childMedia,\n\t\t\trenderId: `${props.renderId}-maskA`,\n\t\t\texcludeTextures: [...(props.excludeTextures || []), tmpATex],\n\t\t},\n\t\ttmpAView,\n\t\ttmpATex,\n\t\twidth,\n\t\theight,\n\t);\n\tctx.renderer.popTransform();\n\tctx.renderer.popScissor();\n\n\t// 2. Render optional Mask B child media if connected\n\tlet tmpBTex: GPUTexture | null = null;\n\tif (op.maskBMedia) {\n\t\ttmpBTex = ctx.renderer.getTemporaryTexture(width, height, [\n\t\t\t...(props.excludeTextures || []),\n\t\t\ttargetTexture,\n\t\t\ttmpATex,\n\t\t]);\n\t\tconst tmpBView = tmpBTex.createView();\n\n\t\tconst childBPass = ctx.renderer.beginFrame(\n\t\t\tencoder,\n\t\t\ttmpBView,\n\t\t\t{ r: 0, g: 0, b: 0, a: 0 },\n\t\t\twidth,\n\t\t\theight,\n\t\t\t\"clear\",\n\t\t);\n\t\tchildBPass.end();\n\n\t\tctx.renderer.pushScissor({ x: 0, y: 0, width, height });\n\t\tctx.renderer.pushIdentity();\n\t\tawait drawChild(\n\t\t\top.maskBMedia as VirtualMediaData,\n\t\t\t{\n\t\t\t\t...props,\n\t\t\t\tvirtualMedia: op.maskBMedia as VirtualMediaData,\n\t\t\t\trenderId: `${props.renderId}-maskB`,\n\t\t\t\texcludeTextures: [...(props.excludeTextures || []), tmpATex, tmpBTex],\n\t\t\t},\n\t\t\ttmpBView,\n\t\t\ttmpBTex,\n\t\t\twidth,\n\t\t\theight,\n\t\t);\n\t\tctx.renderer.popTransform();\n\t\tctx.renderer.popScissor();\n\t}\n\n\t// 3. Compile pipeline resources\n\tconst { pipeline, uniformLayout, textureLayout, signalTextureLayout } =\n\t\tgetMaskMathResources(ctx.device, ctx.renderer.format);\n\tconst sampler = ctx.renderer.samplerCache.getSampler(ctx.device);\n\n\tconst elapsedSeconds =\n\t\tprops.elapsedMs !== undefined ? props.elapsedMs / 1000 : frame / fps;\n\tconst durationSeconds = props.virtualMedia?.metadata?.durationMs\n\t\t? props.virtualMedia.metadata.durationMs / 1000\n\t\t: props.durationMs !== undefined\n\t\t\t? props.durationMs / 1000\n\t\t\t: 0;\n\n\tconst getSignalView = (\n\t\tres: {\n\t\t\tval: number;\n\t\t\thasStaticSig: boolean;\n\t\t\tsd: MaskMathSignalData | null;\n\t\t\thandleId?: string | null;\n\t\t},\n\t\tsuffix: string,\n\t) => {\n\t\tif (res.hasStaticSig && res.sd) {\n\t\t\tconst cacheNodeId =\n\t\t\t\tres.sd.nodeId ??\n\t\t\t\tres.handleId ??\n\t\t\t\t`${props.renderId ?? \"maskmath\"}_${suffix}`;\n\t\t\treturn signalRegistry.getOrCreate2DTextureView(\n\t\t\t\tctx.device,\n\t\t\t\tencoder,\n\t\t\t\tcacheNodeId,\n\t\t\t\telapsedSeconds,\n\t\t\t\tdurationSeconds,\n\t\t\t\tres.sd,\n\t\t\t\twidth,\n\t\t\t\theight,\n\t\t\t\tprops.renderId,\n\t\t\t\tframe,\n\t\t\t\tfps,\n\t\t\t);\n\t\t}\n\t\treturn signalRegistry.getDummy1x1TextureView(ctx.device);\n\t};\n\n\tconst radiusView = getSignalView(radiusRes, \"radius_sig\");\n\tconst threshView = getSignalView(thresholdRes, \"threshold_sig\");\n\tconst clampMinView = getSignalView(clampMinRes, \"clampMin_sig\");\n\tconst clampMaxView = getSignalView(clampMaxRes, \"clampMax_sig\");\n\n\tconst sigBindGroup = ctx.device.createBindGroup({\n\t\tlayout: signalTextureLayout,\n\t\tentries: [\n\t\t\t{ binding: 0, resource: radiusView },\n\t\t\t{ binding: 1, resource: threshView },\n\t\t\t{ binding: 2, resource: clampMinView },\n\t\t\t{ binding: 3, resource: clampMaxView },\n\t\t\t{ binding: 4, resource: sampler },\n\t\t],\n\t});\n\n\tconst operationCode = OPERATION_MAP[op.operation ?? \"Union\"] ?? 0;\n\tconst channelACode = CHANNEL_MAP[op.channelA ?? \"Alpha\"] ?? 0;\n\tconst channelBCode = CHANNEL_MAP[op.channelB ?? \"Alpha\"] ?? 0;\n\tconst outputFormatCode =\n\t\tOUTPUT_FORMAT_MAP[op.outputFormat ?? \"WhiteWithAlpha\"] ?? 0;\n\n\tconst dummyBView = tmpBTex ? tmpBTex.createView() : tmpAView;\n\n\t// Populate separate uniform data buffers for each pass\n\tconst hUniformData = new Float32Array(20);\n\tconst vUniformData = new Float32Array(20);\n\n\tconst baseUniforms = [\n\t\t0.0, // [0] dirX (set per pass)\n\t\t0.0, // [1] dirY (set per pass)\n\t\tradiusRes.val, // [2] radius\n\t\tthresholdRes.val, // [3] threshold\n\t\tclampMinRes.val, // [4] clampMin\n\t\tclampMaxRes.val, // [5] clampMax\n\t\toperationCode, // [6] operation\n\t\tchannelACode, // [7] channelA\n\t\tchannelBCode, // [8] channelB\n\t\top.binarize ? 1.0 : 0.0, // [9] binarize\n\t\top.invertResult ? 1.0 : 0.0, // [10] invertResult\n\t\toutputFormatCode, // [11] outputFormat\n\t\ttmpBTex ? 1.0 : 0.0, // [12] hasMaskB\n\t\tradiusRes.hasStaticSig ? 1.0 : 0.0, // [13] hasRadiusSig\n\t\tthresholdRes.hasStaticSig ? 1.0 : 0.0, // [14] hasThreshSig\n\t\tclampMinRes.hasStaticSig ? 1.0 : 0.0, // [15] hasClampMinSig\n\t\tclampMaxRes.hasStaticSig ? 1.0 : 0.0, // [16] hasClampMaxSig\n\t\t0.0, // [17] isSecondPass (set per pass)\n\t\t0.0, // [18] pad0\n\t\t0.0, // [19] pad1\n\t];\n\n\thUniformData.set(baseUniforms);\n\thUniformData[0] = 1.0; // dirX\n\thUniformData[1] = 0.0; // dirY\n\thUniformData[17] = 0.0; // isSecondPass = false\n\n\tvUniformData.set(baseUniforms);\n\tvUniformData[0] = 0.0; // dirX\n\tvUniformData[1] = 1.0; // dirY\n\tvUniformData[17] = 1.0; // isSecondPass = true\n\n\tconst outTex1 = ctx.renderer.getTemporaryTexture(width, height, [\n\t\ttmpATex,\n\t\t...(tmpBTex ? [tmpBTex] : []),\n\t\ttargetTexture,\n\t\t...(props.excludeTextures || []),\n\t]);\n\tconst outTex2 = ctx.renderer.getTemporaryTexture(width, height, [\n\t\ttmpATex,\n\t\t...(tmpBTex ? [tmpBTex] : []),\n\t\toutTex1,\n\t\ttargetTexture,\n\t\t...(props.excludeTextures || []),\n\t]);\n\n\t// Pass 1: Horizontal Pass (or direct combination)\n\tconst hBuffer = ctx.renderer.getTemporaryBuffer(hUniformData);\n\n\tconst hPass = encoder.beginRenderPass({\n\t\tcolorAttachments: [\n\t\t\t{\n\t\t\t\tview: outTex1.createView(),\n\t\t\t\tloadOp: \"clear\",\n\t\t\t\tstoreOp: \"store\",\n\t\t\t\tclearValue: { r: 0, g: 0, b: 0, a: 0 },\n\t\t\t},\n\t\t],\n\t});\n\thPass.setPipeline(pipeline);\n\thPass.setBindGroup(\n\t\t0,\n\t\tctx.device.createBindGroup({\n\t\t\tlayout: uniformLayout,\n\t\t\tentries: [{ binding: 0, resource: { buffer: hBuffer } }],\n\t\t}),\n\t);\n\thPass.setBindGroup(\n\t\t1,\n\t\tctx.device.createBindGroup({\n\t\t\tlayout: textureLayout,\n\t\t\tentries: [\n\t\t\t\t{ binding: 0, resource: tmpAView },\n\t\t\t\t{ binding: 1, resource: dummyBView },\n\t\t\t\t{ binding: 2, resource: tmpAView },\n\t\t\t\t{ binding: 3, resource: sampler },\n\t\t\t],\n\t\t}),\n\t);\n\thPass.setBindGroup(2, sigBindGroup);\n\thPass.draw(4);\n\thPass.end();\n\n\t// Pass 2: Vertical Pass + post-processing\n\tconst vBuffer = ctx.renderer.getTemporaryBuffer(vUniformData);\n\n\tconst vPass = encoder.beginRenderPass({\n\t\tcolorAttachments: [\n\t\t\t{\n\t\t\t\tview: outTex2.createView(),\n\t\t\t\tloadOp: \"clear\",\n\t\t\t\tstoreOp: \"store\",\n\t\t\t\tclearValue: { r: 0, g: 0, b: 0, a: 0 },\n\t\t\t},\n\t\t],\n\t});\n\tvPass.setPipeline(pipeline);\n\tvPass.setBindGroup(\n\t\t0,\n\t\tctx.device.createBindGroup({\n\t\t\tlayout: uniformLayout,\n\t\t\tentries: [{ binding: 0, resource: { buffer: vBuffer } }],\n\t\t}),\n\t);\n\tvPass.setBindGroup(\n\t\t1,\n\t\tctx.device.createBindGroup({\n\t\t\tlayout: textureLayout,\n\t\t\tentries: [\n\t\t\t\t{ binding: 0, resource: outTex1.createView() },\n\t\t\t\t{ binding: 1, resource: dummyBView },\n\t\t\t\t{ binding: 2, resource: tmpAView },\n\t\t\t\t{ binding: 3, resource: sampler },\n\t\t\t],\n\t\t}),\n\t);\n\tvPass.setBindGroup(2, sigBindGroup);\n\tvPass.draw(4);\n\tvPass.end();\n\n\t// 4. Final Pass: draw output into targetView\n\tconst finalPass = ctx.renderer.beginFrame(\n\t\tencoder,\n\t\ttargetView,\n\t\t{ r: 0, g: 0, b: 0, a: 0 },\n\t\ttargetWidth,\n\t\ttargetHeight,\n\t\t\"load\",\n\t);\n\n\tconst finalOpacity = props.opacity ?? op.opacity ?? 1.0;\n\n\tctx.renderer.drawTexture(\n\t\tfinalPass,\n\t\toutTex2,\n\t\t{ x: 0, y: 0, width: targetWidth, height: targetHeight },\n\t\t{ opacity: finalOpacity },\n\t);\n\n\targs.pass = finalPass;\n};\n","import { defineRenderer } from \"@framefields/node-sdk/renderer\";\nimport { WebGPURenderer } from \"./webgpu-renderer.js\";\n\nexport default defineRenderer({\n\tWebGPURenderer,\n});\n\nexport { WebGPURenderer };\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,48 @@
1
1
  {
2
2
  "name": "@framefields/node-mask-math",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "2.0.3",
4
+ "private": false,
5
+ "framefields": {
6
+ "type": "MaskMath",
7
+ "kind": "effect"
8
+ },
9
+ "type": "module",
10
+ "license": "Apache-2.0",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.mts",
14
+ "development": "./src/index.ts",
15
+ "import": "./dist/index.mjs",
16
+ "default": "./dist/index.mjs"
17
+ },
18
+ "./renderer": {
19
+ "types": "./dist/renderer.d.mts",
20
+ "development": "./src/renderers/index.ts",
21
+ "import": "./dist/renderer.mjs",
22
+ "default": "./dist/renderer.mjs"
23
+ }
24
+ },
25
+ "dependencies": {
26
+ "zod": "^4.3.6",
27
+ "@framefields/node-sdk": "2.0.3",
28
+ "@framefields/webgpu-renderers": "2.0.3",
29
+ "@framefields/core": "2.0.3"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^24.1.0",
33
+ "tsdown": "^0.19.0",
34
+ "typescript": "^5.8.3",
35
+ "vitest": "^4.1.5",
36
+ "webgpu": "^0.4.0",
37
+ "@framefields/tsconfig": "2.0.3"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "scripts": {
43
+ "build": "tsdown",
44
+ "dev": "tsdown --watch",
45
+ "test": "vitest run --passWithNoTests",
46
+ "clean": "rm -rf dist .turbo"
47
+ }
6
48
  }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./shared/index.js";
2
+ export * from "./renderers/index.js";
@@ -0,0 +1,8 @@
1
+ import { defineRenderer } from "@framefields/node-sdk/renderer";
2
+ import { WebGPURenderer } from "./webgpu-renderer.js";
3
+
4
+ export default defineRenderer({
5
+ WebGPURenderer,
6
+ });
7
+
8
+ export { WebGPURenderer };