feat: add feather brush tool with adjustable settings and blending functionality

- Implemented feather brush tool in the brushRaster module, allowing for feathered edges in brush strokes.
- Added new FeatherControls component for UI adjustments of feather settings including size, radius, strength, and smoothing.
- Updated brush preview logic to accommodate feather tool alongside existing brush and eraser tools.
- Enhanced layer rendering to support feather mask previews and interactions.
- Introduced blending logic for feathered strokes to mix blurred mask values with original pixels.
- Added unit tests for feather blending functionality and tool keybindings.
- Updated cursor handling to reflect feather tool usage.
This commit is contained in:
syntaxbullet
2026-07-11 22:08:25 +02:00
parent 95043dfbdd
commit 38565382c3
27 changed files with 491 additions and 65 deletions

View File

@@ -0,0 +1,40 @@
import { describe, expect, test } from "bun:test";
import { blendFeatherPatch } from "./brushRaster";
describe("feather brush raster blending", () => {
test("mixes blurred mask values inside the stroke and preserves pixels outside it", () => {
const original = rgbaRow([255, 255, 255, 255, 255]);
const blurred = rgbaRow([0, 64, 128, 192, 255]);
blendFeatherPatch(original, blurred, 5, 1, { x: 0, y: 0 }, {
from: { x: 2.5, y: 0.5 },
to: { x: 2.5, y: 0.5 },
size: 3,
strength: 100,
});
expect(alphaValues(original)).toEqual([255, 64, 128, 192, 255]);
});
test("applies strength as a non-destructive mix", () => {
const original = rgbaRow([255]);
const blurred = rgbaRow([0]);
blendFeatherPatch(original, blurred, 1, 1, { x: 0, y: 0 }, {
from: { x: 0.5, y: 0.5 },
to: { x: 0.5, y: 0.5 },
size: 10,
strength: 50,
});
expect(alphaValues(original)).toEqual([128]);
});
});
function rgbaRow(alpha: number[]) {
return new Uint8ClampedArray(alpha.flatMap((value) => [255, 255, 255, value]));
}
function alphaValues(data: Uint8ClampedArray) {
return Array.from({ length: data.length / 4 }, (_, index) => data[index * 4 + 3]);
}