Funny shader for https://github.com/markusfisch/ShaderEditor
#version 300 es

#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
out vec4 fragColor;

#define RADIUS .45
#define SIZE .01
#define TIME_STEP .01
#define CHAIN_LEN 11.
#define FADE_FACTOR 5.
#define FADE_TIME 2.
#define ENABLE_FADE 1.
#define ENABLE_NOTIF 1.

vec2 pos(float time) {
    return vec2(sin(.7 * time) * cos(time), sin(.3 * time) * sin(time)) * RADIUS + .5;
}
uniform vec2 resolution;
uniform float time;
uniform float startRandom;
uniform int notificationCount;
uniform float battery;
#define COL .157 // 0x28/0xff
#define COL_RANGE .843
#define RAND_RANGE 62.8318530718 // 20PI
void main() {
    vec2 uv = gl_FragCoord.xy / resolution.xy;
    float sides = resolution.y / resolution.x;
    uv.y *= sides;
    lowp vec3 color = vec3(0., COL, COL);
    float fade_progress = smoothstep(0., FADE_TIME * step(1., ENABLE_FADE), time);
    float size = (FADE_FACTOR - (FADE_FACTOR - 1.) * fade_progress) * SIZE * SIZE;
    for (int n = 0; n < min(notificationCount, 10) * int(step(1., ENABLE_NOTIF)); n++) {
        float snake_dist = 2. * float(n) * CHAIN_LEN * TIME_STEP;
        for (float i = 0.; i < CHAIN_LEN; i++) {
            float pos_time = (time + startRandom * RAND_RANGE - i * TIME_STEP - snake_dist) / (battery + .1);
            vec2 circ = pos(pos_time);
            circ.y *= sides;
            vec2 dist = circ - uv;
            float col_val = step(dot(dist, dist), size);
            col_val *= 1. - i / CHAIN_LEN;
            col_val *= COL_RANGE;
            color.yz += step(color.y, col_val) * col_val;
        }
    }
    fragColor = vec4(color, 1.);
}