Skip to content

Instantly share code, notes, and snippets.

@radiofun
Last active February 27, 2026 01:14
Show Gist options
  • Select an option

  • Save radiofun/c3afa84c774361ab2b701ed3e3932351 to your computer and use it in GitHub Desktop.

Select an option

Save radiofun/c3afa84c774361ab2b701ed3e3932351 to your computer and use it in GitHub Desktop.
Simple Wave with Noise
#include <metal_stdlib>
#include <SwiftUI/SwiftUI.h>
using namespace metal;
float hash21(float2 p) {
float3 p3 = fract(float3(p.xyx) * 0.1031);
p3 += dot(p3, p3.yzx + 33.33);
return fract((p3.x + p3.y) * p3.z);
}
float vnoise(float2 p) {
float2 i = floor(p);
float2 f = fract(p);
float2 u = f * f * (3.0 - 2.0 * f); // smoothstep hermite
float a = hash21(i);
float b = hash21(i + float2(1.0, 0.0));
float c = hash21(i + float2(0.0, 1.0));
float d = hash21(i + float2(1.0, 1.0));
return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
}
float fbm(float2 p, int octaves) {
float val = 0.0;
float amp = 0.5;
float freq = 1.0;
for (int i = 0; i < octaves; i++) {
val += amp * vnoise(p * freq);
freq *= 2.0;
amp *= 0.5;
}
return val;
}
[[ stitchable ]] half4 rippleDissolve(float2 pos, SwiftUI::Layer l, float4 boundingRect, float progress) {
float2 size = boundingRect.zw;
float2 uv = pos / size;
float2 center = float2(0.5,0.5);
float2 p = uv - center;
float aspect = size.x / size.y;
p.x *= aspect;
float dist = length(p);
float maxDist = length(float2(0.5 * aspect, 0.5));
float normDist = clamp(dist / maxDist, 0.0, 1.0);
float angle = atan2(p.y, p.x);
// Noise to break up the wavefront
float noiseWarp = fbm(float2(angle * 2.5 + 10.0, normDist * 6.0 + progress * 2.0), 4);
float noiseCart = fbm(p * 12.0 + float2(progress * 2.0, -progress * 1.5), 3);
float warpedDist = normDist + (noiseWarp - 0.5) * 0.45 + (noiseCart - 0.5) * 0.4;
// Wavefront expanding outward
float waveFront = progress * 1.2;
// Envelope for multiple waves
float sigma = 0.2; // Wider envelope to fit multiple waves
float delta = warpedDist - waveFront;
float baseEnvelope = exp(-delta * delta / (2.0 * sigma * sigma));
float waveFreq = 40.0; // Controls number of ripples
float ripples = max(0.0, cos(delta * waveFreq));
float envelope = baseEnvelope * ripples;
// How far behind the wave this pixel is (0 = at/ahead of wave, 1 = fully behind)
float feather = 0.2 + 0.03 * noiseWarp; // widened boundary
float behindWave = smoothstep(waveFront + feather, waveFront - feather, warpedDist);
// Zero effect at progress 0
float gate = smoothstep(0.0, 0.05, progress);
envelope *= gate;
behindWave *= gate;
// Displacement only at the wavefront — the burn edge
float2 dir = (dist > 0.001) ? normalize(p) : float2(0.0);
float pushAmt = envelope * 0.15;
float2 uvOffset = dir * pushAmt;
uvOffset.x /= aspect;
// Chromatic aberration at the wavefront
float caStrength = envelope * 0.005;
float2 caOffset = dir * caStrength;
caOffset.x /= aspect;
half4 colorR = l.sample((uv - uvOffset - caOffset) * size);
half4 colorG = l.sample((uv - uvOffset) * size);
half4 colorB = l.sample((uv - uvOffset + caOffset) * size);
half4 color = half4(colorR.r, colorG.g, colorB.b, colorG.a);
// Color dodge glow at the wavefront
half glow = half(envelope * 0.95);
color.rgb = clamp(color.rgb / max(1.0h - glow, 0.01h), 0.0h, 1.0h);
// Scatter: pixels behind the wave get flung in random directions
float2 scatter = float2(hash21(p * 50.0) - 0.5, hash21(p * 50.0 + 7.0) - 0.5);
float2 scatteredUV = uv + scatter;
scatteredUV = mix(uv - uvOffset, scatteredUV, behindWave);
// Re-sample with scattered UVs (replaces the wavefront-only sample)
half4 scatterR = l.sample((scatteredUV - caOffset) * size);
half4 scatterG = l.sample(scatteredUV * size);
half4 scatterB = l.sample((scatteredUV + caOffset) * size);
half4 scattered = half4(scatterR.r, scatterG.g, scatterB.b, scatterG.a);
// Blend from wavefront sample to scattered sample
color = mix(color, scattered, half(behindWave));
// Scattered pixels fade out as they disperse
float scatterFade = 1.0 - smoothstep(0.3, 1.0, behindWave);
color *= half(scatterFade);
//
return color;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment