Where ideas percolate and thoughts brew

The Retention Illusion

About This Sketch

A neural pathway visualization comparing passive exposure (reading, highlighting) to active retrieval (testing, spaced practice). Watch as exposure pathways fade rapidly while retrieval pathways strengthen through spaced reinforcement—a visual representation of the science of learning.

Algorithm

This sketch visualizes the forgetting curve and retention strength of two different learning strategies: passive exposure vs. active retrieval practice. Each horizontal pathway represents a neural connection formed during learning. The pathways are color-coded by strategy: - Orange pathways represent exposure-based learning (reading, highlighting, passive review) - Brown pathways represent retrieval-based learning (testing, spaced repetition) Exposure pathways start bright and strong but decay rapidly over time, mimicking how we quickly forget passively consumed information. Retrieval pathways start dimmer but receive periodic reinforcement (marked with "R") at spaced intervals, simulating retrieval practice. Each retrieval event strengthens the pathway, building more durable retention. Over time, you can observe that retrieval pathways maintain higher average strength while exposure pathways fade away—visualizing the research on effective learning strategies.

Pseudocode

SETUP:
  Initialize empty pathway array
  Set canvas to 400x300

FOR EACH PATHWAY:
  Randomly assign strategy (exposure or retrieval)

  IF exposure:
    Start with high strength (255)
    Set fast decay rate (2.5 per frame)
    No reinforcement events

  IF retrieval:
    Start with medium strength (100)
    Set slow decay rate (0.3 per frame)
    Schedule spaced reinforcement at: 60, 150, 300, 500 frames

EACH FRAME:
  Clear background with theme colors

  FOR EACH PATHWAY:
    Increment age

    IF retrieval pathway AND at reinforcement time:
      Boost strength by 80
      Mark reinforcement event

    Decay strength by decay rate
    Draw neurons as circles
    Draw connections with opacity based on strength
    Display strength percentage

    IF pathway strength too low:
      Remove from array

  Generate new pathway every 80 frames
  Display statistics: count and average strength per strategy
  Show legend explaining visual encoding

Source Code

