Blossom Branch
by MusicBar, progress bar
A gnarled Tet branch grows to the playhead and bursts into five-petal blossoms, petals drift off on the breeze with a flurry on every beat, and a yellow palette turns the peach blossom into apricot blossom.
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 c7dd314bea8cedb7adad7a45d3911dfe72b9ad7e095b3ca4935c8c43dbac38d9
//! name: Blossom Branch
//! author: MusicBar
//! kind: progress
//! description: A gnarled Tet branch grows to the playhead and bursts into five-petal blossoms, with petals drifting off on the breeze and a flurry on every beat.
// A steady random number for a cell.
float hash1(float n) { n = frac(n * 0.1031); n *= n + 33.33; n *= n + n; return frac(n); }
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);
}
float2 rot(float2 p, float a)
{
float c = cos(a);
float s = sin(a);
return float2(c * p.x + s * p.y, -s * p.x + c * p.y);
}
// The branch's height along the bar: slow bends plus angular kinks so it looks gnarled.
float branchY(float x, float u)
{
float k = abs(frac(x / (u * 1.7)) - 0.5) * 4.0 - 1.0;
return u * (0.42 + 0.11 * sin(x / u * 0.75 + 0.5) + 0.05 * sin(x / u * 2.1 + 1.3) + 0.045 * k);
}
// Distance to a twig from a to b that thins toward its tip.
float twig(float2 p, float2 a, float2 b, float r0, float r1)
{
float2 pa = p - a;
float2 ba = b - a;
float h = saturate(dot(pa, ba) / max(dot(ba, ba), 0.001));
return length(pa - ba * h) - lerp(r0, r1, h);
}
// One blossom: five round petals with a notch at each tip, opening from a bud as open goes 0 to 1.
void blossom(inout float3 acc, inout float cover, float2 p, float R, float open, float spin)
{
float2 q = rot(p, spin);
float r = length(q);
float a = atan2(q.y, q.x);
float k = floor(a / 1.2566 + 0.5);
float pa = a - k * 1.2566;
float2 pq = r * float2(cos(pa), sin(pa));
float pr = R * lerp(0.17, 0.5, open);
float pc = R * lerp(0.08, 0.5, open);
float d = max(length(pq - float2(pc, 0)) - pr, R * 0.09 - length(pq - float2(pc + pr * 1.02, 0)));
float body = smoothstep(0.6, -0.6, d);
float3 c = lerp(colorA.rgb * lerp(0.7, 0.85, open), lerp(colorB.rgb, float3(1, 1, 1), 0.3), smoothstep(0.1, 1.0, r / R) * open);
c += float3(1, 1, 1) * smoothstep(R * 0.1, 0.0, length(q - float2(-0.08, 0.1) * R)) * (1.0 - open) * 0.6;
c *= 1.0 - 0.3 * smoothstep(R * 0.03, 0.0, abs(abs(pa) - 0.6283) * r) * step(R * 0.25, r) * open;
c *= 1.0 - 0.25 * smoothstep(-2.0, 0.0, d);
layer(acc, cover, c, body);
// The heart: a colorC center ringed with tiny stamen dots.
float sa = frac(a / 0.6283) - 0.5;
float stamen = smoothstep(R * 0.07, R * 0.03, length(float2(sa * 0.6283 * r, r - R * 0.3)));
float heart = smoothstep(R * 0.17, R * 0.1, r);
layer(acc, cover, lerp(colorC.rgb, float3(1, 1, 1), 0.2), (heart * 0.9 + stamen) * smoothstep(0.35, 0.7, open));
}
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 sway = sin(time * 1.4) * u * 0.03 * (1.0 + level); // the young end sways in the breeze
float3 acc = float3(0, 0, 0);
float cover = 0;
// The main branch, thick and old at the start, thin at the growing tip.
float by = branchY(px.x, u) + sway * exp(-max(head - px.x, 0.0) / (u * 2.0));
float slope = (branchY(px.x + 1.0, u) - branchY(px.x - 1.0, u)) * 0.5;
float th = u * (0.028 + 0.05 * saturate((head - px.x) / (u * 7.0)));
float2 tipP = float2(head, branchY(head, u) + sway);
float bd = px.x > head ? length(px - tipP) - u * 0.028 : abs(px.y - by) / sqrt(1.0 + slope * slope) - th;
// Ahead of the playhead a faint dotted ghost of the branch to come; behind it a soft blossom glow.
float ghost = smoothstep(1.2, 0.2, abs(px.y - by)) * step(head + u * 0.3, px.x) * step(frac(px.x / (u * 0.18)), 0.5);
layer(acc, cover, lerp(colorA.rgb, float3(1, 1, 1), 0.3), ghost * 0.22);
float glow = exp(-abs(px.y - by) / (u * 0.25)) * smoothstep(head + u * 0.4, head - u * 0.6, px.x);
layer(acc, cover, colorA.rgb, glow * (0.1 + 0.12 * level));
// Twigs: one per cell, reaching forward and up or down from the branch, each tipped with a flower.
float cw = u * 1.15;
float cell = floor(px.x / cw);
float twigD = 1e4;
float2 tips[2]; // each twig's tip and how open its flower is
float tipOpen[2];
[unroll] for (int i = 0; i < 2; i++)
{
float k = cell - i;
float x0 = (k + 0.15 + 0.5 * hash1(k * 3.3)) * cw;
float grow = saturate((head - x0) / (u * 1.2));
float ang = (0.55 + 0.45 * hash1(k * 1.9)) * (hash1(k * 7.7 + 1.0) < 0.55 ? 1.0 : -1.0);
float len = u * (0.28 + 0.16 * hash1(k * 5.1)) * grow;
float2 a0 = float2(x0, branchY(x0, u) + sway * exp(-max(head - x0, 0.0) / (u * 2.0)));
tips[i] = a0 + float2(cos(ang), sin(ang)) * len;
twigD = min(twigD, twig(px, a0, tips[i], u * 0.03, u * 0.012) + step(grow, 0.0) * 1e4);
tipOpen[i] = saturate((head - x0) / (u * 2.5) - 0.3) * step(u * 0.05, len);
}
// The bark: dark wood with a warm rim of light along the top and fine grain.
float wood = min(bd, twigD);
float woodA = smoothstep(0.6, -0.6, wood);
float grain = 0.85 + 0.15 * sin(px.x / u * 40.0 + sin(px.y / u * 9.0) * 2.0);
float rimLit = smoothstep(-th * 0.2, th * 1.2, px.y - by) * step(bd, twigD);
layer(acc, cover, float3(0.2, 0.12, 0.09) * grain + float3(0.35, 0.22, 0.15) * rimLit, woodA);
layer(acc, cover, float3(0.75, 0.55, 0.42), smoothstep(1.0, 0.0, abs(wood + 0.6)) * 0.45 * woodA);
// Blossoms along the branch: newest near the tip are still buds, older ones wide open,
// breathing a little with the music.
float fw = u * 0.6;
float fc = floor(px.x / fw);
float pulse = 1.0 + 0.1 * level + 0.12 * beat;
[unroll] for (int j = -1; j <= 1; j++)
{
float k = fc + j;
float h = hash1(k * 4.1 + 2.0);
float fx = (k + 0.2 + 0.6 * hash1(k * 9.3)) * fw;
float side = (frac(k * 0.5) < 0.25 ? 1.0 : -1.0) * (0.06 + 0.12 * hash1(k * 6.7));
float2 fp = float2(fx, branchY(fx, u) + sway * exp(-max(head - fx, 0.0) / (u * 2.0)) + side * u);
float R = u * (0.17 + 0.06 * hash1(k * 2.3)) * pulse;
if (h < 0.78 && fx < head - u * 0.05) blossom(acc, cover, px - fp, R, saturate((head - fx) / (u * 2.2) - 0.15), h * 6.28 + time * 0.1);
}
if (tipOpen[0] > 0.0) blossom(acc, cover, px - tips[0], u * 0.18 * pulse, tipOpen[0], cell);
if (tipOpen[1] > 0.0) blossom(acc, cover, px - tips[1], u * 0.18 * pulse, tipOpen[1], cell + 2.0);
// The growing tip carries a fat bud that swells and glows on the beat.
float2 budP = tipP + float2(u * 0.07, u * 0.01);
float2 bq = rot(px - budP, 0.25);
layer(acc, cover, colorC.rgb, exp(-length(px - budP) / (u * 0.12)) * (0.25 + 0.45 * beat));
float3 budC = colorA.rgb * 0.8 + smoothstep(u * 0.04, 0.0, length(bq - float2(u * 0.01, u * 0.03))) * 0.5;
layer(acc, cover, budC, smoothstep(0.6, -0.6, length(float2(bq.x * 0.75, bq.y)) - u * (0.065 + 0.02 * beat)));
layer(acc, cover, float3(0.25, 0.32, 0.12), smoothstep(0.6, -0.6, length(px - tipP - float2(u * 0.02, 0.0)) - u * 0.035));
// Petals let go and drift back and down; more of them fly when the music is loud or on the beat.
float2 dp = px + float2(time * u * 0.55, time * u * 0.22);
dp.y += sin(dp.x / u * 1.3 + time) * u * 0.08;
float2 dc = floor(dp / (u * 0.55));
float dh = hash1(dc.x * 13.7 + dc.y * 3.1);
float2 dq = dp - (dc + 0.25 + 0.5 * float2(hash1(dc.x + dc.y * 7.0), hash1(dc.y * 3.0 - dc.x))) * u * 0.55;
dq = rot(dq, time * (1.0 + 2.0 * dh) + dh * 6.0);
dq.x /= max(abs(cos(time * 2.0 + dh * 9.0)), 0.3);
float petal = smoothstep(0.6, -0.6, length(float2(dq.x * 0.8, dq.y * 1.4)) - u * 0.055);
float drift = step(dh, 0.12 + 0.25 * level + 0.45 * beat) * smoothstep(head + u * 0.4, head - u * 0.4, px.x);
layer(acc, cover, lerp(colorA.rgb, colorB.rgb, 0.5 + 0.4 * dq.y / (u * 0.05)), petal * drift * 0.9);
return paint(acc / max(cover, 0.001), cover);
}