How can I create this effect?

110 Views Asked by At

I want to create this effect using HTML, JavaScript, and p5.js, but I don't know the name of this effect, and I don't know how to work on it. https://yalegraphicdesign.tumblr.com/post/182779665334/simone-cutri-mfa-2019

Similarly, I want to make the text wobble like mold or cells, and also want to give it an effect of spreading like below. If the above content is difficult, I would appreciate advice for a similar effect. https://martingroch.tumblr.com/post/188814239759/poster-for-theatre-meetfactory https://codepen.io/Mertl/pen/rNvEEYr

<!DOCTYPE html>
<html>
<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
</head>
<body>
    <script>
        const MAX = 1000;
        let particles = [];
        let list = [];
        let axis;
        let count = 0;
        let typedText = 'Macro';
        let inputText = [];
        let graphics;

        function setup() {
            createCanvas(1200, 600);
            colorMode(RGB, 255, 255, 255);
            frameRate(30);
            noStroke();
            noCursor();

            graphics = createGraphics(width, height);
            graphics.textFont("Arial", 300);
            graphics.fill(0);
            graphics.textAlign(CENTER, CENTER);
            graphics.text(typedText, width / 2, height / 2 - 70);
            typedText = "";
            inputText = [];

            count = 0;
            list = new Array(width * height);

            graphics.loadPixels();

            for(let y = 0; y <= height - 1; y++) {
                for(let x = 0; x <= width - 1; x++) {
                    let index = (x + y * graphics.width) * 4;
                    if(graphics.pixels[index] < 128) {  
                        list[y * width + x] = 0;  
                    } else {  
                        list[y * width + x] = 1;  
                    }
                }
            }

            graphics.updatePixels();
            particles = [];
        }

        function draw() {
            if (count < MAX) {
                let i = 0;

                while(i < 3) {
                    axis = createVector(int(random(100, width - 300)), int(random(100, height - 300)));
                    if(list[int(axis.y * width + axis.x)] == 0) {
                        particles.push(new Particle(axis.x, axis.y));
                        i++;
                        count++;
                    }
                }
            }
            background(239);
            for (let i = 0; i < particles.length; i++) {
                let p = particles[i];
                fill(20);
                p.display();
                p.update();
            }
        }

        function keyReleased() {
            if (keyCode == ENTER) {
                typedText = inputText.join('');
                setup();
            } else {
                inputText.push(key);
            }
        }

        class Particle {
            constructor(x, y) {
                this.location = createVector(x, y);
                this.velocity = createVector(0, 0);
                this.scale = random(0.35, 0.9);
                this.radius = this.scale * 45;
                this.border = 15;
            }

            update() {
                let noiseX = noise(this.location.x * 0.005, this.location.y * 0.005);
                let noiseY = noise(this.location.y * 0.005, this.location.x * 0.005);
                this.velocity.x = map(noiseX, 0, 1, -0.5, 0.5);
                this.velocity.y = map(noiseY, 0, 1, -0.5, 0.5);
                this.location.add(this.velocity);

                // Check if the particle is out of the text area
                if(list[int((this.location.y + this.velocity.y) * width + int(this.location.x + this.velocity.x))] == 1) {
                    this.velocity.mult(-1);
                }
            }

            display() {
                ellipse(this.location.x, this.location.y, this.radius, this.radius);
            }
        }
    </script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
</head>
<body>
    <script>
        const MAX = 1000;
        let particles = [];
        let list = [];
        let axis;
        let count = 0;
        let typedText = 'Macro';
        let inputText = [];
        let graphics;

        function setup() {
            createCanvas(1200, 600);
            colorMode(RGB, 255, 255, 255);
            frameRate(30);
            noStroke();
            noCursor();

            graphics = createGraphics(width, height);
            graphics.textFont("Arial", 300);
            graphics.fill(0);
            graphics.textAlign(CENTER, CENTER);
            graphics.text(typedText, width / 2, height / 2 - 70);
            typedText = "";
            inputText = [];

            count = 0;
            list = new Array(width * height);

            graphics.loadPixels();

            for(let y = 0; y <= height - 1; y++) {
                for(let x = 0; x <= width - 1; x++) {
                    let index = (x + y * graphics.width) * 4;
                    if(graphics.pixels[index] < 128) {  
                        list[y * width + x] = 0;  
                    } else {  
                        list[y * width + x] = 1;  
                    }
                }
            }

            graphics.updatePixels();
            particles = [];
        }

        function draw() {
            if (count < MAX) {
                let i = 0;

                while(i < 3) {
                    axis = createVector(int(random(100, width - 300)), int(random(100, height - 300)));
                    if(list[int(axis.y * width + axis.x)] == 0) {
                        particles.push(new Particle(axis.x, axis.y));
                        i++;
                        count++;
                    }
                }
            }
            background(239);
            for (let i = 0; i < particles.length; i++) {
                let p = particles[i];
                fill(20);
                p.display();
                p.update();
            }
        }

        function keyReleased() {
            if (keyCode == ENTER) {
                typedText = inputText.join('');
                setup();
            } else {
                inputText.push(key);
            }
        }

        class Particle {
            constructor(x, y) {
                this.location = createVector(x, y);
                this.velocity = createVector(0, 0);
                this.scale = random(0.35, 0.9);
                this.radius = this.scale * 45;
                this.border = 15;
            }

            update() {
                let noiseX = noise(this.location.x * 0.005, this.location.y * 0.005);
                let noiseY = noise(this.location.y * 0.005, this.location.x * 0.005);
                this.velocity.x = map(noiseX, 0, 1, -0.5, 0.5);
                this.velocity.y = map(noiseY, 0, 1, -0.5, 0.5);
                this.location.add(this.velocity);

                // Check if the particle is out of the text area
                if(list[int((this.location.y + this.velocity.y) * width + int(this.location.x + this.velocity.x))] == 1) {
                    this.velocity.mult(-1);
                }
            }

            display() {
                ellipse(this.location.x, this.location.y, this.radius, this.radius);
            }
        }
    </script>
</body>
</html>

I've tried various methods using the above images, but I'm frustrated because I don't know the specific name of the effect. I would appreciate it if you could give me as much advice as possible.

1

There are 1 best solutions below

0
Lecrte On

I think that effect is referred to as 'metaballs' https://en.wikipedia.org/wiki/Metaballs

David Schiffman did a Coding Train episode on it which might be worth checking out: https://www.youtube.com/watch?v=ccYLb7cLB1I

Regarding plotting points along text, I would recommend taking a look at textToPoints() in the p5.js reference https://p5js.org/reference/#/p5.Font/textToPoints

That will return an array of points for given text and allow you to create particles a bit more efficiently than creating random points and testing against a drawn-text background (which is the approach in the HTML snippet you posted).

With that said, I took a look through the HTML snippet and noticed two issues:

  1. Background on the graphics wasn't set to a non-black value
  2. The axis test points were a bit too limited (with hardcoded 100 and 300 pixel margins)

This codepen includes some optional fixes for those two issues: https://codepen.io/lecrte/pen/GRzmaeG?editors=0010