Candy Interference
GLSL shader by merrypranxter · created 2026-02-14 · 10s loop · 2 passes
Math pretending to be a Lisa Frank poster. Iridescent chaos, procedurally generated.
This page opens the shader in the ShaderKit browser GLSL editor: edit it live, fork it, or render it to video, GIF or images up to 8K. Also available as a full-screen view and an embeddable player.
Shader source (GLSL)
Common
#define pi acos(-1.)
#define deg pi/180. //1 degree
#define time iTime*2.*pi/10. //sin(time) loops 10 seconds
#define R iResolution.xy //shorthand
#define ar R.x/R.y //aspect ratio
#define M iMouse //shorthand
#define xm (M.xy/R) //normalized mouse
#define nm ((xm.xy-0.5)*vec2(ar,1.)+0.5) //aspect ratio correction
vec3 cs = vec3(1.,2.,3.);
mat2 r2d(float a) {
return mat2(cos(a),sin(a),-sin(a),cos(a));
}
Buffer A (iChannel0)
// ============================================================
// LISA FRANK FIELD v1.0
// Controls: glitchAmt, warpScale, iridescence,
// aberration, speed, brightness
// ============================================================
#define PI 6.28318530718
// ---- KNOBS ---- (tweak these first) ----
float glitchAmt = 0.35; // scan-line / jitter strength
float warpScale = 3.2; // how wild the domain warp gets
float iridescence = 1.8; // color band density
float aberration = 0.18; // chromatic split amount
float speed = 0.4; // animation speed
float brightness = 1.3; // final output gain
// ---- PALETTE: Lisa Frank cosine ----
// Cycles: hot pink → electric cyan → lemon → violet → repeat
vec3 lfPalette(float t) {
vec3 a = vec3(0.7, 0.4, 0.7); // bias (pink-violet base)
vec3 b = vec3(0.6, 0.5, 0.5); // amplitude
vec3 c = vec3(1.0, 1.2, 0.8); // frequency per channel
vec3 d = vec3(0.0, 0.33, 0.67); // phase offset (spreads hues)
return a + b * cos(PI * (c * t + d));
}
// ---- Hot neon accent palette ----
vec3 acidPalette(float t) {
vec3 a = vec3(0.5, 0.5, 0.5);
vec3 b = vec3(0.5, 0.5, 0.5);
vec3 c = vec3(2.0, 1.0, 0.0);
vec3 d = vec3(0.5, 0.2, 0.25);
return a + b * cos(PI * (c * t + d));
}
// ---- Hash / noise ----
float hash(vec2 p) {
p = fract(p * vec2(127.1, 311.7));
p += dot(p, p + 19.19);
return fract(p.x * p.y);
}
float noise(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(mix(hash(i), hash(i + vec2(1,0)), u.x),
mix(hash(i + vec2(0,1)), hash(i + vec2(1,1)), u.x), u.y);
}
// ---- FBM domain warp (2 octaves is cheap & plenty weird) ----
vec2 domainWarp(vec2 p, float t) {
float n1 = noise(p * 1.5 + t * 0.3);
float n2 = noise(p * 2.3 - t * 0.2 + vec2(5.2, 1.3));
vec2 warp1 = vec2(n1, n2) * 2.0 - 1.0;
float n3 = noise((p + warp1 * 0.8) * 2.0 + t * 0.15);
float n4 = noise((p + warp1 * 0.8) * 1.7 - t * 0.25 + vec2(1.7, 9.2));
vec2 warp2 = vec2(n3, n4) * 2.0 - 1.0;
return p + (warp1 * 0.6 + warp2 * 0.4) * warpScale * 0.25;
}
// ---- Thin-film interference field ----
float thinFilm(vec2 p, float t) {
float r = length(p);
float a = atan(p.y, p.x);
// Concentric interference rings warped by angle
return sin(r * iridescence * 8.0 - t * 2.0)
* sin(a * 3.0 + r * 4.0 + t)
+ sin(r * iridescence * 13.0 + a * 2.0 - t * 1.3);
}
// ---- CRT scanline grime ----
float scanlines(vec2 uv, float t) {
float line = sin(uv.y * 200.0 + t * 10.0) * 0.5 + 0.5;
float coarse = sin(uv.y * 40.0 - t * 3.0) * 0.5 + 0.5;
return mix(1.0, 0.75 + line * 0.25 * coarse, glitchAmt * 0.4);
}
// ---- H-jitter glitch (VHS horizontal displacement) ----
vec2 vhsJitter(vec2 uv, float t) {
float band = floor(uv.y * 15.0 + t * 7.0);
float jitter = (hash(vec2(band, floor(t * 20.0))) - 0.5)
* glitchAmt * 0.04;
return uv + vec2(jitter, 0.0);
}
// ---- Main ----
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;
float t = iTime * speed;
// Apply VHS jitter
vec2 jUV = vhsJitter(uv, t);
// Domain warp the coordinate space
vec2 wp = domainWarp(jUV * warpScale, t);
// Chromatic aberration: sample warped field at 3 slightly offset UVs
float filmR = thinFilm(domainWarp(jUV * warpScale + aberration, t), t);
float filmG = thinFilm(wp, t);
float filmB = thinFilm(domainWarp(jUV * warpScale - aberration * 1.3, t), t);
// Map film values to palette phase
float phaseR = filmR * 0.5 + 0.5;
float phaseG = filmG * 0.5 + 0.5;
float phaseB = filmB * 0.5 + 0.5;
// Sample two palettes and blend
vec3 colA = lfPalette(phaseG + t * 0.1);
vec3 colB = acidPalette(phaseG * 0.7 + length(wp) * 0.2 - t * 0.08);
// Combine channels with aberration split
vec3 col;
col.r = mix(colA.r, colB.r, phaseR) * 1.1;
col.g = mix(colA.g, colB.g, phaseG);
col.b = mix(colA.b, colB.b, phaseB) * 1.15;
// Glow accumulator — adds neon plasma rim light
float glowField = abs(sin(filmG * 3.0 + t)) / (0.1 + abs(filmG));
glowField = clamp(glowField * 0.04, 0.0, 0.8);
col += lfPalette(length(uv) + t * 0.2) * glowField;
// Scanlines
col *= scanlines(jUV, t);
// Vignette (soft, barely there)
col *= 1.0 - dot(uv, uv) * 0.3;
// Output
col = pow(col * brightness, vec3(0.88)); // gamma + boost
col = clamp(col, 0.0, 1.0);
fragColor = vec4(col, 1.0);
}
Image
Not used
More shaders by merrypranxter
- PRISMACORE_003 — Retina Banquet
- PRISMACORE_002 — After Work Sky
- PRISMACORE_001 — Liquid Crystal Fever Dream
- Hopf Vibratiok in pink
- Void Geode
- Project_2026-02-14_04-53-13
- Chromatic Plexus
- Signal Death
- Deep fried math
- Project_2026-02-12_21-16-32
- Project_2026-02-12_17-00-28
- Project_2026-02-12_16-17-50
Browse all public shaders · All shaders by merrypranxter · ShaderKit home
Unread comments
×Projects with new comments. Click to open and read.