vec3 palette(
    float t,
    float a0, float a1, float a2,
    float b0, float b1, float b2,
    float c0, float c1, float c2,
    float d0, float d1, float d2
) {
    vec3 a = vec3(a0, a1, a2);
    vec3 b = vec3(b0, b1, b2);
    vec3 c = vec3(c0, c1, c2);
    vec3 d = vec3(d0, d1, d2);
    
    return a + b * cos(6.283185 * (c * t + d));
}

// Main shader function: calculates the color for each pixel
void mainImage(out vec4 fragColor, in vec2 fragCoord) 
{
    // Loop over the first three color channels (red, green, blue)
    for (int channelIndex = 0; channelIndex < 3; channelIndex++) {
        // Calculate an offset as 2 times the current channel index.
        // This offset is applied uniformly to both x and y coordinates.
        float channelOffset = float(2 * channelIndex);
        vec2 offsetVector = vec2(channelOffset);

        // Compute the texture coordinate by adding the offset to the fragment coordinate
        // and then dividing by the screen resolution.
        vec2 textureCoord = (fragCoord + offsetVector) / iResolution.xy;

        // Sample the texture at the computed coordinate and take the red component.
        // (This value will be used for the current channel.)
        float redComponent = texture(iChannel0, textureCoord).r;

        // Store the red component in the appropriate channel of the output color.
        fragColor[channelIndex] = redComponent;
    }

    vec3 color = palette(fragColor.x, 
        0.0, -1.0, -1.3, 
        0.184, 1.184, -1.576,
        0.468, 0.636, 3.036, 
        1.136, -0.328, 1.408
    );

    fragColor.x = color.x;
    fragColor.y = color.y;
    fragColor.z = color.z;

    // Set the alpha channel to fully opaque.
    fragColor.a = 1.0;
}