Sketches120Writing16

Fragments

Learn creative coding with shaders. For design engineers, creative coders and shader artists: techniques, tools, deep dives. Powered by ThreeJS and TSL.

Be the first to know what's next

2025 Phobon

phobon.io↗Shadercraft↗

Pages

Home↗Techniques↗Utilities↗Sketches↗Writing↗

Contact

X @thenoumenon↗hey@fragments.supply↗
All rights reserved.
I almost quit making this LED effect
↑
The moment I almost walked awayWhy did I want to make this?The long road to successThe breakthroughBreaking it downAnother compound techniqueSometimes you need to step awayThe payoffTry it yourself
↵Writing
←

I almost quit making this LED effect

Hours of tweaking shapes, offsets and falloffs almost broke me. Here's what happens when you push through the frustration.

The moment I almost walked away

I was ready to close my laptop and call it a day. Spent so many hours tweaking, adjusting and second-guessing my approach - it really felt like nothing was working.

That really lush LED effect I had in my head just wouldn't translate to the screen. Almost every attempt just looked off. The shapes were strange, the offsets didn't line up, the bloom was just a little too bright. I just couldn't get it to look right.

Something kept me going, though. Maybe it was stubbornness, maybe just curiosity. I'm really glad I didn't quit.

Why did I want to make this?

There's just something about that look that really just hits different. I've always been fascinated with that whole retro-futuristic aesthetic, and I wanted to try and capture that using a shader.

Years ago, I bought a piece of music hardware called the Roli Lightpad Block. It's a small device with a grid of LEDs that you can use as a midi controller, or program a sequence of patterns to play with. The look is just so cool, and using it is really fun.

Roli Lightpad Block

There's just this incredible depth to it. Colours jump off the screen in a way flat colours never can. I love the way light pools in those circular cells, and how the grid creates such a nice rhythm and pattern - it's a timeless look.

That sort of retro-futuristic aesthetic is just such a paradox - it feels both nostalgic and modern at the same time.

The long road to success

My first attempts were pretty awful. I started with what I thought would be simple - just create a grid pattern and throw some shapes in it. I was wrong.

Failed attempt at an LED effect

The problems started small and just kept stacking:

  • Shapes didn't align properly - the offsets weren't working
  • The grid felt stiff and lifeless - this was a recurring theme
  • The repetitions in the grid were way too obvious
  • The actual LED effect just looked too clean - the glow was just a little too bright

I tried all sorts of different shapes, different spacing, scaling coordinate spaces. Nothing felt right. Each version just had something wrong about it.

Second failed attempt at an LED effect

The breakthrough

The turning point was when I just started to trust the process, so I started over and simplified my approach.

Here's what finally worked:

import { Fn, fract, pow, float, smoothstep, length, screenSize } from 'three/tsl'
import { screenAspectUV } from '@/tsl/utils/function'
 
const ledEffect = Fn((props) => {
  const {
    resolution = screenSize,
    cellSize = float(10),
    intensity = float(0.5),
    intensityFalloff = float(1.8),
    edgeSoftness = float(0.2),
  } = props || {}
 
  const _uv = screenAspectUV(resolution).toVar()
 
  // Scale the UV space to create our grid
  const _scaledRes = resolution.div(cellSize)
  _uv.assign(fract(_uv.mul(_scaledRes)).sub(0.5))
 
  // Circle pattern
  const pattern = length(_uv.div(intensity)).oneMinus().toVar()
 
  // Add smoothness and punch to the edges
  pattern.assign(smoothstep(edgeSoftness, 1, pattern))
  pattern.assign(pow(pattern, intensityFalloff))
 
  return pattern
})

The keys to the whole thing were:

  • Properly setting up the coordinate space
  • Using really simple shapes for the LED effect
  • Dialling in the falloff and softness of the LED effect

This approach was really simple, but it paid off big time.

Breaking it down

The fract() function repeats the UV space. This creates our grid of cells. Then length() calculates the distance from the center of each cell.

// Scale the UV space to create our grid
const _scaledRes = resolution.div(cellSize)
_uv.assign(fract(_uv.mul(_scaledRes)).sub(0.5))

The magic happens with smoothstep() and pow(). Smoothstep softens the edges so they're not harsh. The pow function adds punch and contrast, making the LEDs pop.

I also explored other shapes during the process:

// Diamond pattern
const pattern = abs(_uv.x.div(intensity))
  .add(abs(_uv.y.div(intensity)))
  .oneMinus()
 
// Square pattern
const pattern = max(abs(_uv.x.div(intensity)), abs(_uv.y.div(intensity))).oneMinus()

Circles won because they felt organic and a bit more authentic. They have that natural light falloff that LEDs actually have. The other shapes look really cool in certain contexts though.

Another compound technique

This effect is actually a compound of several techniques:

  • Grid systems through Domain Repetition
  • Geometric Shapes for our shapes (Specifically SDF Shapes)
  • A bit of Procedural Color Palettes to learn about falloffs

None of these techniques are complex on their own. But combining them creates something that really feels polished.

Sometimes you need to step away

Here's the thing that really helped me crack the problem: I took a step away from it.

After hours of frustration, I closed my laptop, took my dog for a walk, touched grass - literally anything else.

Something I think is often overlooked is the importance of downtime - letting your body and mind rest and digest. How many times have you been completely stuck on something, only to have the solution pop into your head when you're doing something completely different like going for a walk or taking a shower?

That's your brain subconsciously processing what you've been working on. It's an extremely powerful trait you can actually take advantage of.

I like to think of my brain like a muscle - you put it under some stress, then give it time to recover and it gets stronger. Not exactly like that, but you get the picture.

When I came back the next day, the solution just clicked.

Some things that help me when I'm stuck:

  • Go for a walk - movement helps clear your head
  • Sleep on it - your brain processes things while you sleep
  • Do something completely different - switch contexts entirely
  • Talk it through - explaining the problem to someone often reveals the solution

Remember, progress is not linear. The breakthrough isn't always about working harder. Sometimes it's about giving your brain the space and time to solve things on its own.

The payoff

Seeing it finally work was incredible. That moment when the shapes lined up, the grid felt alive, and everything just clicked into place.

LED effect

The LED effect makes visuals pop in ways I didn't expect. It adds texture and depth without overwhelming the original image. You can use it subtly or crank it up for a retro aesthetic.

Was it worth the hours of frustration? Absolutely.

Try it yourself

Want to experiment with the LED effect in your own work? Check out the full implementation in Fragments. You can tweak the cell size, intensity, and edge softness to get exactly the look you want.

The code is all there, ready to drop into your shaders.

If you'd like to unlock Fragments and get access to the full collection of techniques, utilities, and over 120 sketches with full breakdowns, you can sign up here.