Where ideas percolate and thoughts brew

Mimetic vs. Intrinsic Desire

About This Sketch

Two particle systems visualize RenΓ© Girard's mimetic desire against Self-Determination Theory's intrinsic motivation. On the left, particles frantically chase a shared desirability signal that keeps moving β€” reactive, noisy, never settled. On the right, each particle follows its own fixed attractor β€” independent, steady, purposeful. Same energy, different architecture.

Algorithm

Two particle systems side by side, separated by a dividing line. Left (mimetic desire): particles chase a shared pulsing attractor that periodically relocates. A Perlin noise field adds jitter, keeping movement reactive and unsettled. Right (intrinsic desire): each particle has its own fixed private attractor. Particles move steadily toward their unique point and orbit it calmly.

Pseudocode

SETUP:
  Create 18 mimetic particles scattered on left half
  Create 10 intrinsic particles on right half, each with unique attractor
  Randomize initial mimetic target position

DRAW:
  Draw dividing line

  LEFT SIDE (mimetic):
    Decrement target timer; relocate target when timer expires
    Draw pulsing glow around shared target
    For each particle:
      Compute attraction force toward shared target
      Add Perlin noise jitter
      Apply damping, update position
      Constrain to left half

  RIGHT SIDE (intrinsic):
    For each particle:
      Draw faint ring and dot at its private attractor
      Compute steady pull toward own attractor
      Apply damping, update position
      Constrain to right half

  Draw labels

Source Code

let sketch = function(p) {
    const W = 400, H = 300;
    const MID = W / 2;

    let mParticles = [];
    let mTarget = { x: 0, y: 0 };
    let mTargetTimer = 0;
    const M_COUNT = 18;

    let iParticles = [];
    const I_COUNT = 10;

    function moveMimeticTarget() {
        mTarget.x = p.random(40, MID - 40);
        mTarget.y = p.random(50, H - 50);
        mTargetTimer = p.floor(p.random(100, 160));
    }

    function resetMimetic() {
        mParticles = [];
        for (let i = 0; i < M_COUNT; i++) {
            mParticles.push({
                x: p.random(18, MID - 14),
                y: p.random(30, H - 30),
                vx: p.random(-0.5, 0.5),
                vy: p.random(-0.5, 0.5),
                size: p.random(3.5, 6)
            });
        }
        moveMimeticTarget();
    }

    function resetIntrinsic() {
        iParticles = [];
        for (let i = 0; i < I_COUNT; i++) {
            iParticles.push({
                x: p.random(MID + 14, W - 18),
                y: p.random(30, H - 30),
                vx: p.random(-0.4, 0.4),
                vy: p.random(-0.4, 0.4),
                ax: p.random(MID + 30, W - 30),
                ay: p.random(40, H - 40),
                size: p.random(4, 6.5)
            });
        }
    }

    p.setup = function() {
        p.createCanvas(W, H);
        p.colorMode(p.RGB);
        resetMimetic();
        resetIntrinsic();
    };

    p.draw = function() {
        const colors = getThemeColors();
        p.background(...colors.bg);

        let t = p.frameCount * 0.012;

        p.stroke(colors.accent3[0], colors.accent3[1], colors.accent3[2], 45);
        p.strokeWeight(1);
        p.line(MID, 18, MID, H - 18);

        mTargetTimer--;
        if (mTargetTimer <= 0) moveMimeticTarget();

        let pulse = 0.5 + 0.5 * Math.sin(t * 2.5);
        for (let r = 32; r > 4; r -= 7) {
            p.noStroke();
            p.fill(colors.accent2[0], colors.accent2[1], colors.accent2[2],
                   p.map(r, 4, 32, 0, 18 + pulse * 14));
            p.ellipse(mTarget.x, mTarget.y, r * 2, r * 2);
        }
        p.fill(...colors.accent2, 180 + pulse * 60);
        p.noStroke();
        p.ellipse(mTarget.x, mTarget.y, 7 + pulse * 3, 7 + pulse * 3);

        for (let mp of mParticles) {
            let dx = mTarget.x - mp.x;
            let dy = mTarget.y - mp.y;
            let dist = Math.sqrt(dx * dx + dy * dy);
            let force = 0.18 / Math.max(dist, 12);
            mp.vx += dx * force;
            mp.vy += dy * force;
            mp.vx += p.noise(mp.x * 0.03, mp.y * 0.03, t * 0.4) * 0.3 - 0.15;
            mp.vy += p.noise(mp.x * 0.03 + 50, mp.y * 0.03, t * 0.4) * 0.3 - 0.15;
            mp.vx *= 0.88;
            mp.vy *= 0.88;
            mp.x += mp.vx;
            mp.y += mp.vy;
            mp.x = p.constrain(mp.x, 10, MID - 10);
            mp.y = p.constrain(mp.y, 14, H - 14);
            p.fill(colors.accent2[0], colors.accent2[1], colors.accent2[2], 160);
            p.noStroke();
            p.ellipse(mp.x, mp.y, mp.size, mp.size);
        }

        p.noStroke();
        p.fill(colors.accent3[0], colors.accent3[1], colors.accent3[2], 100);
        p.textAlign(p.CENTER);
        p.textSize(8.5);
        p.text("mimetic desire", MID / 2, H - 10);

        for (let ip of iParticles) {
            p.noFill();
            p.stroke(colors.accent1[0], colors.accent1[1], colors.accent1[2], 30);
            p.strokeWeight(1);
            p.ellipse(ip.ax, ip.ay, 20, 20);
            p.fill(...colors.accent1, 120);
            p.noStroke();
            p.ellipse(ip.ax, ip.ay, 5, 5);
        }

        for (let ip of iParticles) {
            let dx = ip.ax - ip.x;
            let dy = ip.ay - ip.y;
            let dist = Math.sqrt(dx * dx + dy * dy);
            let force = 0.12 / Math.max(dist, 10);
            ip.vx += dx * force;
            ip.vy += dy * force;
            ip.vx *= 0.90;
            ip.vy *= 0.90;
            ip.x += ip.vx;
            ip.y += ip.vy;
            ip.x = p.constrain(ip.x, MID + 10, W - 10);
            ip.y = p.constrain(ip.y, 14, H - 14);
            p.fill(colors.accent1[0], colors.accent1[1], colors.accent1[2], 190);
            p.noStroke();
            p.ellipse(ip.x, ip.y, ip.size, ip.size);
        }

        p.noStroke();
        p.fill(colors.accent3[0], colors.accent3[1], colors.accent3[2], 100);
        p.textAlign(p.CENTER);
        p.textSize(8.5);
        p.text("intrinsic desire", MID + (W - MID) / 2, H - 10);
    };
};