/** * The gradient ramp bound at group 1, shared by the marks that fill from one. * The stops are baked into a 1D texture on the CPU, so a gradient costs a * sample rather than a stop loop per fragment. */ export declare const GRADIENT_BLOCK = "// coords = (x1, y1, x2, y2) in normalized item space,\n// bounds = (x, y, w, h) of the item in canvas coordinates,\n// misc = (kind, r1, r2, unused). kind: 1 = linear, 2 = radial.\nstruct GradientParams {\n coords: vec4,\n bounds: vec4,\n misc: vec4,\n}\n\n@group(1) @binding(0) var stopSampler: sampler;\n@group(1) @binding(1) var stopRamp: texture_2d;\n@group(1) @binding(2) var gradient: GradientParams;\n\n// p is normalized to the item, wh is the item size in pixels. Linear gradients\n// evaluate in normalized space, matching vega's canvas renderer. Radial ones\n// are circular in pixel space with radii scaled by max(w, h).\nfn gradientT(p: vec2, wh: vec2) -> f32 {\n if gradient.misc.x < 1.5 {\n let a = gradient.coords.xy;\n let b = gradient.coords.zw;\n let ab = b - a;\n let len2 = max(dot(ab, ab), 1e-6);\n return clamp(dot(p - a, ab) / len2, 0.0, 1.0);\n }\n // Radial: the pencil of circles running from (x1, y1, r1) to (x2, y2, r2),\n // which is what createRadialGradient interpolates. The stop is the largest\n // t whose circle passes through the point, so it solves\n // a*t*t - 2*b*t + c = 0 for the circle centre and radius at t. Taking the\n // distance from the outer centre instead is exact only where the two are\n // concentric. Canvas draws nothing outside the cone the circles sweep,\n // which is what a negative discriminant means here.\n let m = max(wh.x, wh.y);\n let c1 = gradient.coords.xy * wh;\n let c2 = gradient.coords.zw * wh;\n let r1 = gradient.misc.y * m;\n let r2 = gradient.misc.z * m;\n let cd = c2 - c1;\n let dr = r2 - r1;\n let pd = p * wh - c1;\n let a = dot(cd, cd) - dr * dr;\n let b = dot(pd, cd) + r1 * dr;\n let c = dot(pd, pd) - r1 * r1;\n if abs(a) < 1e-6 {\n if abs(b) < 1e-6 {\n return 1.0;\n }\n return clamp(c / (2.0 * b), 0.0, 1.0);\n }\n let disc = b * b - a * c;\n if disc < 0.0 {\n return 1.0;\n }\n let root = sqrt(disc);\n let hi = (b + root) / a;\n let lo = (b - root) / a;\n // the larger t wins, but only where its circle has a radius to draw with\n if r1 + hi * dr >= 0.0 {\n return clamp(hi, 0.0, 1.0);\n }\n return clamp(lo, 0.0, 1.0);\n}\n\n// The ramp's colour at a point in canvas coordinates, spread over the bounds.\nfn rampAt(world: vec2) -> vec4 {\n let p = (world - gradient.bounds.xy) / max(gradient.bounds.zw, vec2(1e-6, 1e-6));\n return textureSample(stopRamp, stopSampler, vec2(gradientT(p, gradient.bounds.zw), 0.5));\n}";