Domino Run

by MusicBar, progress bar

A row of glossy dominoes topples up to the playhead, each one landing with a clack of light, the pips glowing with the music and the tiles still standing hopping on the beat.

8 downloads Download file, 6.0 KB
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 c6b14c9e811ffadd3bca2fb913a2c451b83e167b8cf53852807452d122c7e336

//! name: Domino Run
//! author: MusicBar
//! kind: progress
//! description: A row of glossy dominoes topples up to the playhead, each one landing with a clack of light, the pips glowing with the music and the tiles still standing hopping on the beat.

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);
}

float box(float2 p, float2 b, float r)
{
    float2 q = abs(p) - b + r;
    return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - r;
}

// Is the pip at grid spot g (-1..1 each way) shown for a face with n pips, like real dice faces.
float pipOn(float2 g, float n)
{
    float odd = step(0.5, frac(n * 0.5));
    float diag = g.x * g.y;
    float on = (g.x == 0.0 && g.y == 0.0) ? odd : 0.0;
    on += (g.y == 0.0 && g.x != 0.0) ? step(5.5, n) : 0.0;
    on += diag < -0.5 ? step(1.5, n) : 0.0;
    on += diag > 0.5 ? step(3.5, n) : 0.0;
    return on;
}

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 w = u * 0.3;                                        // tile width, height and spacing
    float h = u * 0.62;
    float s = u * 0.58;
    float base = u * 0.1;

    // The chain: tile k is falling (gravity eases it in); each tile behind leans on the next one.
    float k = floor(head / s);
    float f = frac(head / s);
    float b0 = asin((s - w) / h) * f * f;
    float b1 = b0 + asin((s * cos(b0) - w) / h);
    float b2 = b1 + asin((s * cos(b1) - w) / h);
    float b3 = b2 + asin((s * cos(b2) - w) / h);
    float b4 = b3 + asin((s * cos(b3) - w) / h);
    float flat = acos(w / s);

    float3 acc = float3(0, 0, 0);
    float cover = 0;

    // A soft shadow along the ground under the row.
    layer(acc, cover, float3(0, 0, 0), smoothstep(u * 0.08, 0.0, abs(px.y - base + u * 0.01)) * 0.25);

    float cell = floor(px.x / s);
    [unroll] for (int stage = 0; stage < 2; stage++)
    {
        [unroll] for (int i = 0; i < 2; i++)
        {
            float j = cell - i;
            float n = k - j;
            float ang = n < 0.0 ? 0.0 : (n < 1.0 ? b0 : (n < 2.0 ? b1 : (n < 3.0 ? b2 : (n < 4.0 ? b3 : (n < 5.0 ? b4 : flat)))));
            float ahead = step(n, -0.5);
            float hop = ahead * u * 0.1 * beat * exp((n + 2.0) / 4.0) * step(n, -1.5);
            float2 pivot = float2(j * s + w, base + hop);
            float pick = frac(j / 3.0 + 0.01);
            float3 col = pick < 0.33 ? colorA.rgb : (pick < 0.66 ? colorB.rgb : colorC.rgb);
            float light = dot(col, float3(0.3, 0.59, 0.11));
            col *= lerp(1.0, 0.58, ahead);
            float sing = spectrum(frac(j * 0.123) * 0.6);

            if (stage == 0)
            {
                // The tile's depth: a darker slab just behind it, so it reads as a solid block.
                float2 lb = rot(px - pivot - float2(u * 0.04, u * 0.035), -ang) - float2(-w * 0.5, h * 0.5);
                layer(acc, cover, col * 0.42, smoothstep(0.6, -0.6, box(lb, float2(w, h) * 0.5, u * 0.05)));
            }
            else
            {
                float2 lp = rot(px - pivot, -ang) - float2(-w * 0.5, h * 0.5);
                float d = box(lp, float2(w, h) * 0.5, u * 0.05);
                float face = smoothstep(0.6, -0.6, d);

                // Glossy face: lighter toward the top, a bevel along the edge, a sheen across the upper corner.
                float3 c = col * (0.78 + 0.32 * (lp.y / h + 0.5));
                c = lerp(c, float3(1, 1, 1), smoothstep(-u * 0.03, 0.0, d) * 0.3);
                c = lerp(c, float3(1, 1, 1), smoothstep(u * 0.05, 0.0, abs(lp.x + lp.y * 0.6 - u * 0.12)) * 0.22);

                // The divider groove, its brass pin, and the pips (white, glowing with the music).
                float groove = smoothstep(1.2, 0.2, abs(lp.y)) * step(abs(lp.x), w * 0.36);
                c = lerp(c, col * 0.35, groove);
                c = lerp(c, lerp(colorC.rgb, float3(1, 0.9, 0.6), 0.5), smoothstep(u * 0.028, u * 0.016, length(lp)));
                float halfSign = lp.y > 0.0 ? 1.0 : -1.0;
                float count = floor(hash1(j * 7.3 + halfSign * 1.7 + 3.0) * 6.99);
                float sp = w * 0.27;
                float2 hq = float2(lp.x, lp.y - halfSign * h * 0.25);
                float2 g = clamp(floor(hq / sp + 0.5), -1.0, 1.0);
                float pd = length(hq - g * sp);
                float pip = smoothstep(u * 0.04, u * 0.028, pd) * pipOn(g, count);
                float3 pipC = light > 0.62 ? col * 0.28 : float3(1, 1, 1);
                pipC = lerp(pipC, float3(1, 1, 1), smoothstep(u * 0.02, 0.0, length(hq - g * sp + u * 0.01)) * 0.5);
                c = lerp(c, lerp(pipC, colorC.rgb, 0.25 * sing * (1.0 - ahead)), pip * lerp(1.0, 0.7, ahead));
                layer(acc, cover, c, face * lerp(1.0, 0.9, ahead));
                layer(acc, cover, lerp(colorC.rgb, float3(1, 1, 1), 0.6), exp(-pd / (u * 0.03)) * pipOn(g, count) * face * sing * 0.45 * (1.0 - ahead));
            }
        }
    }

    // The clack: a flash where the last tile just landed, brighter on the beat.
    float2 hit = float2((k - 1.0) * s + w, base) + float2(sin(b1), cos(b1)) * h;
    float2 hd = abs(px - hit);
    float clack = exp(-f * 5.0) * 0.8 + beat;
    float reach = u * (0.12 + 0.12 * beat);
    float star = exp(-length(hd) / (u * 0.07)) + (exp(-(hd.x * 7.0 + hd.y) / reach) + exp(-(hd.y * 7.0 + hd.x) / reach)) * 0.8;
    layer(acc, cover, colorC.rgb, exp(-length(hd) / (u * 0.2)) * clack * 0.35 * step(1.0, k));
    layer(acc, cover, lerp(colorC.rgb, float3(1, 1, 1), 0.65), star * clack * step(1.0, k));

    return paint(acc / max(cover, 0.001), cover);
}