Where ideas percolate and thoughts brew

The Effort Trap

About This Sketch

Three paths, same starting point, same goal. One moves directly, efficiently closing the distance. Another wanders but progresses. The third thrashes randomly, expending massive effort while barely advancing.

The sketch visualizes a fundamental truth about work: effort is a multiplier on direction. The high-efficiency path reaches the goal with minimal steps. The low-efficiency path burns 10x the energy and still fails. All three "work hard" but only direction determines results.

Watch the wasted-effort path (red/orange) meander aimlessly despite constant movement. Every step costs energy, but random direction means zero progress. This is what grinding without strategy looks like—motion mistaken for progress, busyness confused with productivity.

The smart-work path (golden) isn't lucky or talented. It continuously corrects course toward the goal. Same effort, better direction, exponentially better results. This is what working smart looks like—ruthless efficiency about where energy goes.

Algorithm

This sketch visualizes the relationship between effort and direction through three animated paths moving toward a goal. Three paths start from the left side, each with different "efficiency" values that determine how directly they move toward the goal. The high-efficiency path (smart work) moves almost straight toward the target. The medium-efficiency path (busy work) wanders somewhat but generally progresses. The low-efficiency path (wasted effort) meanders significantly and may never reach the goal. Each path tracks both effort (total steps taken) and progress (distance covered toward the goal). The visual demonstrates that equal effort produces vastly different results depending on direction. The smart-work path reaches the goal quickly with minimal wandering. The wasted-effort path expends massive energy while making little progress. This accompanies the blog post "The Effort Trap" which argues that effort without proper direction is worse than no effort at all.

Pseudocode

SETUP:
  Create canvas (400x300)
  Initialize three paths with different efficiency values:
    - High efficiency (0.9): Direct path
    - Medium efficiency (0.5): Somewhat wandering
    - Low efficiency (0.1): Very wandering

FOR each path:
  INITIALIZE:
    - Starting position (left side)
    - Initial direction (toward goal)
    - Efficiency parameter (0-1)
    - Target (right side, center)

DRAW (every frame):
  Get current theme colors
  Clear background

  Draw goal indicator (concentric circles at target)

  FOR each active path:
    UPDATE:
      Calculate ideal direction toward goal
      Blend current direction with ideal based on efficiency
      Add random wobble inversely proportional to efficiency
      Move in current direction
      Track effort (increment step counter)
      Calculate progress (distance to goal)
      Check if reached goal or exhausted effort

    DRAW:
      Choose color based on efficiency level
      Draw path as connected line segments
      Show current position if still active
      Show success/failure indicator if finished

  Draw labels and legend

  IF all paths finished AND sufficient time passed:
    Reset animation with new paths

Source Code

