Paw Trail
by MusicBar, progress bar
A little cat trots to the playhead leaving a trail of paw prints that fade behind it, and on every beat it hops and a heart pops up.
How it installs, its SHA-256 and its code
Click Apply: MusicBar downloads it, checks its SHA-256 and puts it on the taskbar, or just puts it on if it already has it. Needs MusicBar 1.8 or newer.
SHA-256 94d39cf30cdad24dcb0da6af34a1bad1029b72c76f4bc263ee8b4ff265a2c78f
//! name: Paw Trail
//! author: MusicBar
//! kind: progress
//! description: A little cat trots to the playhead leaving a trail of paw prints that fade behind it, and on every beat it hops and a heart pops up.
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);
}
// Smooth minimum: melts the head into the body so there is a neck.
float smin(float a, float b, float k) { float h = saturate(0.5 + 0.5 * (b - a) / k); return lerp(b, a, h) - k * h * (1.0 - h); }
// Distance to a capsule from a to b with radius r.
float capsule(float2 p, float2 a, float2 b, float r)
{
float2 pa = p - a;
float2 ba = b - a;
return length(pa - ba * saturate(dot(pa, ba) / dot(ba, ba))) - r;
}
// Distance to a triangle (negative inside).
float tri(float2 p, float2 p0, float2 p1, float2 p2)
{
float2 e0 = p1 - p0, e1 = p2 - p1, e2 = p0 - p2;
float2 v0 = p - p0, v1 = p - p1, v2 = p - p2;
float2 q0 = v0 - e0 * saturate(dot(v0, e0) / dot(e0, e0));
float2 q1 = v1 - e1 * saturate(dot(v1, e1) / dot(e1, e1));
float2 q2 = v2 - e2 * saturate(dot(v2, e2) / dot(e2, e2));
float s = sign(e0.x * e2.y - e0.y * e2.x);
float2 d = min(min(float2(dot(q0, q0), s * (v0.x * e0.y - v0.y * e0.x)), float2(dot(q1, q1), s * (v1.x * e1.y - v1.y * e1.x))), float2(dot(q2, q2), s * (v2.x * e2.y - v2.y * e2.x)));
return -sqrt(d.x) * sign(d.y);
}
// One leg: hip to paw with a bend, the paw lifting while it swings forward.
float leg(float2 p, float2 hip, float phase, float bendX, float r)
{
float2 paw = float2(hip.x + 0.02 + 0.085 * cos(phase), 0.035 + 0.07 * max(0.0, -sin(phase)));
float2 knee = (hip + paw) * 0.5 + float2(bendX, 0.0);
float d = min(capsule(p, hip, knee, r * 1.25), capsule(p, knee, paw, r));
return min(d, length((p - paw - float2(0.015, -0.005)) / float2(1.0, 0.7)) * 0.7 - 0.03);
}
// A heart, about one unit tall from its tip at the origin.
float heart(float2 p)
{
p.x = abs(p.x);
float2 a = p - float2(0.25, 0.75);
float2 b = p - 0.5 * max(p.x + p.y, 0.0);
float2 c = p - float2(0.0, 1.0);
return p.y + p.x > 1.0 ? length(a) - 0.3536 : sqrt(min(dot(c, c), dot(b, b))) * sign(p.x - p.y);
}
float4 main(float2 uv : TEXCOORD) : COLOR
{
float2 px = float2(uv.x * size.x, (1.0 - uv.y) * size.y); // pixels: along the bar, and up the screen so gravity holds on a top taskbar too
float u = size.y;
float head = progress * size.x;
float aa = 0.6 / u; // half a pixel, in bar heights
float stepT = time * 9.0;
float hop = 0.17 * 4.0 * beat * (1.0 - beat);
float2 p = (px - float2(head, u * 0.1)) / u - float2(0.0, hop + 0.012 * cos(stepT * 2.0));
float3 acc = float3(0, 0, 0);
float cover = 0;
// The trail: paw prints alternating left and right, toes forward, fading with age and pulsing with the music.
float ps = u * 0.36;
float n = floor(px.x / ps);
float side = frac(n * 0.5) < 0.25 ? 1.0 : -1.0;
float pulse = 1.0 + 0.3 * spectrum(frac(n * 0.618) * 0.5);
float2 pq = (px - float2((n + 0.5) * ps, u * (0.27 + 0.08 * side))) / (u * pulse);
float padD = length(pq * float2(1.15, 0.95)) - 0.055;
float toes = 1e4;
[unroll] for (int t = 0; t < 4; t++)
{
float ang = -0.95 + t * 0.633;
toes = min(toes, length(pq - float2(cos(ang), sin(ang)) * 0.1) - 0.026);
}
float printD = min(padD, toes);
float printA = smoothstep(aa, -aa, printD) * step((n + 0.5) * ps, head - u * 0.75);
float age = saturate((head - px.x) / (u * 16.0));
float3 ink = lerp(colorB.rgb, colorA.rgb, 0.3 + 0.3 * age);
ink = lerp(ink, colorA.rgb * 0.5, smoothstep(-2.5 * aa, 0.0, printD) * 0.7);
layer(acc, cover, ink, printA * lerp(0.92, 0.28, age));
// The rest of the song: a faint dotted path ahead.
float dots = smoothstep(1.3, 0.3, length(float2((frac(px.x / ps) - 0.5) * ps, px.y - u * 0.27)));
layer(acc, cover, lerp(colorB.rgb, colorA.rgb, 0.5), dots * step(head + u * 0.45, px.x) * 0.3);
// The far legs, a shade darker, behind the body.
float farD = min(leg(p, float2(-0.1, 0.27), stepT + 3.1416, 0.012, 0.036), leg(p, float2(-0.38, 0.28), stepT, -0.035, 0.04));
// The cat: body, head, ears, near legs and a curling tail that swishes.
float body = capsule(p, float2(-0.4, 0.3), float2(-0.08, 0.32), 0.12);
float headD = (length((p - float2(0.07, 0.44)) / float2(0.15, 0.13)) - 1.0) * 0.13;
float earB = tri(p, float2(-0.06, 0.52), float2(0.07, 0.55), float2(-0.02, 0.67)) - 0.012;
float earF = tri(p, float2(0.07, 0.55), float2(0.19, 0.52), float2(0.16, 0.66)) - 0.012;
float tail = 1e4;
float2 tp = float2(-0.5, 0.34);
float ta = 2.3;
[unroll] for (int i = 0; i < 4; i++)
{
ta -= 0.42 - 0.28 * sin(time * 3.4 - i * 0.9 + 0.6 * level);
float2 tn = tp + float2(cos(ta), sin(ta)) * 0.1;
tail = min(tail, capsule(p, tp, tn, 0.042 - i * 0.004));
tp = tn;
}
float nearD = min(leg(p, float2(-0.08, 0.27), stepT, 0.012, 0.038), leg(p, float2(-0.4, 0.28), stepT + 3.1416, -0.035, 0.042));
float cat = min(min(smin(body, headD, 0.06), min(earB, earF)), min(tail, nearD));
// A soft light behind the cat so it holds up on a dark taskbar, and a shadow on the ground.
layer(acc, cover, colorA.rgb, exp(-max(min(cat, farD), 0.0) / 0.07) * 0.22 * step(0.0, min(cat, farD)));
layer(acc, cover, float3(0, 0, 0), smoothstep(0.02, -0.02, length((p + float2(0.17, hop + 0.012)) / float2(0.32, 0.035)) - 1.0) * 0.25);
float3 fur = colorA.rgb, outline = colorA.rgb * 0.32;
layer(acc, cover, fur * 0.62, smoothstep(aa, -aa, farD));
layer(acc, cover, outline, smoothstep(aa, -aa, farD) * smoothstep(-2.0 * aa, 0.0, farD) * 0.8);
// Fur shading: lit along the back, a lighter belly and muzzle, tabby stripes across the back.
float belly = smoothstep(0.31, 0.2, p.y) * step(p.x, 0.0) + smoothstep(0.1, 0.17, p.x) * smoothstep(0.47, 0.4, p.y);
float3 c = lerp(fur, lerp(fur, float3(1, 0.97, 0.92), 0.65), saturate(belly));
float stripe = smoothstep(0.24, 0.1, abs(frac(p.x * 7.0 + p.y * 1.8) - 0.5)) * smoothstep(0.35, 0.42, p.y) * step(p.x, 0.0) * step(0.0, tail);
c = lerp(c, fur * 0.68, stripe * 0.8);
c *= 0.88 + 0.22 * smoothstep(0.25, 0.5, p.y);
layer(acc, cover, c, smoothstep(aa, -aa, cat));
// Inner ears, cheek blush, eye (it blinks now and then), nose and whiskers.
float inner = min(tri(p, float2(-0.03, 0.55), float2(0.05, 0.56), float2(-0.015, 0.63)), tri(p, float2(0.1, 0.555), float2(0.17, 0.54), float2(0.155, 0.62)));
layer(acc, cover, lerp(colorC.rgb, float3(1, 0.75, 0.8), 0.5), smoothstep(aa, -aa, inner) * 0.85);
layer(acc, cover, colorC.rgb, smoothstep(0.035, 0.0, length(p - float2(0.11, 0.395))) * 0.45);
float blink = lerp(1.0, 0.15, step(0.95, frac(time * 0.31)));
float eye = length((p - float2(0.135, 0.465)) / float2(0.026, 0.034 * blink)) - 1.0;
layer(acc, cover, float3(0.07, 0.05, 0.05), smoothstep(aa, -aa, eye * 0.028));
layer(acc, cover, float3(1, 1, 1), smoothstep(aa * 1.6, 0.0, length(p - float2(0.142, 0.478)) - 0.006) * blink);
layer(acc, cover, lerp(colorC.rgb, float3(1, 0.6, 0.7), 0.5), smoothstep(aa, -aa, length((p - float2(0.218, 0.43)) / float2(1.0, 0.75)) - 0.018));
float wh = min(capsule(p, float2(0.2, 0.415), float2(0.34, 0.44), 0.0), capsule(p, float2(0.2, 0.405), float2(0.33, 0.38), 0.0));
layer(acc, cover, float3(1, 1, 1), smoothstep(aa * 1.6, 0.0, wh) * 0.7);
layer(acc, cover, outline, smoothstep(aa, -aa, cat) * smoothstep(-2.2 * aa, -0.2 * aa, cat) * 0.85);
// On the beat a heart pops up in front of the face and floats away.
float hs = 0.22 * (0.6 + 0.4 * sqrt(beat));
float2 hq = ((px - float2(head, 0.0)) / u - float2(0.47, 0.4 + 0.2 * (1.0 - beat))) / hs;
float hd = heart(hq) * hs;
float hon = saturate(beat * 3.0);
layer(acc, cover, colorC.rgb, exp(-max(hd, 0.0) / 0.05) * beat * 0.5);
layer(acc, cover, colorC.rgb * 0.45, smoothstep(aa, -aa, hd - 1.6 * aa) * hon);
float3 hc = lerp(colorC.rgb, float3(1, 1, 1), 0.45 * smoothstep(0.03, 0.0, length(hq - float2(-0.22, 0.72)) * hs));
layer(acc, cover, hc, smoothstep(aa, -aa, hd + 0.4 * aa) * hon);
return paint(acc / max(cover, 0.001), cover);
}