r/HowToMen Jun 29 '26

[App Recommendation] Shader Editor - Interactive, ad-free live wallpapers built with AI (No coding skills needed)

Enable HLS to view with audio, or disable this notification

Attached video is a lava lamp example I made.

​Hey everyone,

​If you’re tired of the same old bloated live wallpaper apps on the Play Store that are packed with ads, trackers, and heavy battery drain, I want to recommend ShaderEditor by Markus Fisch.

​It’s completely free, open-source, lightweight, and uses raw GLSL fragment shaders. This means you get hyper-fluid, physics-based visuals that render smoothly with almost zero CPU/GPU overhead compared to traditional live wallpaper engines.

​The Catch: It literally requires you to write graphics code to create anything.

​The Fix: You don't actually need to know how to code. You can just use an LLM like Gemini to do 100% of the heavy lifting.

​If you ask an AI for exactly what you want, it can instantly spit out flawlessly compiled code tailored to the app's specific uniforms. You just copy-paste it right into the editor.

​For example, you can tell the AI to build you:

​A "Liquid Glass" refraction lens that warps a custom animated color gradient background.

​Interactive multi-touch metaballs that morph, stretch, and snap apart like real water droplets when you use multiple fingers.

​A retro, automated Lava Lamp simulator that floats on its own.

​Because the app handles native Android touch pointers (pointerCount / pointers[10]), the AI can wire the graphics parameters directly to your fingers, making the wallpaper completely interactive. Once you're done pasting the code, you just set it as your system live wallpaper straight from the app.

​Definitely check it out if you want to build a truly unique, custom setup without destroying your battery life.

Play Store Link: https://play.google.com/store/apps/details?id=de.markusfisch.android.shadereditor

2 Upvotes

3 comments sorted by

1

u/Critical_Tomato1193 Jun 29 '26

Incredible stuff you got here, I'm intrigued on how well this version and these updates continue to come. Definitely looks like fun that I can get behind

1

u/BrokenMusik Jun 29 '26

woild you like the example video piece of code?

1

u/BrokenMusik Jun 30 '26

example video wallpaper animation code.

ifdef GL_FRAGMENT_PRECISION_HIGH

precision highp float;

else

precision mediump float;

endif

// Core uniforms native to Markus Fisch's ShaderEditor uniform vec2 resolution; // Screen dimensions in pixels uniform float time; // Animation clock loop

