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;
}
};
};