Neoplastic Liquidity

📅 April 17, 2026 🏷️ art
de-stijl generative-art perlin-noise mondrian fluidity minimalism abstract-geo
Generated by GridFlow AI | Tags: de-stijl, generative-art, perlin-noise, mondrian, fluidity, minimalism, abstract-geo

📊 视觉感受量化评分

0
0
0
0

💡 AI 提示词

Create a p5.js artwork that combines the rigid aesthetic of De Stijl (Mondrian) with fluid dynamics. Use recursive subdivision to create a grid of primary colored rectangles, then warp their edges using Perlin noise to make them feel like they are floating or melting in liquid.

🧠 核心算法要点

  • Initialize a color palette containing Red, Blue, Yellow, White, and Black.
  • Use a recursive subdivision function to split the canvas into non-uniform rectangles.
  • Store rectangle coordinates and randomly assigned colors in an array of objects.
  • Implement a vertex-warping function that samples Perlin noise along the edges of each rectangle.
  • Use a time-based variable to animate the noise offset, creating a shimmering fluid effect.
  • Draw each shape using beginShape() and endShape() to allow for non-linear, wavy boundaries.
  • Handle window resizing by recalibrating the canvas and re-generating the subdivision grid.

💻 原始 p5.js 代码

var sketch = function(p) {
    let blocks = [];
    let colors;
    let noiseScale = 0.005;
    let time = 0;

    p.setup = function() {
        let container = document.getElementById('p5-wrapper'); p.createCanvas(container.offsetWidth, container.offsetHeight).parent('p5-wrapper');
        colors = [
            p.color(225, 30, 40),   // Red
            p.color(30, 80, 160),   // Blue
            p.color(245, 210, 40),  // Yellow
            p.color(255, 255, 255), // White
            p.color(20, 20, 20)     // Black/Dark
        ];
        generateGrid();
        p.noFill();
    };

    p.draw = function() {
        p.background(240);
        time += 0.01;

        for (let block of blocks) {
            drawWavyBlock(block);
        }
    };

    function generateGrid() {
        blocks = [];
        subdivide(0, 0, p.width, p.height, 5);
    }

    function subdivide(x, y, w, h, depth) {
        if (depth > 0 && (p.random() > 0.3 || depth > 3)) {
            if (w > h) {
                let split = p.random(0.3, 0.7) * w;
                subdivide(x, y, split, h, depth - 1);
                subdivide(x + split, y, w - split, h, depth - 1);
            } else {
                let split = p.random(0.3, 0.7) * h;
                subdivide(x, y, w, split, depth - 1);
                subdivide(x, y + split, w, h - split, depth - 1);
            }
        } else {
            blocks.push({
                x: x,
                y: y,
                w: w,
                h: h,
                col: p.random(colors),
                weight: p.random([1, 2, 4, 8])
            });
        }
    }

    function drawWavyBlock(b) {
        p.fill(b.col);
        p.stroke(0);
        p.strokeWeight(p.map(p.width, 400, 2000, 2, 8));
        
        let res = 10; // segments per side
        p.beginShape();
        
        // Top edge
        for(let i=0; i<=res; i++) {
            let tx = p.lerp(b.x, b.x + b.w, i/res);
            let ty = b.y + getOffset(tx, b.y);
            p.vertex(tx, ty);
        }
        // Right edge
        for(let i=0; i<=res; i++) {
            let ty = p.lerp(b.y, b.y + b.h, i/res);
            let tx = b.x + b.w + getOffset(b.x + b.w, ty);
            p.vertex(tx, ty);
        }
        // Bottom edge
        for(let i=res; i>=0; i--) {
            let tx = p.lerp(b.x, b.x + b.w, i/res);
            let ty = b.y + b.h + getOffset(tx, b.y + b.h);
            p.vertex(tx, ty);
        }
        // Left edge
        for(let i=res; i>=0; i--) {
            let ty = p.lerp(b.y, b.y + b.h, i/res);
            let tx = b.x + getOffset(b.x, ty);
            p.vertex(tx, ty);
        }
        
        p.endShape(p.CLOSE);
    }

    function getOffset(x, y) {
        let n = p.noise(x * noiseScale, y * noiseScale, time);
        return p.map(n, 0, 1, -25, 25);
    }

    p.windowResized = function() {
        let container = document.getElementById('p5-wrapper'); p.resizeCanvas(container.offsetWidth, container.offsetHeight);
        generateGrid();
    };

    p.mousePressed = function() {
        generateGrid();
    };
}; 
new p5(sketch);

🎨 AI 艺术解读

This piece explores the tension between the strict, dogmatic order of Neoplasticism and the chaotic, organic nature of the physical world. By taking the iconic Mondrian grid and introducing fluid noise, the rigid boundaries of the modernist era begin to melt and breathe. It suggests that even the most structured systems are subject to the erosive and transformative power of time and movement. The interaction allows the viewer to reset the 'structure,' which immediately begins its slow, liquid transformation.

📝 补充说明

  • The strokeWeight is dynamically mapped to the canvas width to maintain visual balance on different screens.
  • Perlin noise is sampled at the vertices of the subdivided rectangles to ensure the 'gaps' between fluid shapes feel somewhat consistent.
  • Recursive depth is capped to prevent performance degradation while ensuring visual complexity.
  • Clicking or tapping the canvas triggers a new subdivision layout, showcasing the variety of the generative algorithm.