The Friction Solution
About This Sketch
A particle system where each particle experiences different levels of friction, demonstrating how resistance affects movement and persistence. Particles with higher friction must continuously apply force to maintain motion, while those with lower friction glide more easily. The visualization explores how friction isn't always the enemyβit creates the conditions for meaningful effort and sustained growth.
Algorithm
This sketch visualizes the concept of friction through a particle system where each particle experiences different levels of resistance.
Particles move through space with varying friction coefficients (0.95 to 0.99), causing some to maintain momentum while others slow down quickly. Higher-friction particles (shown in lighter tones) must work harder to maintain movement, continuously applying small random forces to counteract the resistance. Lower-friction particles glide more easily.
The subtle horizontal waves represent "zones of resistance" - areas where friction would be higher in a physical system. The varying friction levels among particles demonstrate how different amounts of resistance affect movement and persistence.
This sketch accompanies the blog post "The Friction Solution" and explores how resistance (friction) isn't always the enemy - it creates the conditions for meaningful effort and sustained growth. Just as particles with friction must continuously apply force to move, humans build capacity by pushing against resistance.
Pseudocode
SETUP:
Initialize canvas (400x300)
Create particle class with random friction values
Spawn initial set of particles
PARTICLE CLASS:
Properties:
- position (x, y)
- velocity (vx, vy)
- age and maxAge (lifespan)
- friction coefficient (0.95-0.99)
- size
Update:
- Apply friction to velocity (multiply by friction coefficient)
- Add small random force (continuous "effort")
- Constrain maximum speed
- Update position based on velocity
- Bounce off canvas edges
- Increment age
Display:
- Calculate alpha based on age (fade over time)
- Choose color based on friction level
- Draw motion trail (previous positions)
- Draw particle circle
DRAW (every frame):
Get current theme colors
Clear background
Periodically spawn new particles
For each particle:
- Update physics
- Display with trail
- Remove if past maxAge
Draw resistance zone lines (sine waves)
Source Code
let sketch = function(p) {
let particles = [];
let time = 0;
class Particle {
constructor(x, y) {
this.x = x;
this.y = y;
this.vx = p.random(-1, 1);
this.vy = p.random(-1, 1);
this.age = 0;
this.maxAge = p.random(100, 300);
this.size = p.random(2, 6);
this.friction = p.random(0.95, 0.99); // Each particle has different friction
}
update() {
// Apply friction differently to each particle
this.vx *= this.friction;
this.vy *= this.friction;
// Add small random force (the "effort")
this.vx += p.random(-0.1, 0.1);
this.vy += p.random(-0.1, 0.1);
// Constrain velocity
let speed = p.sqrt(this.vx * this.vx + this.vy * this.vy);
if (speed > 3) {
this.vx = (this.vx / speed) * 3;
this.vy = (this.vy / speed) * 3;
}
this.x += this.vx;
this.y += this.vy;
this.age++;
// Bounce off edges
if (this.x < 0 || this.x > 400) this.vx *= -1;
if (this.y < 0 || this.y > 300) this.vy *= -1;
this.x = p.constrain(this.x, 0, 400);
this.y = p.constrain(this.y, 0, 300);
}
display(colors) {
let alpha = p.map(this.age, 0, this.maxAge, 255, 0);
// Color based on friction level - high friction particles are lighter
let frictionAmount = p.map(this.friction, 0.95, 0.99, 0, 1);
let col = frictionAmount > 0.5 ? colors.accent1 : colors.accent2;
p.noStroke();
p.fill(col[0], col[1], col[2], alpha);
// Draw trail
for (let i = 1; i < 4; i++) {
let trailX = this.x - this.vx * i;
let trailY = this.y - this.vy * i;
let trailAlpha = alpha * (1 - i / 4);
p.fill(col[0], col[1], col[2], trailAlpha);
p.circle(trailX, trailY, this.size * (1 - i / 5));
}
p.fill(col[0], col[1], col[2], alpha);
p.circle(this.x, this.y, this.size);
}
isDead() {
return this.age > this.maxAge;
}
}
p.setup = function() {
p.createCanvas(400, 300);
p.colorMode(p.RGB);
// Initialize with some particles
for (let i = 0; i < 30; i++) {
particles.push(new Particle(p.random(400), p.random(300)));
}
};
p.draw = function() {
const colors = getThemeColors();
p.background(...colors.bg);
time++;
// Add new particles periodically
if (time % 10 === 0 && particles.length < 80) {
particles.push(new Particle(p.random(400), p.random(300)));
}
// Update and display particles
for (let i = particles.length - 1; i >= 0; i--) {
particles[i].update();
particles[i].display(colors);
if (particles[i].isDead()) {
particles.splice(i, 1);
}
}
// Draw some "resistance lines" - areas of higher friction
p.stroke(...colors.accent3, 30);
p.strokeWeight(1);
for (let i = 0; i < 5; i++) {
let y = 60 * i + 30;
p.line(0, y + p.sin(time * 0.02 + i) * 10, 400, y + p.sin(time * 0.02 + i) * 10);
}
};
};