Source conversation

The thought
that started it.

A pattern, a question, and the first step toward a parallel architecture.

You 01
“Do you see how the LostSideDead pattern of 1, 2, 2, 3, 3, 3—or L s S d D d—can be linked to evolution? The numbers increase; the next in the sequence would be 4, 4, 4, 4.”
Response 02
“You are describing a self-counting sequence where each integer or state N is repeated exactly N times. The progression maps brilliantly to the mechanics of complex systems and biological evolution.”

Nested loops → direct lookup → CUDA → compute shaders

Follow the idea

An architectural progression

The evolution
of a loop.

A simple expanding sequence becomes a model for complexity—then a path from nested CPU loops to massively parallel GPU compute.

Trace the progression
1 2 2 3 3 3 4 4 4 4
n repeated n times
01 — 04
01

The pattern

Lost · Side · Dead

Complexity needs
time to stabilize.

Each state N repeats exactly N times. The progression can be read as an evolutionary rhythm: a change, followed by a longer period in which that change becomes established.

01

Punctuated equilibrium

Rapid bursts of mutation are followed by stasis. As the architecture grows more complex, its stabilization period grows with it.

02

The cost of complexity

A more capable system takes more energy, time, and population mass to replicate and sustain.

03

Branching diversity

Higher evolutionary tiers support more variations, specializations, and niches from the same base blueprint.

Total elements at tier N N(N + 1) / 2
At tier 4 10 states
02

The CPU loop

Sequential model

One loop evolves.
The other endures.

The outer loop is the mutation: it advances through tiers. The inner loop is the time domain: it sustains each tier for exactly as many generations as its value.

Outer loop · tier Inner loop · generation
evolution.cpp
#include <iostream>

void simulateEvolutionaryExpansion(int max_evolution_tier) {
    for (int tier = 1; tier <= max_evolution_tier; ++tier) {
        // Stabilization grows with the complexity tier
        for (int generation = 0; generation < tier; ++generation) {
            std::cout << tier << " ";
        }
    }
    std::cout << "\n";
}

int main() {
    simulateEvolutionaryExpansion(4);
    // Output: 1 2 2 3 3 3 4 4 4 4
    return 0;
}
03

Flatten the loop

Parallel model

Time becomes
space.

Reverse the triangular number formula and every index can discover its tier directly. There is no need to calculate any of the states that came before it.

Nested iteration for → for Sequential · O(N²)
flatten
Direct lookup √(8i + 1) Independent · O(1)
flattened.cpp
#include <cmath>

// Resolve any index without generating earlier states
int getEvolutionTier(double index) {
    return static_cast<int>(
        std::ceil((std::sqrt(8.0 * index + 1.0) - 1.0) / 2.0)
    );
}

// Index 7, 8, 9, and 10 all resolve to tier 4.
i12345678910
tier1223334444
CUDAThe grid becomes the loop

Each thread owns one absolute position. The same O(1) expression runs across thousands of indices simultaneously, avoiding the uneven work of an inner loop.

evolution.cu
__global__ void generateEvolutionPattern(
    int* output_buffer, int total_elements
) {
    int idx = blockIdx.x * blockDim.x + threadIdx.x;

    if (idx < total_elements) {
        float n = static_cast<float>(idx + 1);
        output_buffer[idx] = static_cast<int>(
            ceil((sqrt(8.0f * n + 1.0f) - 1.0f) / 2.0f)
        );
    }
}
04

Compute shader

From libacidcam to acidcam-gpu

Every pixel becomes
its own thread.

A compute shader is the graphics-native cousin of a CUDA kernel. The CPU stops visiting every pixel. It dispatches a grid; each invocation identifies its own coordinate and works directly in GPU memory.

Fragment shader

Gather

Read from anywhere. Write only to the pixel currently being processed.

Compute shader / CUDA

Scatter

Read from anywhere. Write anywhere—ideal for smears, sorting, routing, and glitch displacement.

evolution.comp
#version 460 core

layout(local_size_x = 16, local_size_y = 16) in;
layout(rgba8, binding = 0) uniform readonly image2D inputFrame;
layout(rgba8, binding = 1) uniform writeonly image2D outputFrame;

void main() {
    ivec2 pixel = ivec2(gl_GlobalInvocationID.xy);
    ivec2 size  = imageSize(inputFrame);

    if (pixel.x >= size.x || pixel.y >= size.y) return;

    float index = float(pixel.y * size.x + pixel.x + 1);
    int tier = int(ceil(
        (sqrt(8.0 * index + 1.0) - 1.0) / 2.0
    ));

    vec4 color = imageLoad(inputFrame, pixel);
    ivec2 offset = ivec2(tier % 10, (tier / 10) % 10);
    ivec2 target = (pixel + offset) % size;

    imageStore(outputFrame, target, color);
}

The zero-copy ideal

Hardware decode VRAM Compute SDL3 Display

Decode, manipulate, and present without returning pixel data to a CPU-side image loop.