Skip to content

SVG based <DitherGradient> for 360 degree rotation and improved performance #19

Description

@sortedcord

Currently, the <DitherGradient> component renders via a <canvas> element and is restricted to four cardinal directions ("up" | "down" | "left" | "right"). If we were to extend this for precise 360deg steps, calculating arbitrary angles for gradients pixel by pixel can be computationally expensive, and rotating a canvas introduces browser anti aliasing that causes some blurriness because of anti-aliasing.

for (let y = 0; y < rows; y++) {
for (let x = 0; x < cols; x++) {
// t runs 0 at the `from` edge → 1 at the `to` edge.
const t =
spec.direction === "up"
? 1 - (y + 0.5) / rows
: spec.direction === "down"
? (y + 0.5) / rows
: spec.direction === "left"
? 1 - (x + 0.5) / cols
: (x + 0.5) / cols
const density = 1 - t

Basically, to support an arbitrary angles using this canvas approach, we would have to replace those simple fractions with Math.sin and Math.cos for every single cell in that loop. Computing this before calling fillRect causes main thread blocking.

Proposed Solution (Procedural SVG Filters)

I had been working on a standalone tool that achieves this effect perfectly by offloading the quantization and dithering math directly to the browser's native SVG rendering engine.

So, instead of iterating, we can use a lightweight SVG node:

  • Define the angle natively via an SVG <linearGradient>.
  • Embed the Bayer matrix (e.g., 4x4) and tile it using feTile.
  • Use feComposite (with arithmetic operators) and feComponentTransfer (with discrete tables) to mathematically threshold the gradient against the Bayer map natively.

Benefits:

  • We get Arbitrary Angles, so full 360-degree support.
  • No anti-aliasing as we wouldn't need to transform the canvas
  • Bypasses the nested JS for loop, moving heavy computation to the GPU/native renderer.

I already have a working proof of concept for this exact math and would love to help contribute it as a PR, either as a standalone component or an enhancement to the existing one. Let me know what the team thinks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions