Skip to content

Web Development

Shader Park & GLSL Backgrounds — How Aidxn Adds Premium Texture for $0/mo

Shader Park lets you write minimal GLSL backgrounds in JavaScript that compile to WebGL. The difference between a stock-gradient site and one that feels alive. Real code, scroll-driven uniforms, and the performance tradeoffs agencies never mention.

🎨 🌊

There's a moment on every premium marketing site where you scroll down and the background shifts. Not a fade. Not a gradient. A texture — something with depth and movement that makes the page feel like it's made of more than pixels. It feels hand-crafted. Expensive. That's not an illustration. That's a shader.

Most designers reach for After Effects or Figma to bake these textures as static images. Your bundle size bloats. Your load time increases. You've bought motion with bytes. But there's a better way: Shader Park. Write 20 lines of GLSL in JavaScript, compile it to WebGL once, and animate it with scroll. One canvas element. Sub-100kb. Runs on potato GPUs. And it makes your marketing site feel like it was built by someone who actually knows what they're doing.

What Shader Park Actually Is

Shader Park is a JavaScript library that takes GLSL code (the language WebGL uses) and compiles it into a three.js/Babylon.js scene. But it's not a full 3D engine. It's the opposite: minimal. Write a sculpt function (a mathematical description of a surface), declare some uniforms (scrollable values), and Shader Park renders it to a canvas. No meshes. No lights. No camera setup. Just shader code.

Why does this matter? Because CSS gradients are static. SVG backgrounds are vectors (beautiful but heavy). Canvas is raw pixels (fast but painful to write). GLSL shaders are procedural — they generate texture mathematically. A 50-line shader can create infinite variations of noise, distortion, waves, or crystalline patterns. The file size is microscopic. The performance is insane. And you can animate it by tweaking a single variable: scroll position.

