Snake Byte
của MusicBar, thanh tiến trình
Con rắn ô vuông kiểu màn hình điện thoại cục gạch uốn qua uốn lại tới chỗ đang phát, bài chạy tới đâu rắn dài tới đó, tới nhịp là thè lưỡi, mấy ô trống phía trước thì nháy theo nhạc.
Cách cài, mã SHA-256 và mã nguồn
Bấm Áp dụng: MusicBar tự tải về, kiểm tra mã SHA-256 rồi mặc lên taskbar; có rồi thì mặc luôn. Cần MusicBar 1.8 trở lên.
SHA-256 29b0ab284de6625a11f07a94b19424c6e407d624633495a88cc32c6cb78259e5
//! name: Snake Byte
//! author: MusicBar
//! kind: progress
//! description: A blocky LCD snake winds back and forth to the playhead, its body as long as the song so far, flicking its tongue on every beat while the empty cells ahead light up with the music.
// The snake's path snakes up one column, over the top, down the next, over the bottom, and so on.
// Step i of the path, as (column, row) with 4 rows; every 5 steps cover 2 columns.
float2 pathCell(float i)
{
float k = floor(i / 5.0), j = i - 5.0 * k;
float up = 1.0 - step(0.25, frac(k * 0.5));
float row = j < 3.5 ? lerp(3.0 - j, j, up) : up * 3.0;
return float2(2.0 * k + step(3.5, j), row);
}
// Which way the path goes after step i, and where it came from.
float2 nextDir(float i)
{
float k = floor(i / 5.0), j = i - 5.0 * k;
float up = 1.0 - step(0.25, frac(k * 0.5));
return j < 2.5 ? float2(0.0, up * 2.0 - 1.0) : float2(1.0, 0.0);
}
float2 prevDir(float i)
{
float k = floor(i / 5.0), j = i - 5.0 * k;
float up = 1.0 - step(0.25, frac(k * 0.5));
return (j < 0.5 || j > 3.5) ? float2(-1.0, 0.0) : float2(0.0, 1.0 - 2.0 * up);
}
float sdBox(float2 p, float2 b) { float2 d = abs(p) - b; return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); }
void layer(inout float3 acc, inout float cover, float3 rgb, float a)
{
a = saturate(a);
acc = rgb * a + acc * (1.0 - a);
cover = a + cover * (1.0 - a);
}
float4 main(float2 uv : TEXCOORD) : COLOR
{
// The LCD grid: 4 rows of square cells, with a quarter cell of margin top and bottom.
float s = size.y / 4.5;
float2 px = float2(uv.x * size.x, rise(uv) * size.y - 0.25 * s);
float2 cell = floor(px / s);
float2 f = px / s - cell - 0.5; // -0.5..0.5 inside the cell
float aa = 1.0 / s;
float inRows = step(0.0, cell.y) * step(cell.y, 3.0);
float headX = progress * size.x;
float3 acc = float3(0, 0, 0);
float cover = 0;
// How long the snake is: the whole path across the bar times the progress.
float total = floor(floor(size.x / s) * 0.5) * 5.0;
float H = floor(progress * total);
// This cell's place on the path (odd columns only hold the turn at the top or bottom).
float k = floor(cell.x * 0.5);
float odd = cell.x - 2.0 * k;
float up = 1.0 - step(0.25, frac(k * 0.5));
float j = odd > 0.5 ? 4.0 : lerp(3.0 - cell.y, cell.y, up);
float onPath = odd > 0.5 ? step(abs(cell.y - up * 3.0), 0.1) : 1.0;
float idx = 5.0 * k + j;
float lit = onPath * step(idx, H) * inRows;
// Unlit cells: a faint ghost grid; ahead of the snake they light up like an equalizer.
float cx = (cell.x + 0.5) * s;
float eq = spectrum(saturate((cx - headX) / max(size.x - headX, 1.0)) * 0.9);
float bar = step(cell.y + 0.5, eq * 4.6) * step(headX + s, cx);
float ghost = smoothstep(aa, -aa, sdBox(f, float2(0.3, 0.3)) - 0.03);
layer(acc, cover, colorB.rgb, ghost * inRows * (1.0 - lit) * (0.18 + 0.32 * bar));
// The body: one square per segment, bridged to its neighbors so it reads as one snake, fading toward the tail.
float2 nd = nextDir(idx), pd = prevDir(idx);
float bulge = saturate(1.0 - abs(idx - (H - (1.0 - beat) * 26.0)) / 1.5) * step(0.05, beat); // a swallow wave on the beat
float g = 0.3 + 0.1 * bulge;
float dSeg = sdBox(f, float2(g, g)) - 0.04;
float dNext = sdBox(f - nd * 0.42, abs(nd) * 0.12 + abs(nd.yx) * 0.2);
float dPrev = sdBox(f - pd * 0.42, abs(pd) * 0.12 + abs(pd.yx) * 0.2);
dNext += 9.0 * (1.0 - step(idx + 1.0, H));
dPrev += 9.0 * (1.0 - step(1.0, idx));
float dBody = min(dSeg, min(dNext, dPrev));
float age = 0.5 + 0.5 * exp(-(H - idx) / 70.0);
float3 skin = colorA.rgb * lerp(1.0, 0.8, step(0.25, frac(idx * 0.5))) * age;
skin = lerp(skin, float3(1, 1, 1), 0.22 * smoothstep(-0.1, -0.3, f.x - f.y) + 0.35 * bulge); // a lit bevel on each square
layer(acc, cover, colorA.rgb * 0.12, lit * smoothstep(aa, -aa, dBody - 1.5 * aa));
layer(acc, cover, skin, lit * smoothstep(aa, -aa, dBody) * (0.55 + 0.45 * age));
// The head at the playhead, seen from above: two eyes facing where it goes, and a forked tongue that flicks on the beat.
float2 hc = (pathCell(H) + 0.5) * s;
float2 hn = nextDir(H);
float2 hq = (px - hc) / s;
float2 side = float2(-hn.y, hn.x);
float along = dot(hq, hn), across = dot(hq, side);
float dHead = sdBox(float2(along + 0.03, across), float2(0.44, 0.4)) - 0.05;
layer(acc, cover, colorA.rgb * 0.12, smoothstep(aa, -aa, dHead - 1.5 * aa));
layer(acc, cover, lerp(colorA.rgb, float3(1, 1, 1), 0.3), smoothstep(aa, -aa, dHead));
float eyes = sdBox(float2(along - 0.14, abs(across) - 0.2), float2(0.09, 0.09));
layer(acc, cover, float3(0.04, 0.07, 0.03), smoothstep(aa, -aa, eyes));
float flick = saturate(beat * 1.6 + step(0.85, frac(time * 0.9)));
float tlen = 0.5 + 0.55 * flick;
float stem = step(0.44, along) * step(along, tlen) * step(abs(across), 0.05);
float forkT = step(tlen - 0.18, along) * step(along, tlen + 0.06) * step(abs(abs(across) - (along - tlen + 0.18) * 0.7), 0.05);
layer(acc, cover, lerp(colorC.rgb, float3(1.0, 0.25, 0.35), 0.6), saturate(stem + forkT) * step(0.05, flick));
// Food a few cells ahead, blinking.
float F = (floor(H / 9.0) + 1.0) * 9.0 + 3.0;
float2 fq = (px - (pathCell(F) + 0.5) * s) / s;
float plus = min(sdBox(fq, float2(0.3, 0.1)), sdBox(fq, float2(0.1, 0.3)));
float blink = step(0.35, frac(time * 2.2));
layer(acc, cover, colorC.rgb, exp(-max(length(fq) - 0.2, 0.0) / 0.25) * 0.35 * blink);
layer(acc, cover, lerp(colorC.rgb, float3(1, 1, 1), 0.3 * beat), smoothstep(aa, -aa, plus) * blink);
return paint(acc / max(cover, 0.001), cover);
}