let sketch = function(p) {
    let paths = [];
    let currentPath = 0;

    class Path {
        constructor(startX, startY, direction, efficiency) {
            this.points = [{x: startX, y: startY}];
            this.direction = direction; // angle in radians
            this.efficiency = efficiency; // how direct the path is (0-1)
            this.effort = 0; // total effort expended
            this.progress = 0; // actual progress toward goal
            this.color = null;
            this.active = true;
            this.targetX = 350; // goal is right side
            this.targetY = 150; // goal is middle
            this.wobble = p.random(0.1, 0.3); // how much the path wanders
        }

        update() {
            if (!this.active) return;

            let last = this.points[this.points.length - 1];

            // Calculate ideal direction toward goal
            let idealAngle = p.atan2(this.targetY - last.y, this.targetX - last.x);

            // Blend current direction with ideal direction based on efficiency
            this.direction = p.lerp(
                this.direction + p.random(-this.wobble, this.wobble),
                idealAngle,
                this.efficiency
            );

            // Move in current direction
            let stepSize = 3;
            let newX = last.x + p.cos(this.direction) * stepSize;
            let newY = last.y + p.sin(this.direction) * stepSize;

            // Constrain to canvas
            newX = p.constrain(newX, 10, 390);
            newY = p.constrain(newY, 60, 240);

            this.points.push({x: newX, y: newY});

            // Track effort (every step costs effort)
            this.effort += 1;

            // Track progress (distance toward goal)
            let distToGoal = p.dist(newX, newY, this.targetX, this.targetY);
            let startDist = p.dist(this.points[0].x, this.points[0].y, this.targetX, this.targetY);
            this.progress = p.map(distToGoal, startDist, 0, 0, 100);

            // Stop if reached goal or hit edge repeatedly
            if (distToGoal < 20 || this.effort > 200) {
                this.active = false;
            }
        }

        draw(colors) {
            // Color based on efficiency
            let pathColor;
            if (this.efficiency > 0.7) {
                pathColor = colors.accent1; // Good direction
            } else if (this.efficiency > 0.3) {
                pathColor = colors.accent3; // Neutral
            } else {
                pathColor = colors.accent2; // Bad direction
            }

            // Draw path
            p.noFill();
            p.stroke(...pathColor, 150);
            p.strokeWeight(2);
            p.beginShape();
            for (let pt of this.points) {
                p.vertex(pt.x, pt.y);
            }
            p.endShape();

            // Draw current position
            if (this.active) {
                let last = this.points[this.points.length - 1];
                p.fill(...pathColor, 200);
                p.noStroke();
                p.circle(last.x, last.y, 6);
            }

            // Draw endpoint if finished
            if (!this.active) {
                let last = this.points[this.points.length - 1];
                let distToGoal = p.dist(last.x, last.y, this.targetX, this.targetY);

                if (distToGoal < 20) {
                    // Success - reached goal
                    p.fill(...pathColor, 150);
                    p.noStroke();
                    p.circle(last.x, last.y, 12);
                } else {
                    // Failed - gave up
                    p.stroke(...pathColor, 100);
                    p.strokeWeight(2);
                    p.noFill();
                    p.circle(last.x, last.y, 8);
                    p.line(last.x - 4, last.y - 4, last.x + 4, last.y + 4);
                    p.line(last.x - 4, last.y + 4, last.x + 4, last.y - 4);
                }
            }
        }
    }

    p.setup = function() {
        p.createCanvas(400, 300);
        p.colorMode(p.RGB);

        // Create three paths with different efficiencies
        // High efficiency - direct path
        paths.push(new Path(50, 100, 0, 0.9));

        // Medium efficiency - somewhat wandering
        paths.push(new Path(50, 150, 0, 0.5));

        // Low efficiency - very wandering
        paths.push(new Path(50, 200, 0, 0.1));
    };

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

        // Draw goal
        p.fill(...colors.accent1, 50);
        p.noStroke();
        p.circle(350, 150, 30);
        p.fill(...colors.accent1, 100);
        p.circle(350, 150, 20);
        p.fill(...colors.accent1, 200);
        p.circle(350, 150, 8);

        // Update and draw all paths
        for (let path of paths) {
            path.update();
            path.draw(colors);
        }

        // Draw labels
        p.fill(...colors.accent3);
        p.noStroke();
        p.textAlign(p.LEFT, p.CENTER);
        p.textSize(9);

        p.text("Start", 10, 150);
        p.text("Goal", 360, 150);

        // Draw title and legend
        p.textAlign(p.CENTER, p.TOP);
        p.textSize(11);
        p.fill(...colors.accent3);
        p.text("Effort × Direction = Results", 200, 15);

        p.textSize(8);
        p.textAlign(p.LEFT, p.TOP);
        p.fill(...colors.accent1);
        p.text("High Efficiency: Smart Work", 20, 35);
        p.fill(...colors.accent3);
        p.text("Medium Efficiency: Busy Work", 20, 47);
        p.fill(...colors.accent2);
        p.text("Low Efficiency: Wasted Effort", 20, 59);

        // Check if all paths are done, restart animation
        let allDone = paths.every(p => !p.active);
        if (allDone && p.frameCount > 180) {
            paths = [];
            paths.push(new Path(50, 100, 0, 0.9));
            paths.push(new Path(50, 150, 0, 0.5));
            paths.push(new Path(50, 200, 0, 0.1));
        }
    };
};