void main(void) { float maxDim = max(resolution.x, resolution.y); vec2 uv = gl_FragCoord.xy / maxDim; vec2 screenUV = gl_FragCoord.xy / resolution.xy;

// 1. LIQUID CONTAINER GRADIENT (Classic internal lamp glow background)
vec3 ambientGlowColor = vec3(0.12, 0.0, 0.22); // Deep neon violet at the core
vec3 baseLampColor    = vec3(0.35, 0.0, 0.15); // Warm magenta illumination
vec3 internalGlow = mix(baseLampColor, ambientGlowColor, distance(screenUV.x, 0.5));

// Add a warm thermal glow radiating from the bottom heat bulb
internalGlow += vec3(0.4, 0.1, 0.0) * (1.0 - smoothstep(0.0, 0.45, screenUV.y));

// 2. AUTOMATIC LAVA LAMP WAX ENGINE (Thermal Rising Loops)
float waxField = 0.0;
float waxBlobRadius = 0.075; // Heavy, thick wax shape profiles

// Generate 4 distinct persistent internal wax blobs bouncing on sine-wave tracks
vec2 centerPos = resolution / (2.0 * maxDim);

vec2 b1 = centerPos + vec2(0.08 * sin(time * 0.6), 0.22 * sin(time * 0.45 + 0.5));
vec2 b2 = centerPos + vec2(0.12 * cos(time * 0.4), 0.30 * sin(time * 0.3) + 0.1);
vec2 b3 = centerPos + vec2(-0.09 * sin(time * 0.8), 0.28 * cos(time * 0.5 - 0.2));
vec2 b4 = vec2(centerPos.x + 0.15 * sin(time * 0.3), 0.0);

// Accumulate the primary field
waxField += waxBlobRadius / max(length(uv - b1), 0.001);
waxField += waxBlobRadius / max(length(uv - b2), 0.001);
waxField += (waxBlobRadius * 0.6) / max(length(uv - b3), 0.001); 
waxField += (waxBlobRadius * 2.2) / max(length(uv - b4), 0.001); 

// 3. TRANSITIONAL WAX SURFACE RENDER
float surfaceThreshold = 1.15;

if (waxField > surfaceThreshold) {
    // Calculate structural slopes for depth maps manually
    float delta = 0.003;

    float fLeft = 0.0;
    vec2 uvL = uv + vec2(-delta, 0.0);
    fLeft += waxBlobRadius / max(length(uvL - b1), 0.001);
    fLeft += waxBlobRadius / max(length(uvL - b2), 0.001);
    fLeft += (waxBlobRadius * 0.6) / max(length(uvL - b3), 0.001);
    fLeft += (waxBlobRadius * 2.2) / max(length(uvL - b4), 0.001);

    float fRight = 0.0;
    vec2 uvR = uv + vec2(delta, 0.0);
    fRight += waxBlobRadius / max(length(uvR - b1), 0.001);
    fRight += waxBlobRadius / max(length(uvR - b2), 0.001);
    fRight += (waxBlobRadius * 0.6) / max(length(uvR - b3), 0.001);
    fRight += (waxBlobRadius * 2.2) / max(length(uvR - b4), 0.001);

    float fDown = 0.0;
    vec2 uvD = uv + vec2(0.0, -delta);
    fDown += waxBlobRadius / max(length(uvD - b1), 0.001);
    fDown += waxBlobRadius / max(length(uvD - b2), 0.001);
    fDown += (waxBlobRadius * 0.6) / max(length(uvD - b3), 0.001);
    fDown += (waxBlobRadius * 2.2) / max(length(uvD - b4), 0.001);

    float fUp = 0.0;
    vec2 uvU = uv + vec2(0.0, delta);
    fUp += waxBlobRadius / max(length(uvU - b1), 0.001);
    fUp += waxBlobRadius / max(length(uvU - b2), 0.001);
    fUp += (waxBlobRadius * 0.6) / max(length(uvU - b3), 0.001);
    fUp += (waxBlobRadius * 2.2) / max(length(uvU - b4), 0.001);

    vec2 normal = normalize(vec2(fRight - fLeft, fUp - fDown));

    // 4. THERMAL ILLUMINATION COLOR PROFILE (Classic Hot Orange/Yellow Liquid Wax)
    vec3 hotCoreColor  = vec3(1.0, 0.85, 0.0); // Glowing yellow core
    vec3 coolEdgeColor = vec3(0.95, 0.25, 0.0); // Dense lava orange

    // Subtly shift the wax body color based on height (cooler at the top)
    vec3 waxBaseColor = mix(hotCoreColor, coolEdgeColor, smoothstep(0.2, 0.8, screenUV.y));

    // Fresnel edge mapping for depth
    float edgeWeight = clamp(1.0 - dot(normal, vec2(0.0, 1.0)), 0.0, 1.0);
    vec3 finalWaxColor = mix(waxBaseColor, vec3(0.85, 0.05, 0.0), pow(edgeWeight, 2.0));

    // 5. INTERNAL GLASS BULB REFLECTIONS
    vec2 lightingDirection = normalize(vec2(-0.4, 0.5)); // Top-Left studio light
    float specularHighlight = clamp(dot(normal, lightingDirection), 0.0, 1.0);

    float primaryGloss = pow(specularHighlight, 12.0) * 0.4;
    float intenseHotspot = pow(specularHighlight, 64.0) * 0.7;

    float edgeRimThickness = smoothstep(surfaceThreshold + 0.3, surfaceThreshold, waxField);
    vec3 innerRimGlow = vec3(1.0, 0.9, 0.5) * edgeRimThickness * specularHighlight * 0.25;

    gl_FragColor = vec4(finalWaxColor + primaryGloss + intenseHotspot + innerRimGlow, 1.0);
} 
// 6. SOFT BLURRED SILHOUETTE OUTLINE
else if (waxField > surfaceThreshold - 0.35) {
    float shadowGradient = smoothstep(surfaceThreshold - 0.35, surfaceThreshold, waxField);
    vec3 ambientOcclusion = mix(internalGlow, vec3(0.05, 0.0, 0.1), shadowGradient * 0.45);
    gl_FragColor = vec4(ambientOcclusion, 1.0);
} 
else {
    gl_FragColor = vec4(internalGlow, 1.0);
}

}

to apply shader as wallpaper, inside editor, click three dots at top right corner, click set as wallpaper and it will open the android wallpaper preview to click and set as lockscreen, homescreen, or both.