float4 shadeVideo(ShaderContext context)
{
    if (drop <= 0)
        return context.sourceColor;

    float age = max(context.time - dropTime, 0.0);
    float2 aspect = float2(context.outputResolution.x / max(context.outputResolution.y, 1.0), 1.0);
    float2 fromDrop = (context.uv - center) * aspect;
    float radius = length(fromDrop);

    float2 c0 = (float2(0.0, 0.0) - center) * aspect;
    float2 c1 = (float2(1.0, 0.0) - center) * aspect;
    float2 c2 = (float2(0.0, 1.0) - center) * aspect;
    float2 c3 = (float2(1.0, 1.0) - center) * aspect;
    float maxRadius = max(max(length(c0), length(c1)), max(length(c2), length(c3)));
    float progress = saturate(age / max(speed, 0.001));
    float waveRadius = progress * maxRadius;
    float distanceToWave = radius - waveRadius;
    float waveWidth = max(width * maxRadius, 0.0001);
    float ring = (1.0 - smoothstep(waveWidth, waveWidth * 1.65, abs(distanceToWave))) * exp(-progress * damping * 0.35);
    float crest = 1.0 - smoothstep(0.0, waveWidth * 0.35, abs(distanceToWave));
    float ripple = ring * (distanceToWave >= 0.0 ? 1.0 : -0.55);

    float2 direction = radius > 0.0001 ? fromDrop / radius : float2(0.0, 0.0);
    float2 uvOffset = direction * (ripple * strength);
    uvOffset.x /= aspect.x;

    float2 refractedUv = clamp(context.uv - uvOffset, float2(0.0, 0.0), float2(1.0, 1.0));
    float4 refracted = sampleVideo(refractedUv);

    float highlight = saturate(ring * 0.75 + crest * 0.55);
    refracted.rgb += highlight * 0.075;
    return saturate(refracted);
}
