SAMPLE BRUSH DRAWING TOOL experiments

This collection offers a hands-on, low-level tutorial for creating custom web-based brushes. It demonstrates how to build an interactive drawing tool where users can sample textures directly from an image to create dynamic, soft-edged round or square brushes. This is a practical guide for designers and developers looking to understand and implement custom drawing functionality in JavaScript.

SIMPLE SQUARE / ROUND BRUSH SAMPER

nice simpe easy example

     // Globale Variablen
        let img;
        let brushTip;
        let brushTipSet = false;
        let brushSizeSlider;
        let roundBrushInput;
        let squareBrushInput;
        
        // PGraphics-Element für die Zeichenfläche
        let pg;

        // Lädt das Bild
        function preload() {
            img = loadImage('https://picsum.photos/1280/768');
        }

        function setup() {
            const canvas = createCanvas(img.width, img.height);
            canvas.parent('canvas-container');

            // Erstellt die PGraphics-Zeichenfläche
            pg = createGraphics(width, height);
            pg.image(img, 0, 0);

            // Ruft die Menü-Elemente ab
            brushSizeSlider = document.getElementById('brushSizeSlider');
            roundBrushInput = document.getElementById('roundBrush');
            squareBrushInput = document.getElementById('squareBrush');
        }

        function draw() {
            // 1. Zeichnet die permanente Zeichenfläche (pg) auf den Haupt-Canvas
            image(pg, 0, 0);
            
            // 2. Zeichnet die temporäre Pinsel-Vorschau direkt auf den Haupt-Canvas
            if (mouseX >= 0 && mouseX <= width && mouseY >= 0 && mouseY <= height) {
                drawPreview();
            }

            // 3. Wenn die linke Maustaste gedrückt ist, zeichnet es permanent auf das PGraphics-Element
            if (mouseIsPressed && mouseButton === LEFT) {
                let currentSize = parseFloat(brushSizeSlider.value);
                let isRound = roundBrushInput.checked;

                if (brushTipSet) {
                    const drawSize = currentSize;
                    const aspectRatio = brushTip.width / brushTip.height;
                    const drawWidth = drawSize * aspectRatio;
                    const drawHeight = drawSize;
                    
                    pg.image(brushTip, mouseX - drawWidth / 2, mouseY - drawHeight / 2, drawWidth, drawHeight);
                } else {
                    // Fallback-Pinsel mit den gewählten Einstellungen
                    if (isRound) {
                        pg.noStroke();
                        pg.fill(150, 100);
                        pg.ellipse(mouseX, mouseY, currentSize, currentSize);
                    } else {
                        pg.noStroke();
                        pg.fill(150, 100);
                        pg.rect(mouseX - currentSize / 2, mouseY - currentSize / 2, currentSize, currentSize);
                    }
                }
            }
        }
        
        // Zeichnet die halbtransparente Vorschau direkt auf den Haupt-Canvas
        function drawPreview() {
            push();
            noStroke();
            let currentSize = parseFloat(brushSizeSlider.value);
            let isRound = roundBrushInput.checked;

            if (brushTipSet) {
                const drawSize = currentSize;
                const aspectRatio = brushTip.width / brushTip.height;
                const drawWidth = drawSize * aspectRatio;
                const drawHeight = drawSize;
                
                // Zeichnet die Pinselspitze halbtransparent
                tint(255, 128); // 50% Transparenz
                image(brushTip, mouseX - drawWidth / 2, mouseY - drawHeight / 2, drawWidth, drawHeight);
                noTint();
            } else {
                fill(150, 100);
                if (isRound) {
                    drawSoftBrush(mouseX, mouseY, currentSize, 100);
                } else {
                    drawSoftSquareBrush(mouseX, mouseY, currentSize, 100);
                }
            }
            pop();
        }

        function mousePressed() {
            if (mouseButton === RIGHT) {
                let currentSize = parseFloat(brushSizeSlider.value);
                let isRound = roundBrushInput.checked;
                
                let x = mouseX - currentSize / 2;
                let y = mouseY - currentSize / 2;
                let w = currentSize;
                let h = currentSize;

                x = constrain(x, 0, width - w);
                y = constrain(y, 0, height - h);
                
                // 1. Holt das Bildsegment vom PGraphics-Element
                let tempBrush = pg.get(x, y, w, h);
                
                // 2. Erstellt die Maske und wendet sie an
                tempBrush.mask(createBrushMask(w, h, isRound));
                
                brushTip = tempBrush;
                brushTipSet = true;
                
                console.log("Pinselspitze ausgewählt bei:", x, y, "Größe:", w, "Form: " + (isRound ? "Rund" : "Quadratisch"));
                
                return false;
            }
        }
        
        // Erstellt die Maske (Kreis oder Quadrat) auf einem PGraphics-Element
        function createBrushMask(w, h, isRound) {
            let maskPG = createGraphics(w, h);
            maskPG.background(0); // Schwarzer Hintergrund = vollständig transparent
            maskPG.noStroke();
            maskPG.fill(255); // Weiße Form = vollständig sichtbar

            // Weiche Kante
            let edgeSize = 3;
            for (let i = 0; i < edgeSize; i++) {
                let currentAlpha = map(i, 0, edgeSize - 1, 0, 255);
                maskPG.fill(255, currentAlpha);
                if (isRound) {
                    maskPG.ellipse(w / 2, h / 2, w - i, h - i);
                } else {
                    maskPG.rect(i, i, w - i * 2, h - i * 2);
                }
            }

            return maskPG;
        }

        // Hilfsfunktion zum Zeichnen eines runden Pinsels mit weicher Kante (für den Fallback)
        function drawSoftBrush(x, y, size, alpha) {
          noStroke();
          for (let i = 0; i < 3; i++) {
            let currentAlpha = map(i, 0, 2, alpha, 0);
            fill(150, currentAlpha);
            ellipse(x, y, size - i * 2, size - i * 2);
          }
        }

        // Hilfsfunktion zum Zeichnen eines quadratischen Pinsels mit weicher Kante (für den Fallback)
        function drawSoftSquareBrush(x, y, size, alpha) {
          noStroke();
          for (let i = 0; i < 3; i++) {
            let currentAlpha = map(i, 0, 2, alpha, 0);
            fill(150, currentAlpha);
            rect(x - (size - i * 2) / 2, y - (size - i * 2) / 2, size - i * 2, size - i * 2);
          }
        }

https://editor.p5js.org/brucexxxbanner/sketches/3318WXh3k