Hi there! This one will be quick. Let's let the code speak for itself for a change. ![[innocent-gradient-fun.webp]] A week back or so I saw a [video by a channel called Texture Labs](https://www.youtube.com/watch?v=1poWgZWpsiY&t=22s) explaining a simple shading technique using gradients, grain and posterise. I thought it would be a fun thing to play with, so here you go. [Just Some Innocent Gradient Fun](https://grain.potato.horse) is a simple graphics editor demonstrating the technique mentioned in the video. > [!NOTE] **Check it out [here](https://grain.potato.horse/).** <marquee style='font-family: cursive; font-size: 2em'> or <a href='//grain.potato.horse' target='_blank'>heeere</a> </marquee> ### How it works: The video does a pretty good job explaining the effect itself, so I recommend watching it out for more context. The process boils down to 4 steps: 1. desaturate the base image 2. apply the noise 3. reduce the number of colours to 3-5 steps (e.g. using *posterize*) 4. apply a gradient mask I prefer learning by playing, tweaking, and breaking things. So I added a bit of UI to control different parts of the effect, in case you're similar to me in that regard: ![[innocent-gradient-fun-bela.webp]] ### How it works in HTML + CSS If you're interested in a longer write-up, [let me know](mailto:[email protected]). Today, we're [[Half-ass it|half-assing]] things. In short, the image is wrapped in a bunch of HTML elements called *Layers*. Each *Layer* has a `filter: url(#some-svg-filter)` applied to it. Those `#some-svg-filter` IDs point to an invisible SVG element with SVG filter definitions. ```html <div className={styles.layer} style={ { filter: 'url("#posterize")' } } > <img ...> ``` ```jsx <svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="display: none;"> <defs> <filter id="posterize"> <feComponentTransfer> <feFuncR type="discrete" tableValues={posterSteps} /> <feFuncG type="discrete" tableValues={posterSteps} /> <feFuncB type="discrete" tableValues={posterSteps} /> </feComponentTransfer> </filter> ... </defs> </svg> ``` In a real world scenario, you could do just fine with 1-2 DOM elements because CSS filters can be stacked. I kept them separate to make the code easier to read and mess with. ### What I've learned: [[Just Some Innocent Gradient Fun/SVG filter quirks]] ### Next steps: Not much. This was fun to play with, but I'm trying to me more selective with my time since I have more important things to wrap up this year (like the next version of [Ensō](https://enso.sonnet.io)!) OK, there's one tempting idea: creating a web component that wraps an image element to render it in the style of [Return of the Obra Dinn](https://store.steampowered.com/app/653530/Return_of_the_Obra_Dinn/) or applies a dithering effect like some of the bio entries on this site ([[Wislawa Szymborska]], [[Zygmunt Bauman]]). ### Why I made it: 1. [[Share your unfinished, scrappy work]] 2. [[Dog mode]] 3. [[Why make toys, why play?]] (I needed to get out of a rut, and sometimes making useless things helps me get back on track.) Thanks for reading, see you tomorrow! ![[innocent-gradient-fun.png]]