Velocity X (Aidxn's conversion-engineered marketing template) uses this on the hero section. Instead of a static gradient, there's a procedurally-generated wavy background that subtly responds to scroll. Visitors don't consciously notice it. But they feel it. The page doesn't feel static. It feels alive.

GLSL Beats CSS Gradients — Here's Why

A CSS gradient is a 1D or 2D color ramp. It's fast to render and gorgeous for simple cases. But it's flat. You're assigning colors to positions in a fixed grid. A shader, by contrast, evaluates a mathematical function at every pixel. You can create:

  • Organic noise: Perlin or Simplex noise baked into the shader. Infinite variation, zero images.
  • Reactive motion: Uniforms (variables) change with scroll, time, or mouse. The texture breathes.
  • Sub-100kb file: A shader is source code. It compresses to nothing. A 4K noise texture is 20MB.
  • Infinite resolution: The shader runs at the canvas resolution. 2560px or 1920px — it scales for free.
  • GPU-accelerated: CSS gradients are CPU-rendered. Shaders run on the GPU. Mobile hardware benefits most.

CSS gradients are fine for solid backgrounds. For premium texture? Shaders are the only play.

Setup: One Script Tag, 20 Lines

Here's a minimal Shader Park scene:

import ShaderPark from 'shader-park-core';

const canvas = document.querySelector('canvas');
const scene = new ShaderPark.Scene({ canvas });

scene.setUniform('time', 0);
scene.setUniform('scroll', 0);

// The shader code: a mathematical function that returns color
const shader = `
  void main() {
    vec2 uv = gl_FragCoord.xy / uResolution.xy;
    float noise = fbm(uv * 3.0 + uTime * 0.1);
    float wave = sin(uv.x * 5.0 + uScroll * 2.0) * 0.5 + 0.5;

    gl_FragColor = vec4(
      mix(vec3(0.1, 0.2, 0.5), vec3(0.8, 0.3, 0.7), noise),
      1.0
    );
  }
`;

scene.setShader(shader);

// Update uniforms on scroll
window.addEventListener('scroll', () => {
  const scroll = window.scrollY / window.innerHeight;
  scene.setUniform('scroll', scroll);
});

// Render loop
function animate() {
  scene.setUniform('time', Date.now() * 0.001);
  scene.render();
  requestAnimationFrame(animate);
}

That's it. You now have an animated, scroll-responsive shader running on the page. The canvas is a single DOM element. The shader re-evaluates every pixel every frame. No assets. No baked imagery. No bundle bloat.

Real Pattern: Scroll-Driven Uniforms (Velocity X Hero)

Here's how Velocity X uses this in the hero section:

// HeroShader.tsx
import { useEffect, useRef } from 'react';
import ShaderPark from 'shader-park-core';

export const HeroShader = () => {
  const canvasRef = useRef(null);
  const sceneRef = useRef(null);

  useEffect(() => {
    if (!canvasRef.current) return;

    // Initialize scene
    const scene = new ShaderPark.Scene({ canvas: canvasRef.current });
    sceneRef.current = scene;

    // Shader: wavy noise background
    const shaderCode = `
      void main() {
        vec2 uv = gl_FragCoord.xy / uResolution.xy;

        // Wave distortion based on scroll
        float wave = sin(uv.y * 3.0 + uScroll * 5.0) * 0.1;
        uv.x += wave;

        // Perlin noise
        float noise = fbm(uv * 2.0 + uTime * 0.05);

        // Color gradient driven by noise + scroll
        vec3 color = mix(
          vec3(0.05, 0.15, 0.35),  // Dark purple
          vec3(0.7, 0.2, 0.8),     // Bright magenta
          noise * (0.5 + uScroll * 0.5)
        );

        gl_FragColor = vec4(color, 1.0);
      }
    `;

    scene.setShader(shaderCode);

    // Uniform: time for continuous animation
    const updateTime = () => {
      scene.setUniform('time', Date.now() * 0.001);
      requestAnimationFrame(updateTime);
    };
    updateTime();

    // Uniform: scroll for interactivity
    const updateScroll = () => {
      const scroll = Math.min(1.0, window.scrollY / 1000);
      scene.setUniform('scroll', scroll);
    };
    window.addEventListener('scroll', updateScroll);

    return () => {
      window.removeEventListener('scroll', updateScroll);
    };
  }, []);

  return (
    <canvas
      ref={canvasRef}
      className="absolute inset-0 w-full h-screen"
    />
  );
};

The canvas sits behind the hero text. As you scroll, the shader's `uScroll` uniform changes. The noise pattern shifts. The wave distortion updates. The entire background feels responsive to your input. All of this runs at 60fps on a 2-year-old phone.

Performance Budget: When Shaders Become Expensive

Shaders are GPU code, but they can still tank performance. Here's what you need to know:

Canvas Size

A shader evaluates every pixel every frame. A 2560×1440 canvas is 3.6M pixels. At 60fps, that's 216M pixel operations per second. Even modern GPUs will drop frames. Cap your canvas resolution:

// Render at native resolution, but cap expensive shaders
const dpr = Math.min(window.devicePixelRatio, 1.5);
canvas.width = window.innerWidth * dpr;
canvas.height = window.innerHeight * dpr;

Never let canvas resolution scale 1:1 with 4K monitors. Users don't notice the quality difference. Your frame rate does.

Shader Complexity

Simple shaders (a single noise call + a color mix) run instantly. Complex ones (nested fbm loops, raymarching, multiple texture lookups) tank performance. Benchmark with DevTools GPU profiler:

// Fast: ~2ms per frame
float noise = fbm(uv * 2.0);

// Slow: ~15ms per frame
float noise = fbm(uv * 2.0);
noise += fbm(uv * 4.0 + uTime);
noise += fbm(uv * 8.0 + uTime * 0.5);
noise = fbm(vec3(uv, uTime) * 10.0);

More fbm calls = exponential cost. Use a single noise layer, or bake expensive calculations into pre-generated textures.

Mobile & Accessibility

Shaders on mobile can tank battery. Check `prefers-reduced-motion` and disable on low-end devices:

const prefersReducedMotion = window.matchMedia(
  '(prefers-reduced-motion: reduce)'
).matches;

const isLowEndDevice = navigator.hardwareConcurrency <= 2;

if (prefersReducedMotion || isLowEndDevice) {
  // Fall back to static CSS gradient
  canvas.style.display = 'none';
  hero.style.background = 'linear-gradient(...)';
} else {
  // Render shader normally
}

Don't force shaders on users who've asked for reduced motion. Accessibility first. Fancy second.

Six FAQs

Isn't WebGL harder than CSS?

Raw WebGL is brutal. But Shader Park abstracts 90% of the pain. You just write the `main()` function. Shader Park handles contexts, buffers, and viewport setup.

Can I use shaders on hero images?

Yes. Load an image texture into the shader and apply effects. You can add animated distortion, color grading, or glitch effects to any image — all procedural.

Do shaders work in Safari?

Yes, if your device supports WebGL 2. Most do. For older Safari, fallback to CSS gradient. Check `gl.getParameter(gl.VERSION)` and detect gracefully.

Can I version-control shader code?

Absolutely. Store shader code as strings in your codebase, just like you would JavaScript. They're human-readable and diff-friendly.

What's the learning curve for GLSL?

If you know JavaScript, GLSL takes ~2 hours to learn basics (vectors, noise functions, swizzling). Advanced stuff (raymarching, SDF rendering) takes weeks. Start with Shader Park's examples and build from there alongside smooth scroll patterns.

Can I use shaders in Astro?

Yes. Import ShaderPark in a client component, mount it in an island, and initialize on `useEffect`. Astro's View Transitions handle the rest — the canvas persists across page swaps if you use `transition:persist`.

The Bottom Line

Shaders are the premium texture layer that separates template sites from bespoke work. A single procedurally-generated background conveys care, technical depth, and polish without requiring a 10MB hero image or a motion designer's timeline.

Velocity X uses Shader Park on the hero because it's zero-cost (bandwidth-wise), infinitely scalable (any resolution), and feels alive. Visitors scroll and feel something responsive. They don't know why. But they remember it. And that's what converts the ambiguous visitor into the convinced customer.

Start small: replace your hero gradient with a Shader Park scene. Add a single noise layer. Tie it to scroll. You'll immediately see the difference. For the deeper pattern on how shaders pair with smooth scroll and pinned animations, check how Velocity X templates layer motion primitives for maximum conversion impact.

Let us make some quick suggestions?
Please provide your full name.
Please provide your phone number.
Please provide a valid phone number.
Please provide your email address.
Please provide a valid email address.
Please provide your brand name or website.
Please provide your brand name or website.