Overview
Blob Shader is an interactive WebGL artwork built with Svelte, Three.js, and custom GLSL shaders. The scene combines two layered meshes: a large gradient sphere that works like an atmospheric backdrop and a high-detail icosahedron blob that pulses with procedural noise.
The project keeps the page structure intentionally lightweight (hero, process notes, and supporting notes), while the visual identity comes from shader math, camera choreography, and subtle post-processing. Pointer movement and scroll both influence the composition, so the page feels alive even without explicit UI controls.
This repository is a focused shader study rather than a full app platform, which makes it a clean reference for experimental front-end graphics work.
Tech stack
- Runtime/UI: Svelte + Vite
- 3D engine: Three.js (
WebGLRenderer, customShaderMaterial) - Motion system: GSAP + ScrollTrigger + ASScroll
- Post-processing: EffectComposer, custom noise pass, SMAA anti-aliasing
- Shaders: Gradient field + chaos blob + screen-space grain pass
Architecture
At runtime, the app initializes smooth scrolling (ASScroll), wires that scroller into GSAP ScrollTrigger, and boots a WebglEngine class that owns scene setup and frame updates.
Inside WebglEngine, the scene graph is compact:
- A background sphere (
SphereGeometry(8, 100, 100)) with a gradient shader - A foreground blob (
IcosahedronGeometry(1, 65)) with a distortion shader - A post-processing pipeline that applies a subtle animated grain and SMAA
The render loop updates elapsed time uniforms each frame and re-renders through EffectComposer. Pointer movement adds smooth positional/rotational drift via GSAP, while scroll timelines rotate the blob and shift camera/plane transforms for section transitions.
Shader breakdown
1) Chaos blob vertex shader
The blob deformation happens in the vertex shader with periodic Perlin noise (pnoise) sampled from normal direction and animated by uTime * uSpeed. The output distortion pushes each vertex along its normal and then applies a Y-axis rotation field:
distortion = pnoise((normal + t) * uNoiseDensity, vec3(10.0)) * uNoiseStrengthpos = position + normal * distortionpos = rotateY(pos, sin(uv.y * uFreq + t) * uAmp)
Finally, the mesh scales over time using a mapped sine wave, giving the blob a breathing rhythm.
2) Chaos blob fragment shader
Coloring uses a cosine palette (cosPalette) with distortion as input. Instead of fixed RGB ramps, this creates smooth hue transitions tied directly to shape turbulence. The result is a coherent look where motion and color shift together.
3) Gradient sphere shader
The large sphere behind the blob uses simplex noise layers in the vertex shader to perturb depth and blend across a 5-color palette (uColor[5]). Since color mixing happens per vertex before interpolation, the gradient feels soft and atmospheric rather than banded.
4) Noise post-processing pass
After scene render, a screen-space shader adds tiny randomized luminance variation, then slightly darkens output (* vec4(0.8, 0.8, 0.8, 1.0)). This gives a film-like texture that helps the scene avoid looking overly sterile.
Interaction and motion
The interaction model is intentionally simple:
- Pointer move: gently offsets blob position and gradient sphere rotation.
- Initial load timeline: drops the blob in with elastic easing and fades in hero elements.
- Scroll timelines: rotate blob/camera and shift decorative circles as content sections enter.
The combination makes the page feel tactile while still remaining readable as a portfolio case study.
What works well
- Strong visual identity from a small number of primitives
- Clear separation between scene engine (
webgl.js) and page layout (Svelte components) - Good use of shader uniforms for time-driven motion and tunable art direction
- Lightweight project scope that is easy to run and extend
Links
Live project — deployed Blob Shader experience.
Repository — source code, shader files, and runtime setup.
three.js — rendering framework used for scene, camera, and post-processing.
GSAP — motion engine for timeline- and scroll-driven transforms.
Setup (for developers)
Clone the repository and run:
npm install
npm run dev
Build for production with:
npm run build