The four minutes in the title is real, but it's the wrong number to focus on. Four minutes is how long it takes my Claude Code skill to generate a working chromatic aberration hover effect for a gallery page today. The number that matters is the eight to ten iterations it took before I trusted that output on client work, because raw AI-generated Three.js code has a very specific set of failure modes, and shader effects hit all of them at once: leaked WebGL contexts, listeners that never detach, and canvases that turn to jagged mush on retina screens.
I do client web design through my services, and GLSL was always the line I didn't cross. I can read a fragment shader; I cannot write a production displacement effect from scratch without a documentation tab open, and I've never had a project where learning to was worth the weeks it costs. Shaders are hard relative to how often you need them. That asymmetry is exactly what a well-built skill fixes: mechanical complexity handled once, then reused forever. Skill authoring is my actual practice — I maintain a local library of 31 skills and publish 53 more — so wrapping shader effects in one was the obvious move.

Why "Just Learn GLSL" Is Bad Advice for Most Developers
GLSL is a C-like language that runs on the GPU, in parallel, with no console.log and no tolerance for fuzzy understanding. Debugging is visual guessing: change a uniform, rebuild, squint. Three.js's ShaderMaterial abstracts some of it and obscures the rest, especially how uniforms, attributes, and varyings flow between your JavaScript and the shader program.
The honest learning path to writing custom production shaders runs through linear algebra, the WebGL pipeline, GLSL's constraints (strict typing, no recursion), coordinate normalization, and time-uniform management. That's months, and most of it transfers to nothing else you do. If you're a full-time creative developer, make that investment. If you're shipping full-stack product work, wrap the capability in tooling instead and spend your judgment where it counts: deciding whether an effect belongs on a page at all.
What the Skill Does
The skill lives in the project's .claude/skills directory, not my global library — shader work is client-project-specific, and I keep project-shaped skills with the project. Invoked from a Claude Code session, it asks two things: which file holds the gallery, and which effect — distortion, wave, chromatic aberration, or wobble — then intensity and animation-style options.
Before generating anything, it reads the target HTML, the relevant CSS, and any existing Three.js usage. That context pass is the difference between code that integrates and code that merely coexists. Then it produces one new file: renderer, scene, and camera setup with correct pixelRatio, the GLSL source strings, uniform management, mouse listeners with viewport-space normalization, a ResizeObserver, and explicit disposal on unload. One script tag added to the HTML. Nothing scattered through existing files.
The disposal part deserves its own sentence, because it's the insight that cost me the most to learn: AI-generated WebGL code almost never cleans up after itself. Left to its defaults, every model I've used writes an effect that works beautifully in a demo and leaks renderer resources and event listeners in a real SPA. My skill handles it because I documented the failure after watching it happen, the same distillation loop I described in lessons from building Claude Code skills.
The Four Effects, Mechanically
Distortion warps UV coordinates around the cursor. The fragment shader samples the texture at an offset calculated from distance to the normalized mouse position; the intensity option maps to the maximum offset (roughly 0.04 UV units for subtle, up to 0.15 where it reads as liquid). Three uniforms drive it: u_mouse, u_time, u_intensity. It suits dark, high-contrast photography and overwhelms lighter corporate layouts.
Wave radiates a ripple from the interaction point. The interesting engineering lives in the animation-style option: a snappy variant uses exponential decay (full intensity instantly, quick die-off — feels like pressed glass), a languid variant overshoots slightly before settling (feels like water), and a smooth variant is plain cosine interpolation. Side by side, those curves change the entire character of a portfolio.
Chromatic aberration is the crowd-stopper. You sample the texture three times — red channel at uv + offset, green at uv as the anchor, blue at uv - offset — which simulates lens fringing. Making the offset follow the mouse-movement vector so the fringe trails your cursor is the detail that sells it as physical rather than gimmicky.
Wobble is the odd one out because it lives in the vertex shader: a sinusoidal displacement of the geometry itself, propagating from the entry point and damping out in under a second, like pressing a rubber sheet. It's also the effect that exposed the retina bug — without correct pixelRatio handling on the canvas, the oscillation renders jagged on high-DPI displays. If you adapt any of this manually and the wobble looks wrong, check that first.
None of this GLSL is exotic. All of it is fiddly. Fiddly-but-known is precisely what belongs inside a skill.
The Iterations Nobody Shows You
The first version of this skill came from the naive prompt you'd expect — "create a skill that applies Three.js shader hover effects to gallery images" — and produced syntactically correct code that didn't run, because it assumed a bundler and the target project used plain script tags. The second version detected the environment but broke on galleries with nested wrapper structures. The third handled nesting and missed galleries built on CSS background-image instead of <img> elements, which is a large share of real-world galleries for aspect-ratio reasons.
Each failure became a documented example inside the skill: here's a background-image gallery, here's what to do differently. This is the same authoring discipline I use on everything in my library, and it's why I bother with test prompts and evals rather than vibes — I wrote up that loop in testing skills with skill-creator. The inflection point was adding failure-mode instructions: what to emit when Three.js isn't on the page, when the selector matches zero elements, when WebGL isn't supported. A skill that degrades gracefully is one you'll actually run on client work; a skill that only survives clean demo HTML is a party trick.
Where does it still go wrong? Ambiguous setups. A project that looks bundled but isn't, or loads Three.js conditionally, can confuse the context-reading pass. I still review the output before anything ships — the review takes ten or fifteen minutes, which is a rounding error against the six-plus hours this class of effect used to cost me.
What the Four Minutes Buys You
The time saving is the least interesting outcome. The real change is what I can offer. Before this skill, I never proposed shader-level polish to a client because the implementation cost made it indefensible for a normal budget. Now the implementation cost is close to zero, so the conversation becomes purely a design question: does chromatic aberration serve this brand, this photography, this audience? The skill knows how to apply the effect. It has no opinion on whether it should be applied. That judgment stayed exactly where it was.
This is the same shape as every abstraction argument the web has already had — jQuery over the DOM, bundlers over manual scripts, TypeScript over untyped JavaScript. The people who built taste on top of the abstraction outran the people who mourned the layer below it. Deciding when an effect belongs, tuning it for context, keeping it from wrecking performance on mid-range phones: that's the durable expertise. I lean on the same principle across my visual work with Claude, from using Claude Code as a UI designer to the design skill I run on every interface.
Build Your Own: The Shortcut I Wish I'd Taken
If you want this in your own setup, don't start from a blank prompt like I did. Start from the best production-tested Three.js effect implementation you can find and make it the skill's foundation example. One excellent reference teaches a skill more than five tutorial snippets that cut corners.
Then build narrow and widen slowly: one effect, one project structure, tested against three or four real projects with messy HTML. Every manual correction you make is an improvement example — feed it back in. Add failure-mode handling before you add the second effect, not after. The versions of this skill that I'd have called "done" at iteration three would have embarrassed me on a client project; the difference between iteration three and iteration nine is entirely accumulated failure documentation.
The gap between the effects you admire on award sites and the effects you ship isn't talent. It's mechanical complexity sitting between the idea and the outcome, and mechanical complexity is now delegable. If you'd rather have this level of visual polish built for your site than build the tooling yourself, my web design and development services cover exactly this kind of work.