[HN Gopher] A flowing WebGL gradient, deconstructed
       ___________________________________________________________________
        
       A flowing WebGL gradient, deconstructed
        
       Author : alexharri
       Score  : 206 points
       Date   : 2025-04-12 10:54 UTC (4 days ago)
        
 (HTM) web link (alexharri.com)
 (TXT) w3m dump (alexharri.com)
        
       | mwkaufma wrote:
       | >> The mix function is an interpolation function that linearly
       | interpolates between the two input colors using a blend factor
       | between and ( in our case).
       | 
       | >> A mix function for two colors works the same way, except we
       | mix the color components. To mix two RGB colors, for example,
       | we'd mix the red, green, and blue channels.
       | 
       | Colorspace alert! mix != lerp in sRGB
        
         | danwills wrote:
         | Quite right! I think if the values were linearized (~gamma 0.5)
         | lerp might be mostly ok though, right?
         | 
         | And what about doing rgb->hsv, then lerp, then hsv->rgb? I'm
         | unclear whether that also needs linearization, or whether the
         | gamma can maybe just be done to the 'v' component before
         | lerping?
         | 
         | Color is a surprisingly deep and fascinating topic, that's for
         | sure! :)
        
           | pornel wrote:
           | Mixing of colors in an "objective" way like blur (lens focus)
           | is a physical phenomenon, and should be done in linear color
           | space.
           | 
           | Subjective things, like color similarity and perception of
           | brightness should be evaluated in perceptual color spaces.
           | This includes sRGB (it's not very good at it, but it's
           | trying).
           | 
           | Gradients are weirdly in the middle. Smoothness and matching
           | of colors are very subjective, but color interpolation is
           | mathematically dubious in most perceptual color spaces,
           | because [?](avg(a+b)) [?] avg([?](a) + [?](b))
        
           | mwkaufma wrote:
           | Perceptual colors -- both sRGB and HSB -- are nonlinear, so
           | you can't expect linear combinations to produce meaningful
           | results (they often "interpolate through mud").
           | 
           | If you just want optical phenomena, you can just convert to
           | luminescence -- WegGL and other modern graphics APIs actually
           | does this internally when you load or render textures, so all
           | shaders are handling optically-linear data, which is why the
           | shader-produced images in the post look better than the
           | javascript gradients.
        
             | eurekin wrote:
             | Googled "luminescence" and OpenGL -- don't seem to return
             | relevant results. Could you point to where it's described?
        
             | virtualritz wrote:
             | Luminance[1], not luminescence[2].
             | 
             | [1] https://en.wikipedia.org/wiki/Luminance
             | 
             | [2] https://en.wikipedia.org/wiki/Luminescence
        
               | mwkaufma wrote:
               | Lol autocorrecttt ty
        
         | itishappy wrote:
         | To be fair, lerp still mixes colors, it just mixes ugly colors.
        
           | immibis wrote:
           | (1,0,0) and (0,0,1) are each twice as bright, in terms of
           | photons, as (0.5,0,0.5).
           | 
           | If you quickly apply gamma=2 so the midpoint is
           | (0.707,0,0.707) your gradient will look much better. Although
           | other commenters suggested mixing in more complicated colour
           | spaces.
        
         | rikroots wrote:
         | I agree with the colorspace alert. Lerping red and blue in
         | OKLAB or OKLCH colorspace produces a much nicer effect. Also,
         | the article details linear interpolation, but I think there's a
         | lot of fun to be had by introducing some easing functionality
         | into the interpolation[1] - it's not difficult to achieve in
         | code, even in shader code?
         | 
         | I do disagree with the article about the need to do such work
         | in the WebGL space. Modern CPUs are insanely fast nowadays, and
         | browsers have put in a lot of work over the past few years to
         | make the Canvas 2D API as performant as possible - including
         | moving as much work as possible into the GPU behind the scenes.
         | With a bit of effort, gradients can be animated in 2D canvases
         | in many interesting ways![2][3]
         | 
         | [1] - Easing a linear gradient in different color spaces:
         | https://scrawl-v8.rikweb.org.uk/demo/canvas-003.html
         | 
         | [2] - Animated gradient effect:
         | https://codepen.io/kaliedarik/pen/poRLBLp
         | 
         | [3] - Animating a gradient over a live video feed:
         | https://codepen.io/kaliedarik/pen/MWMQyJZ
        
         | meindnoch wrote:
         | WebGL/OpenGL doesn't use sRGB in the shaders. If you load an
         | sRGB texture, or render to an sRGB surface, the API
         | automatically applies the gamma- (or inverse gamma) curve, so
         | the shader only ever sees the linear values.
        
           | kookamamie wrote:
           | Correct, it uses just numbers without any specific
           | information about a colorspace being involved. Decoding and
           | encoding sRGB happen during (texture) read and write stages.
        
       | sly010 wrote:
       | Very cool, but by css-rotating (skewY(-6deg)) the canvas at the
       | last moment, you introduced aliasing on the border between the
       | canvas and the rest of the page which kills the vibe. The browser
       | can't automatically blend the canvas with the rest of the page.
       | It's noticeable even on a brand new retina display. Maybe you
       | could keep your canvas square and introduce the skew in the
       | shader.
        
         | danwills wrote:
         | Guess it depends on the browser as it looks sharp and free of
         | aliasing for me, including when zooming in (Opera on Android)
        
           | herpdyderp wrote:
           | - Safari: decent but still obviously present       - Chrome:
           | quite bad looking       - Firefox: something in between
           | 
           | (tested on macOS)
        
         | andrewmcwatters wrote:
         | The funny thing is, as far as I know, skewY is a virtual draw
         | command in the WebKit family of rendering engines.
         | 
         | It's "in the shader" already. For whatever reason, your
         | browser's compositor is failing to anti-alias the rendering
         | bounds of the canvas.
         | 
         | I don't know why, though. I don't see the issue in Safari on my
         | system.
        
         | vanyle wrote:
         | As a workaround, you can add a transparent border (border: 2px
         | solid transparent) around the skewed element to have
         | antialiasing (at least on chrome)
        
       | herpdyderp wrote:
       | The linked source code [0] doesn't seem to have any license
       | attached to it. So how could I actually use this? Is it published
       | as a package somewhere, like npm?
       | 
       | 0.
       | https://github.com/alexharri/website/blob/eb9551dd7312685704...
        
         | alexharri wrote:
         | Hmm, good point. I'm abroad this week and don't have a laptop,
         | but I'll look at adding an MIT licence to the shader itself
         | when I'm home. (I don't want the post contents to be MIT
         | licensed, but the website code and examples should be)
         | 
         | Thanks for raising this
        
       | ikesau wrote:
       | Jesus christ, this is _such_ a polished article. Writing it must
       | have taken at least 5 times as long as the shader!
       | 
       | Have reblogged it and will refer back to it if ever I have some
       | time to learn how to write them :)
        
         | alexharri wrote:
         | Thanks a lot! Yeah tons of work went into this post, I've been
         | working on it since November. The shader itself was about 2-3
         | weeks of evenings to get the effect 90% of the way
        
       | heinternets wrote:
       | This looks very smooth. Would this be in 10 bit colour if the
       | display supports it? I can't see any banding even when zoomed in
       | Safari or Brave on a MBP with HDR display.
        
       | polygot wrote:
       | Reminds me of the JetBrains installer--not a bad reminder, I like
       | the animations.
        
       | mrmagoo17 wrote:
       | We need more articles as polished as this one. WebGL is a topic I
       | wanted to get into for a while now but it's really difficult to
       | find good content about it. Please keep sharing more experiments!
        
         | flashblaze wrote:
         | Could not agree more. Heard good things about
         | https://webgl2fundamentals.org/, but I think it directly jumps
         | into code without any background as such. At least that is what
         | I felt. Not sure whether this is the only way to go about
         | teaching WebGL.
        
           | loige wrote:
           | Thanks for sharing this one. I was looking for more material
           | too!
        
       | fallinditch wrote:
       | Great post Alex, the gradients are lovely, I'm just starting to
       | play around with webgl so the timing is perfect ...
        
       | ww520 wrote:
       | This is a great read. Very instructional. Build from simple
       | concepts and explain clearly. Kudos for the work.
        
       | qiqitori wrote:
       | Nice, it's a bit like an extremely modern version of the oldskool
       | plasma effect!
        
       | tomaskafka wrote:
       | The whole time I was expecting just a 2d height field ("terrain")
       | with animated noise as z, overlooked from an angle by an
       | isometric camera, it could imo produce a same effect in a much
       | simpler way (and without need for expensive blur), right?
        
         | akx wrote:
         | The blur here isn't expensive (as discussed in the article
         | itself).
         | 
         | Chances are sampling a 2D height field and projecting, etc.
         | would be more expensive.
        
       | grishka wrote:
       | This effect kinda reminds me of the PSP menu background
        
       | cloogshicer wrote:
       | Fantastic post, very well written.
        
       | kemuri wrote:
       | Amazing writeup, very inspiring!
        
       | kookamamie wrote:
       | Looks pretty nice. I think there'd be a way of computing the
       | blurriness without the iterative approach and without the
       | aliasing produced in the process.
        
       | smjburton wrote:
       | This is so cool. These flowing gradients have a mesmerizing
       | effect (almost like watching a lava lamp), and seem like a great
       | way to add visual interest to a page. I'll have to play around
       | with this and see if I can incorporate these flowing gradients
       | into some of my web projects. Awesome job detailing the design
       | process for this post.
        
       | zparky wrote:
       | This is an exemplary post and what I come to HN for.
        
       | nyarlathotep_ wrote:
       | This is an excellent article. Thanks for this.
        
       ___________________________________________________________________
       (page generated 2025-04-16 17:02 UTC)