Where ideas percolate and thoughts brew

The Deliberate Practice Myth

About This Sketch

Visualizing the volume vs. "optimal" practice paradox Left: Small, perfect practice sessions (deliberate practice) Right: Large, messy volume (enjoyable practice) Over time, the volume side accumulates far more total progress despite being "inefficient"

This sketch accompanies the blog post "The Deliberate Practice Myth" and visualizes its core concepts through generative art.

Algorithm

Visualizing the volume vs. "optimal" practice paradox Left: Small, perfect practice sessions (deliberate practice) Right: Large, messy volume (enjoyable practice) Over time, the volume side accumulates far more total progress despite being "inefficient" This sketch was originally created as a visual companion to the blog post "The Deliberate Practice Myth" and explores its themes through generative art.

Pseudocode

SETUP:
  Initialize canvas (400x300)
  Set up drawing parameters

DRAW (every frame):
  Get current theme colors
  Clear background
  Draw generative visualization
  Update animation state

Source Code

let sketch = function(p) {

    // Visualizing the volume vs. "optimal" practice paradox
    // Left: Small, perfect practice sessions (deliberate practice)
    // Right: Large, messy volume (enjoyable practice)
    // Over time, the volume side accumulates far more total progress despite being "inefficient"

    let time = 0;
    let leftPractice = []; // Deliberate practice - small, precise
    let rightPractice = []; // Volume practice - large, varied
    let leftTotal = 0;
    let rightTotal = 0;

    class PracticeSession {
        constructor(x, y, size, isDeliberate) {
            this.x = x;
            this.y = y;
            this.size = size;
            this.isDeliberate = isDeliberate;
            this.alpha = 0;
            this.growing = true;
            this.maxAlpha = isDeliberate ? 220 : 160;
            this.wobble = p.random(p.TWO_PI);
            this.value = size; // How much progress this session represents
        }

        update() {
            if (this.growing && this.alpha < this.maxAlpha) {
                this.alpha += 8;
                if (this.alpha >= this.maxAlpha) {
                    this.growing = false;
                }
            } else if (!this.growing) {
                this.alpha -= 2;
            }
        }

        display(colors) {
            if (this.alpha <= 0) return;

            p.noStroke();
            if (this.isDeliberate) {
                // Deliberate practice: small, precise, perfect circles
                p.fill(...colors.accent2, this.alpha);
                p.circle(this.x, this.y, this.size);
            } else {
                // Volume practice: larger, more varied, organic shapes
                p.fill(...colors.accent1, this.alpha);
                // Draw an organic blob instead of perfect circle
                p.beginShape();
                for (let angle = 0; angle < p.TWO_PI; angle += 0.5) {
                    let radius = this.size / 2 + p.sin(angle * 3 + this.wobble) * (this.size * 0.15);
                    let x = this.x + p.cos(angle) * radius;
                    let y = this.y + p.sin(angle) * radius;
                    p.vertex(x, y);
                }
                p.endShape(p.CLOSE);
            }
        }

        isDead() {
            return !this.growing && this.alpha <= 0;
        }
    }

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

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

        // Dividing line
        p.stroke(...colors.accent3, 60);
        p.strokeWeight(1);
        p.line(200, 0, 200, 300);

        // Labels at top
        p.noStroke();
        p.fill(...colors.accent3, 200);
        p.textAlign(p.CENTER, p.TOP);
        p.textSize(11);
        p.text("Deliberate Practice", 100, 15);
        p.text("Volume Practice", 300, 15);

        // Descriptions
        p.textSize(8);
        p.fill(...colors.accent3, 150);
        p.text("30 min/day, efficient", 100, 32);
        p.text("Burns out after 3 months", 100, 43);
        p.text("2 hrs/day, \"inefficient\"", 300, 32);
        p.text("Maintains for years", 300, 43);

        // Practice zones
        p.noStroke();
        p.fill(...colors.accent3, 20);
        p.rect(20, 70, 160, 140);
        p.rect(220, 70, 160, 140);

        // Spawn practice sessions
        // Deliberate practice: small, frequent for a while, then stops
        if (time < 180 && time % 25 === 0) {
            let session = new PracticeSession(
                p.random(40, 160),
                p.random(90, 190),
                p.random(12, 18), // Small size (efficient but short)
                true
            );
            leftPractice.push(session);
            leftTotal += session.value;
        }

        // Volume practice: larger, continues indefinitely
        if (time % 35 === 0) {
            let session = new PracticeSession(
                p.random(240, 360),
                p.random(90, 190),
                p.random(25, 40), // Larger size (more total volume)
                false
            );
            rightPractice.push(session);
            rightTotal += session.value;
        }

        // Update and display left side (deliberate practice)
        for (let i = leftPractice.length - 1; i >= 0; i--) {
            leftPractice[i].update();
            leftPractice[i].display(colors);
            if (leftPractice[i].isDead()) {
                leftPractice.splice(i, 1);
            }
        }

        // Update and display right side (volume practice)
        for (let i = rightPractice.length - 1; i >= 0; i--) {
            rightPractice[i].update();
            rightPractice[i].display(colors);
            if (rightPractice[i].isDead()) {
                rightPractice.splice(i, 1);
            }
        }

        // Progress bars at bottom showing accumulated total
        let barY = 230;
        let barHeight = 12;
        let maxWidth = 160;

        // Left progress bar
        p.noStroke();
        p.fill(...colors.accent3, 60);
        p.rect(20, barY, maxWidth, barHeight, 2);

        let leftProgress = p.min((leftTotal / 800) * maxWidth, maxWidth);
        p.fill(...colors.accent2, 180);
        p.rect(20, barY, leftProgress, barHeight, 2);

        // Right progress bar
        p.fill(...colors.accent3, 60);
        p.rect(220, barY, maxWidth, barHeight, 2);

        let rightProgress = p.min((rightTotal / 800) * maxWidth, maxWidth);
        p.fill(...colors.accent1, 180);
        p.rect(220, barY, rightProgress, barHeight, 2);

        // Progress labels
        p.textAlign(p.CENTER, p.TOP);
        p.textSize(8);
        p.fill(...colors.accent3, 160);
        p.text("Total Progress", 100, 245);
        p.text("Total Progress", 300, 245);

        // Show when deliberate practice stops
        if (time >= 180 && time < 280) {
            let alpha = p.map(p.sin((time - 180) * 0.05), -1, 1, 100, 200);
            p.textAlign(p.CENTER);
            p.textSize(9);
            p.fill(...colors.accent2, alpha);
            p.text("Burned out", 100, 180);
            p.textSize(7);
            p.fill(...colors.accent3, alpha * 0.8);
            p.text("(stopped practicing)", 100, 192);
        }

        // Show volume practice continuing
        if (time > 200) {
            let alpha = p.min((time - 200) * 2, 160);
            p.textAlign(p.CENTER);
            p.textSize(9);
            p.fill(...colors.accent1, alpha);
            p.text("Still going", 300, 180);
            p.textSize(7);
            p.fill(...colors.accent3, alpha);
            p.text("(still enjoying it)", 300, 192);
        }

        // Bottom message
        if (time > 250) {
            p.textAlign(p.CENTER, p.BOTTOM);
            p.textSize(9);
            let msgAlpha = p.min((time - 250) * 2, 160);
            p.fill(...colors.accent3, msgAlpha);
            p.text("Volume beats optimization. Enjoyment enables persistence.", 200, 280);

            p.textSize(8);
            p.fill(...colors.accent2, msgAlpha);
            p.text("The 'efficient' practice stops. The 'wasteful' practice accumulates.", 200, 295);
        }

        // Counter at very top showing time progression
        if (time > 60) {
            p.textAlign(p.LEFT, p.TOP);
            p.textSize(7);
            p.fill(...colors.accent3, 120);
            if (time < 180) {
                p.text("Month " + Math.floor(time / 60), 15, 8);
            } else {
                p.text("Month " + Math.floor(time / 60) + " (deliberate stopped at month 3)", 15, 8);
            }
        }

        time++;

        // Loop for demonstration
        if (time > 600) {
            time = 0;
            leftPractice = [];
            rightPractice = [];
            leftTotal = 0;
            rightTotal = 0;
        }
    };
};