let sketch = function(p) {
    // Neural pathway simulation showing retention strength
    let pathways = [];
    let maxPathways = 20;
    let time = 0;

    class Pathway {
        constructor(id) {
            this.id = id;
            this.x = p.random(50, 350);
            this.y = 80 + (id % 4) * 50;

            // Two learning strategies
            this.strategy = p.random() > 0.5 ? 'exposure' : 'retrieval';

            // Exposure: bright initially, rapid decay
            // Retrieval: dim initially, slow decay with reinforcement
            if (this.strategy === 'exposure') {
                this.strength = 255;
                this.decayRate = 2.5; // Fast decay
                this.color = 'accent2'; // Orange
                this.reinforcements = [];
            } else {
                this.strength = 100;
                this.decayRate = 0.3; // Slow decay
                this.color = 'accent1'; // Warm brown
                // Spaced retrieval events
                this.reinforcements = [60, 150, 300, 500];
                this.nextReinforcement = 0;
            }

            this.age = 0;
            this.neurons = [];
            this.connections = [];

            // Create neuron chain (simplified pathway)
            let numNeurons = 5;
            for (let i = 0; i < numNeurons; i++) {
                this.neurons.push({
                    x: this.x + i * 20,
                    y: this.y + p.random(-3, 3),
                    size: 6
                });
            }

            // Create connections between neurons
            for (let i = 0; i < numNeurons - 1; i++) {
                this.connections.push({
                    from: i,
                    to: i + 1,
                    strength: this.strength
                });
            }
        }

        update() {
            this.age++;

            // Check for retrieval reinforcement
            if (this.strategy === 'retrieval') {
                if (this.nextReinforcement < this.reinforcements.length) {
                    if (this.age >= this.reinforcements[this.nextReinforcement]) {
                        // Retrieval event - strengthen pathway
                        this.strength = p.min(255, this.strength + 80);
                        this.nextReinforcement++;
                    }
                }
            }

            // Decay over time
            this.strength = p.max(0, this.strength - this.decayRate);

            // Update connection strengths
            for (let conn of this.connections) {
                conn.strength = this.strength;
            }

            return this.age < 600; // Pathway exists for 600 frames
        }

        display(colors) {
            let pathwayColor = this.strategy === 'exposure' ? colors.accent2 : colors.accent1;

            // Draw connections between neurons
            for (let conn of this.connections) {
                let fromNeuron = this.neurons[conn.from];
                let toNeuron = this.neurons[conn.to];

                let opacity = p.map(conn.strength, 0, 255, 0, 200);
                let weight = p.map(conn.strength, 0, 255, 0.5, 3);

                p.stroke(...pathwayColor, opacity);
                p.strokeWeight(weight);
                p.line(fromNeuron.x, fromNeuron.y, toNeuron.x, toNeuron.y);
            }

            // Draw neurons
            for (let neuron of this.neurons) {
                let opacity = p.map(this.strength, 0, 255, 30, 180);
                p.fill(...pathwayColor, opacity);
                p.noStroke();
                p.circle(neuron.x, neuron.y, neuron.size);
            }

            // Draw retrieval markers
            if (this.strategy === 'retrieval') {
                for (let i = 0; i < this.reinforcements.length; i++) {
                    if (this.age >= this.reinforcements[i]) {
                        let markerY = this.y + 15;
                        let markerX = this.x + i * 25;

                        p.fill(...colors.accent1, 150);
                        p.noStroke();
                        p.circle(markerX, markerY, 4);

                        // Little "R" for retrieval
                        p.fill(...colors.accent3, 120);
                        p.textSize(6);
                        p.textAlign(p.CENTER, p.CENTER);
                        p.text('R', markerX, markerY);
                    }
                }
            }

            // Strength indicator
            let strengthPercent = p.floor((this.strength / 255) * 100);
            if (strengthPercent > 5) {
                p.fill(...colors.accent3, 100);
                p.noStroke();
                p.textSize(7);
                p.textAlign(p.LEFT);
                p.text(`${strengthPercent}%`, this.x + 105, this.y);
            }
        }
    }

    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 Retention Illusion', 200, 20);

        // Subtitle
        p.textSize(7);
        p.fill(...colors.accent3, 180);
        p.text('Exposure fades fast. Retrieval builds strength.', 200, 32);

        // Generate new pathways periodically
        if (time % 80 === 0 && pathways.length < maxPathways) {
            pathways.push(new Pathway(pathways.length));
        }

        // Update and display pathways
        for (let i = pathways.length - 1; i >= 0; i--) {
            if (!pathways[i].update()) {
                pathways.splice(i, 1);
            } else {
                pathways[i].display(colors);
            }
        }

        // Count surviving pathways by strategy
        let exposureCount = 0;
        let retrievalCount = 0;
        let exposureAvgStrength = 0;
        let retrievalAvgStrength = 0;

        for (let pathway of pathways) {
            if (pathway.strategy === 'exposure') {
                exposureCount++;
                exposureAvgStrength += pathway.strength;
            } else {
                retrievalCount++;
                retrievalAvgStrength += pathway.strength;
            }
        }

        if (exposureCount > 0) exposureAvgStrength /= exposureCount;
        if (retrievalCount > 0) retrievalAvgStrength /= retrievalCount;

        // Legend
        p.textAlign(p.LEFT);
        p.textSize(8);

        // Exposure learning
        let exposureY = 250;
        p.stroke(...colors.accent2, 200);
        p.strokeWeight(3);
        p.line(15, exposureY, 35, exposureY);
        p.noStroke();
        p.fill(...colors.accent3);
        p.text(`Exposure (${exposureCount})`, 40, exposureY + 3);
        p.textSize(6);
        p.fill(...colors.accent3, 150);
        p.text('Bright initially, rapid decay', 40, exposureY + 11);
        if (exposureCount > 0) {
            p.text(`Avg strength: ${p.floor(exposureAvgStrength)}%`, 40, exposureY + 19);
        }

        // Retrieval learning
        let retrievalY = 275;
        p.stroke(...colors.accent1, 200);
        p.strokeWeight(3);
        p.line(15, retrievalY, 35, retrievalY);
        p.noStroke();
        p.fill(...colors.accent3);
        p.textSize(8);
        p.text(`Retrieval (${retrievalCount})`, 40, retrievalY + 3);
        p.textSize(6);
        p.fill(...colors.accent3, 150);
        p.text('Spaced practice (R), builds strength', 40, retrievalY + 11);
        if (retrievalCount > 0) {
            p.text(`Avg strength: ${p.floor(retrievalAvgStrength)}%`, 40, retrievalY + 19);
        }

        // Dynamic insight
        if (time > 400) {
            p.fill(...colors.accent1, 200);
            p.textAlign(p.CENTER);
            p.textSize(7);
            p.text('Retrieval pathways survive and strengthen', 200, 50);
        }
    };
};