Where ideas percolate and thoughts brew

The Question Fetish

About This Sketch

A visualization exploring how we accumulate questions without finding answers. Question marks drift and fade, representing the constant influx of "powerful questions" we encounter. Only rarely does a question convert into a solid answer that builds lasting foundation.

This sketch accompanies the essay "The Question Fetish" about how asking questions has become intellectual theater—a way to seem thoughtful while avoiding the messy work of actually answering anything.

Algorithm

This sketch visualizes the accumulation of unanswered questions versus the rarity of actual answers. Question marks spawn frequently at the top and drift downward, representing how easily we collect questions. Most questions fade out at the bottom (forgotten), never becoming answers. Only a small percentage of questions (8%) have the potential to convert into answers, and even then, it only happens rarely when conditions are met. Answers appear as solid dots that settle at the bottom, building a foundation—persistent and valuable. The visual metaphor shows how questions accumulate without effort, while answers require commitment and are far more scarce. The foundation of answers grows slowly, in stark contrast to the constant flux of questions above.

Pseudocode

SETUP:
  Initialize canvas (400x300)
  Create empty arrays for questions and answers

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

  Spawn new questions frequently (15% chance per frame)

  For each question:
    Move question downward and sideways
    Age the question
    If question reaches bottom, fade it out (forgotten)
    If question is old enough and marked as convertible (8% chance):
      Occasionally convert to answer (0.5% chance per frame)
    Remove dead questions

  For each answer:
    Grow to full size
    Settle at bottom foundation line
    Display with glow effect (persists permanently)

  Draw foundation line for answers
  Display counts: questions asked vs answers found
  Show insight text based on answer count

Source Code

let sketch = function(p) {
    // Visualization: Questions as question marks that multiply and float around
    // Answers as solid dots that occasionally form from questions (rare)
    // Shows accumulation of questions vs. scarcity of answers
    // Questions fade out over time (forgotten), answers persist

    let questions = [];
    let answers = [];
    let time = 0;

    class Question {
        constructor() {
            this.x = p.random(50, 350);
            this.y = p.random(40, 100);
            this.vx = p.random(-0.3, 0.3);
            this.vy = p.random(0.2, 0.5);
            this.opacity = 255;
            this.size = p.random(10, 14);
            this.canConvert = p.random() < 0.08; // Only 8% can become answers
            this.age = 0;
        }

        update() {
            this.x += this.vx;
            this.y += this.vy;
            this.age++;

            // Drift around
            if (this.x < 30 || this.x > 370) this.vx *= -1;
            if (this.y > 240) {
                // Questions fade at the bottom (forgotten)
                this.opacity -= 2;
            }

            // Check if this question can become an answer (rare)
            if (this.canConvert && this.age > 120 && p.random() < 0.005) {
                return 'convert';
            }

            return this.opacity > 0 ? 'alive' : 'dead';
        }

        display(colors) {
            p.fill(...colors.accent3, this.opacity * 0.7);
            p.textAlign(p.CENTER, p.CENTER);
            p.textSize(this.size);
            p.noStroke();
            p.text('?', this.x, this.y);
        }
    }

    class Answer {
        constructor(x, y) {
            this.x = x;
            this.y = y;
            this.targetY = 240;
            this.size = 0;
            this.targetSize = 8;
            this.opacity = 0;
            this.settled = false;
        }

        update() {
            // Grow and settle at the bottom
            this.size = p.lerp(this.size, this.targetSize, 0.1);
            this.opacity = p.min(this.opacity + 5, 255);

            if (!this.settled) {
                this.y = p.lerp(this.y, this.targetY, 0.05);
                if (p.abs(this.y - this.targetY) < 1) {
                    this.settled = true;
                }
            }
        }

        display(colors) {
            p.noStroke();
            p.fill(...colors.accent2, this.opacity);
            p.circle(this.x, this.y, this.size);

            // Glow effect for answers
            p.fill(...colors.accent2, this.opacity * 0.2);
            p.circle(this.x, this.y, this.size * 2);
        }
    }

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

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

        time++;

        // Title
        p.fill(...colors.accent3);
        p.noStroke();
        p.textAlign(p.CENTER);
        p.textSize(12);
        p.text('The Question Fetish', 200, 25);

        // Spawn new questions frequently
        if (p.random() < 0.15) {
            questions.push(new Question());
        }

        // Keep questions count manageable
        if (questions.length > 50) {
            questions.shift();
        }

        // Update questions
        for (let i = questions.length - 1; i >= 0; i--) {
            let status = questions[i].update();

            if (status === 'convert') {
                // Rare: question becomes an answer
                let q = questions[i];
                answers.push(new Answer(q.x, q.y));
                questions.splice(i, 1);
            } else if (status === 'dead') {
                questions.splice(i, 1);
            }
        }

        // Display questions
        for (let q of questions) {
            q.display(colors);
        }

        // Update and display answers
        for (let a of answers) {
            a.update();
            a.display(colors);
        }

        // Draw the answer foundation line
        p.stroke(...colors.accent2, 80);
        p.strokeWeight(2);
        p.line(30, 245, 370, 245);

        // Labels
        p.noStroke();
        p.fill(...colors.accent3, 180);
        p.textSize(8);
        p.textAlign(p.LEFT);
        p.text('Questions accumulate', 30, 270);
        p.text(`${questions.length} asked`, 30, 282);

        p.textAlign(p.RIGHT);
        p.text('Answers are rare', 370, 270);
        p.text(`${answers.length} answered`, 370, 282);

        // Bottom insight
        p.fill(...colors.accent3, 160);
        p.textSize(7);
        p.textAlign(p.CENTER);

        if (answers.length === 0) {
            p.text('Questions multiply effortlessly. Answers require commitment.', 200, 295);
        } else if (answers.length < 3) {
            p.text('One answered question beats a hundred asked ones.', 200, 295);
        } else {
            p.text('Answers build foundation. Questions just accumulate.', 200, 295);
        }
    };
};