# The Last Static Blog RSS

Default feed for blog.pkh.me

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## A series of tricks and techniques I learned doing tiny GLSL demos

DevFeed: [A series of tricks and techniques I learned doing tiny GLSL demos](<https://devfeed.tech/articles/a-series-of-tricks-and-techniques-i-learned-doing-tiny-glsl-demos-26122.md>)

Original publisher: [Read original article](<http://blog.pkh.me/p/48-a-series-of-tricks-and-techniques-i-learned-doing-tiny-glsl-demos.html>)

Published: 2025-12-07T17:48:26Z

Content type: tutorial

Language: en

Sources: [The Last Static Blog RSS](<https://devfeed.tech/sources/the-last-static-blog-rss.md>)

Topics: [glsl](<https://devfeed.tech/topics/glsl.md>), [Demo](<https://devfeed.tech/topics/demo.md>), [Code](<https://devfeed.tech/topics/code.md>), [iteration](<https://devfeed.tech/topics/iteration.md>), [color](<https://devfeed.tech/topics/color.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [demo](<https://devfeed.tech/tags/demo.md>), [fun](<https://devfeed.tech/tags/fun.md>), [glsl](<https://devfeed.tech/tags/glsl.md>), [graphics](<https://devfeed.tech/tags/graphics.md>), [iteration](<https://devfeed.tech/tags/iteration.md>), [math](<https://devfeed.tech/tags/math.md>), [prog](<https://devfeed.tech/tags/prog.md>), [techniques](<https://devfeed.tech/tags/techniques.md>), [tricks](<https://devfeed.tech/tags/tricks.md>)

### AI overview

This tutorial examines four tiny GLSL demos--Moonlight, Entrance 3, Archipelago, and Cutie--and explains selected techniques learned while creating them. It introduces an alternative raymarching approach using inverse-density color contributions and relates it to photon-density integration.

### Source excerpt

In the past two months or so, I spent some time making tiny GLSL demos. I wrote an article about the first one, Red Alp. There, I went into details about the whole process, so I recommend to check it out first if you're not familiar with the field. We will look at 4 demos: Moonlight, Entrance 3, Archipelago, and Cutie. But this time, for each demo, we're going to cover one or two things I learned from it. It won't be a deep dive into every aspect because it would be extremely redundant. Instead, I'll take you along a journey of learning experiences. Moonlight Moonlight demo in 460 characters // Moonlight [460] by bµg // License: CC BY-NC-SA 4.0 void main(){vec3 o,p,u=vec3((P+P-R)/R.y,1),Q;Q++;for(float d,a,m,i,t;i++<1e2;p=t<7.2?Q:vec3(2,1,0),d=abs(d)*.15+.1,o+=p/m+(t>9.?d=9.,Q:p/d),t+=min(m,d))for(p=normalize(u)*t,p.z-=5e1,m=max(length(p)-1e1,.01),p.z+=T,d=5.-length(p.xy*=mat2(cos(t*.2+vec4(0,33,11,0)))),a=.01;a<1.;a+=a)p.xz*=mat2(8,6,-6,8)*.1,d-=abs(dot(sin(p/a*.6-T*.3),p-p+a)),m+=abs(dot(sin(p/a/5.),p-p+a/5.));o/=4e2;O=vec4(tanh(mix(vec3(-35,-15,8),vec3(118,95,60),o-o*length(u.xy*.5))*.01),1);} Note See it on its official page, or play with the code on its Shadertoy portage. In Red Alp, I used volumetric raymarching to go through the clouds and fog, and it took quite a significant part of the code to make the absorption and emission convincing. But there is an alternative technique that is surprisingly simpler. In the raymarching loop, the color contribution at each iteration becomes 1/d or c/d where d is the density of the material at the current ray position, and c an optional color tint if you don't want to work in grayscale level. Some variants exist, for example 1/d^2, but we'll focus on 1/d. 1/d explanation Let's see how it looks in practice with a simple cube raymarch where we use this peculiar contribution: One glowing and rotating cube void main() { float d, t; vec3 o, p, u = normalize(vec3(P+P-R,R.y)); // screen to world coordinate for (int i = 0; i < 30

## Text rendering and effects using GPU-computed distances

DevFeed: [Text rendering and effects using GPU-computed distances](<https://devfeed.tech/articles/text-rendering-and-effects-using-gpu-computed-distances-26121.md>)

Original publisher: [Read original article](<http://blog.pkh.me/p/47-text-rendering-and-effects-using-gpu-computed-distances.html>)

Published: 2025-11-01T17:20:06Z

Content type: tutorial

Language: en

Sources: [The Last Static Blog RSS](<https://devfeed.tech/sources/the-last-static-blog-rss.md>)

Topics: [GPU](<https://devfeed.tech/topics/gpu.md>), [signed distance functions](<https://devfeed.tech/topics/signed-distance-functions.md>), [Font](<https://devfeed.tech/topics/font.md>), [Algorithm](<https://devfeed.tech/topics/algorithm.md>), [Mobile](<https://devfeed.tech/topics/mobile.md>)

Tags: [algorithm](<https://devfeed.tech/tags/algorithm.md>), [code](<https://devfeed.tech/tags/code.md>), [compute](<https://devfeed.tech/tags/compute.md>), [effects](<https://devfeed.tech/tags/effects.md>), [fonts](<https://devfeed.tech/tags/fonts.md>), [gpu](<https://devfeed.tech/tags/gpu.md>), [graphics](<https://devfeed.tech/tags/graphics.md>), [math](<https://devfeed.tech/tags/math.md>), [mobile](<https://devfeed.tech/tags/mobile.md>), [prog](<https://devfeed.tech/tags/prog.md>), [render](<https://devfeed.tech/tags/render.md>), [text](<https://devfeed.tech/tags/text.md>)

### AI overview

This tutorial explains how to compute signed distance fields for text glyphs on the GPU. It covers extracting glyph outlines, representing lines and Bézier curves as cubics, implementing the algorithm in a shader, and the trade-offs and effects enabled by the approach.

### Source excerpt

Text rendering is cursed. Anyone who has worked on text will tell you the same; whether it's about layout, bi-directional, shaping, Unicode, or the rendering itself, it's never a completely solved problem. In my personal case, I've been working on trying to render text in the context of a compositing engine for creative content. I needed crazy text effects, and I needed them to be reasonably fast, which implied working with the GPU as much as possible. The distance field was an obvious requirement because it unlocks anti-aliasing and the ability to make many great effects for basically free. In this article, we will see how to compute signed distance field on the GPU because it's much faster than doing it on the CPU, especially when targeting mobile devices. We will make the algorithm decently fast, then after lamenting about the limitations, we will see what kind of effects this opens up. Progressive build of the 'あ' glyph from the Mochiy Pop One font Extraction of glyph outlines Non-bitmap fonts contain glyphs defined by outlines made of closed sequences of lines and (quadratic or cubic) Bézier curves. Extracting them isn't exactly complicated: FreeType or ttf-parser typically expose a way to do that. For the purpose of this article, we're going to hard code the list of the Bézier curves inside the shader, but of course in a more serious setup those would be uploaded through storage buffers or similar. Using this tiny program, a glyph can be dumped as series of outlines into a fixed size array: struct Bezier { vec2 p0; // start point vec2 p1; // control point 1 vec2 p2; // control point 2 vec2 p3; // end point }; #define N 42 #define NC 2 const int glyph_A_count[2] = int[](33, 9); const Bezier glyph_A[42] = Bezier[]( Bezier(vec2( 0.365370, -0.570817), vec2( 0.374708, -0.631518), vec2( 0.332685, -0.687549), vec2( 0.339689, -0.748249)), Bezier(vec2( 0.339689, -0.748249), vec2( 0.339689, -0.748249), vec2( 0.344358, -0.764591), vec2( 0.351362, -0.771595)), Bezier(vec2

## Fast calculation of the distance to cubic Bezier curves on the GPU

DevFeed: [Fast calculation of the distance to cubic Bezier curves on the GPU](<https://devfeed.tech/articles/fast-calculation-of-the-distance-to-cubic-bezier-curves-on-the-gpu-26120.md>)

Original publisher: [Read original article](<http://blog.pkh.me/p/46-fast-calculation-of-the-distance-to-cubic-bezier-curves-on-the-gpu.html>)

Published: 2025-10-18T09:21:56Z

Content type: article

Language: en

Sources: [The Last Static Blog RSS](<https://devfeed.tech/sources/the-last-static-blog-rss.md>)

Topics: [GPU](<https://devfeed.tech/topics/gpu.md>), [glsl](<https://devfeed.tech/topics/glsl.md>), [WebGL](<https://devfeed.tech/topics/webgl.md>), [shaders](<https://devfeed.tech/topics/shaders.md>), [pixel](<https://devfeed.tech/topics/pixel.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [glsl](<https://devfeed.tech/tags/glsl.md>), [gpu](<https://devfeed.tech/tags/gpu.md>), [graphics](<https://devfeed.tech/tags/graphics.md>), [math](<https://devfeed.tech/tags/math.md>), [maths](<https://devfeed.tech/tags/maths.md>), [pixel](<https://devfeed.tech/tags/pixel.md>), [prog](<https://devfeed.tech/tags/prog.md>), [shaders](<https://devfeed.tech/tags/shaders.md>), [source](<https://devfeed.tech/tags/source.md>), [visualization](<https://devfeed.tech/tags/visualization.md>), [webgl](<https://devfeed.tech/tags/webgl.md>), [webgl-demo](<https://devfeed.tech/tags/webgl-demo.md>)

### AI overview

This article explains how to calculate the distance from a point to a cubic Bézier curve on the GPU. It derives the distance function and its derivative, reducing the problem to solving a fifth-degree polynomial, and demonstrates the method with self-contained GLSL fragment shaders and WebGL visualizations.

### Source excerpt

Bézier curves are a core building block of text and 2D shapes rendering. There are several approaches to rendering them, but one especially challenging problem, both mathematically and technically, is computing the distance to a Bézier curve. For quadratic curves (one control point), this is fairly accessible, but for cubic (two control points) we're going to see why it is so hard. A glyph from the Virgil font, composed of multiple Bézier curves Having this distance field opens up many rendering possibilities. It's hard, but it's possible; here is a live proof: Distance to a cubic Bézier curve In this visualization, I'm borrowing your device resources to compute the distance to the curve for every single pixel. The yellow points are the control points of the curve (in white) and the blue zone is a representation of the distance field. Note All the demos and code in this article are self-contained GLSL fragment shaders. Most of the code can be found in the article, but feel free to inspect the source code of any of these WebGL demo for the complete code. They can be run verbatim using ShaderWorkshop. The basic maths In a previous article, we explained that a Bézier curve can be expressed as a polynomial. In our case, a cubic polynomial: B_3(t) = \textbf{a}t^3 + \textbf{b}t^2 + \textbf{c}t + \textbf{d} Where a, b, c and d are the vector coefficients derived from the start (P_0), end (P_3), and control points (P_1, P_2) using the following formulas (you can refer to the previous article for details): \begin{aligned} \textbf{a} &= -P_0 + 3(P_1-P_2) + P_3 \\ \textbf{b} &= 3P_0 - 6P_1 + 3P_2 \\ \textbf{c} &= -3P_0 + 3P_1 \\ \textbf{d} &= P_0 \end{aligned} For a given point p in 2D space, the distance to that Bézier curve can be expressed as a length between our curve and p: \begin{aligned} d(t) &= ||B_3(t) - \textbf{p}|| \\ &= ||\textbf{a}t^3 + \textbf{b}t^2 + \textbf{c}t + \textbf{d} - \textbf{p}|| \end{aligned} Our goal is to find the t value where d(t) is the smallest.

## Code golfing a tiny demo using maths and a pinch of insanity

DevFeed: [Code golfing a tiny demo using maths and a pinch of insanity](<https://devfeed.tech/articles/code-golfing-a-tiny-demo-using-maths-and-a-pinch-of-insanity-26119.md>)

Original publisher: [Read original article](<http://blog.pkh.me/p/45-code-golfing-a-tiny-demo-using-maths-and-a-pinch-of-insanity.html>)

Published: 2025-09-29T13:30:50Z

Content type: tutorial

Language: en

Sources: [The Last Static Blog RSS](<https://devfeed.tech/sources/the-last-static-blog-rss.md>)

Topics: [glsl](<https://devfeed.tech/topics/glsl.md>), [Code](<https://devfeed.tech/topics/code.md>), [Canvas](<https://devfeed.tech/topics/canvas.md>), [coding](<https://devfeed.tech/topics/coding.md>)

Tags: [3d](<https://devfeed.tech/tags/3d.md>), [canvas](<https://devfeed.tech/tags/canvas.md>), [code](<https://devfeed.tech/tags/code.md>), [coding](<https://devfeed.tech/tags/coding.md>), [floating-point](<https://devfeed.tech/tags/floating-point.md>), [fun](<https://devfeed.tech/tags/fun.md>), [glsl](<https://devfeed.tech/tags/glsl.md>), [graphics](<https://devfeed.tech/tags/graphics.md>), [math](<https://devfeed.tech/tags/math.md>), [prog](<https://devfeed.tech/tags/prog.md>)

### AI overview

This tutorial explains how a 448-character GLSL fragment shader creates a procedural demo by evaluating mathematical formulas for each pixel. It examines the shader structure, WebGL2 canvas inputs, code-golfing techniques, and a local live-coding workflow.

### Source excerpt

A few weeks ago, I made a tiny demo that fits into 448 characters: Red Alp GLSL demo in 448 characters void main(){vec3 c,p,K=vec3(3,1,0);for(float z,i,a,g=1.,t,h,d,w,k=.15;i++<1e2;d=max(max(d-3. ,-d),a=z)*k,w=g-g/exp(h>.001?a++,d/.4:h*3e2),g-=a*=w,c+=a*d*4.5+(d>z?z:h/2e2)*K,a=min(p.y+2. ,1.),c.r+=w*a*a*.1,t+=min(h*.2,k/=.985))for(p=normalize(vec3(P+P-R,R.y))*t,p.xz*=mat2(cos( sin(T*.2)+K.zyxz*11.)),p.z+=T*.3,d=p.y,h=d+.5,a=.01;a<1.;a+=a)p.xz*=mat2(8,6,-6,8)*.1,d+=abs (dot(sin((p/a+T)*.3),p-p+a)),h+=abs(dot(sin(p.xz*.6/a),P-P+a));O=vec4(tanh(c),1);} Note The number of characters was 464 characters at first, but thanks to the community it got reduced further, and the article updated accordingly. There is no texture, no mesh, no 3D helper: it's simply a procedural mathematical formula evaluated at each pixel assigning them a color. Code golfing is about making it as short as possible, and thus is part of the art performance. To put things into perspective, the 853x480 JPEG thumbnail of this article is 167x larger than this code. You can watch a larger version on its main dedicated page, or a portage on Shadertoy (484 chars). If your device is not powerful enough (I'm sorry for the lag on this page) or doesn't support WebGL2, a short preview video can be seen on Mastodon. I'm guessing the wizardry of the code has confused many people so we're going to dive through the making-of together. Overall, this demo is a particularly dense and entangled compilation of different techniques, where each aspect could mandate a dedicated article. For that reason, some parts will prefer to link to external resources when the literacy is verbose on the subject. Warning Some demos in this article will start "decaying" over time due to floating point variables getting too large. Reloading the page should fix that. The base template The code is written in GLSL and is executed for each pixel (technically each fragment) on a simple quad geometry (to be accurate it's even a single big triang

## Perfecting anti-aliasing on signed distance functions

DevFeed: [Perfecting anti-aliasing on signed distance functions](<https://devfeed.tech/articles/perfecting-anti-aliasing-on-signed-distance-functions-26118.md>)

Original publisher: [Read original article](<http://blog.pkh.me/p/44-perfecting-anti-aliasing-on-signed-distance-functions.html>)

Published: 2025-07-26T14:29:32Z

Content type: article

Language: en

Sources: [The Last Static Blog RSS](<https://devfeed.tech/sources/the-last-static-blog-rss.md>)

Topics: [signed distance functions](<https://devfeed.tech/topics/signed-distance-functions.md>), [SDF](<https://devfeed.tech/topics/sdf.md>)

Tags: [functions](<https://devfeed.tech/tags/functions.md>), [graphics](<https://devfeed.tech/tags/graphics.md>), [math](<https://devfeed.tech/tags/math.md>), [prog](<https://devfeed.tech/tags/prog.md>), [sdf](<https://devfeed.tech/tags/sdf.md>), [signed-distance-functions](<https://devfeed.tech/tags/signed-distance-functions.md>), [visualization](<https://devfeed.tech/tags/visualization.md>)

### AI overview

This article explains why anti-aliasing signed distance functions is more complicated than applying hardcoded constants or generic formulas. It develops anti-aliasing approaches from SDF properties such as the unit-length gradient and considers both inside/outside sign conventions.

### Source excerpt

Doing anti-aliasing on SDF is not as straightforward as it seems. Most of the time, we see people use a smoothstep with hardcoded constants, sometimes with screen space information, sometimes cryptic or convoluted formulas. Even if SDFs have the perfect mathematical properties needed for a clean anti-aliasing, the whole issue has a scope larger than it appears at first glance. And even when trivial solutions exist, it's not always clear why they are a good fit. Let's study that together. SDF The article assumes that you are at least a bit familiar with what an SDF is, but if I had to provide a quick and informal definition, I would say something like: "It's a function (or lookup-table of said function, usually stored in a texture) which returns the signed distance from the specified coordinates to a given shape, where the sign indicates whether you're inside or outside the shape." A common visualization of it looks like this: SDF of a moving pie/pacman, using Inigo Quilez formula and colorscheme for visualization The distance is fancily colored here for illustrative purpose, and the shape is animated to see how it affects the field. Another way of seeing it is to switch to a 3D view: SDF of a moving pie/pacman, as seen in 3D For the sign interpretation, here we're using the convention positive inside and negative outside, as seen for example on the Wikipedia illustration. But this is not always the case, for example, Inigo prefers the opposite: negative inside and positive outside. I personally find the Wikipedia convention to be more intuitive and easy to work with, but that's a matter of preferences so we'll figure out the formulas for both models. Switching from one to the other is just a sign swap, but it's important to know what we are working with. Linear ramp A properly crafted SDF has a gradient of length 1, meaning the slope is either going up or down, but always at the same constant rate of 1: 1D side cut of an SDF depicting the gradient/slope This is an i

## Choosing sRGB, Linear RGB, and OkLab for Color Gradients

DevFeed: [Choosing sRGB, Linear RGB, and OkLab for Color Gradients](<https://devfeed.tech/articles/the-current-technology-is-not-ready-for-proper-blending-26117.md>)

Original publisher: [Read original article](<http://blog.pkh.me/p/43-the-current-technology-is-not-ready-for-proper-blending.html>)

Published: 2025-07-18T20:10:43Z

Content type: article

Language: en

Sources: [The Last Static Blog RSS](<https://devfeed.tech/sources/the-last-static-blog-rss.md>)

Topics: [glsl](<https://devfeed.tech/topics/glsl.md>), [color](<https://devfeed.tech/topics/color.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [color](<https://devfeed.tech/tags/color.md>), [glsl](<https://devfeed.tech/tags/glsl.md>), [graphics](<https://devfeed.tech/tags/graphics.md>), [math](<https://devfeed.tech/tags/math.md>), [prog](<https://devfeed.tech/tags/prog.md>), [technology](<https://devfeed.tech/tags/technology.md>)

### AI overview

This article examines how sRGB, linear RGB, and OkLab behave when generating color gradients. It explains that sRGB can produce muddy midtones, linear RGB models light energy correctly but may look less perceptually suitable, and OkLab generally provides the best perceptual result at a performance cost. It also notes that monochrome gradients produce different tradeoffs.

### Source excerpt

The idea that we must always linearize sRGB gradients or work in a perceptually uniform colorspace is starting to be accepted universally. But is it that simple? When I learned about the subject, it felt like being handed a hammer and using it everywhere. The reality is a bit more nuanced. In this article we will see when to use which, how to use them, and we will then see why the situation is more dire than it looks. Code snippets Before we start, since we are going to use GLSL as language, following are the reference functions we will use for the rest of the article. vec3 s2l(vec3 c) { // sRGB to linear return mix(c/12.92, pow((max(c,0.0)+0.055)/1.055,vec3(2.4)), step(vec3(0.04045),c)); } vec3 l2s(vec3 c) { // linear to sRGB return mix(c*12.92, 1.055*pow(max(c,0.0),vec3(1./2.4))-0.055, step(vec3(0.0031308),c)); } vec3 l2oklab(vec3 rgb) { // linear to OkLab const mat3 rgb2lms = mat3( +0.4122214708, +0.2119034982, +0.0883024619, +0.5363325363, +0.6806995451, +0.2817188376, +0.0514459929, +0.1073969566, +0.6299787005); const mat3 lms2lab = mat3( +0.2104542553, +1.9779984951, +0.0259040371, +0.7936177850, -2.4285922050, +0.7827717662, -0.0040720468, +0.4505937099, -0.8086757660); vec3 lms = rgb2lms * rgb; return lms2lab * pow(lms, vec3(1.0/3.0)); } vec3 oklab2l(vec3 lab) { // OkLab to linear const mat3 lab2lms = mat3( +1.0000000000, +1.0000000000, +1.0000000000, +0.3963377774, -0.1055613458, -0.0894841775, +0.2158037573, -0.0638541728, -1.2914855480); const mat3 lms2rgb = mat3( +4.0767416621, -1.2684380046, -0.0041960863, -3.3077115913, +2.6097574011, -0.7034186147, +0.2309699292, -0.3413193965, +1.7076147010); vec3 lms = lab2lms * lab; return lms2rgb * (lms*lms*lms); } Also, the output of the pipeline will be expected to be sRGB all the time. Color gradients To illustrate how sRGB, linear RGB and OkLab respectively look like, let's interpolate between two colors with each one of them: Color gradients from top to bottom: sRGB, linear, OkLab The 3 stripes were generate

## Understanding Gradient Noise with WebGL2 and GLSL

DevFeed: [Understanding Gradient Noise with WebGL2 and GLSL](<https://devfeed.tech/articles/sharing-everything-i-could-understand-about-gradient-noise-26116.md>)

Original publisher: [Read original article](<http://blog.pkh.me/p/42-sharing-everything-i-could-understand-about-gradient-noise.html>)

Published: 2025-06-06T14:45:38Z

Content type: tutorial

Language: en

Sources: [The Last Static Blog RSS](<https://devfeed.tech/sources/the-last-static-blog-rss.md>)

Topics: [glsl](<https://devfeed.tech/topics/glsl.md>), [GPU](<https://devfeed.tech/topics/gpu.md>), [Code](<https://devfeed.tech/topics/code.md>), [hashing](<https://devfeed.tech/topics/hashing.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [complexity](<https://devfeed.tech/tags/complexity.md>), [cpu](<https://devfeed.tech/tags/cpu.md>), [floating-point](<https://devfeed.tech/tags/floating-point.md>), [function](<https://devfeed.tech/tags/function.md>), [glsl](<https://devfeed.tech/tags/glsl.md>), [graphics](<https://devfeed.tech/tags/graphics.md>), [hashing](<https://devfeed.tech/tags/hashing.md>), [math](<https://devfeed.tech/tags/math.md>), [performance](<https://devfeed.tech/tags/performance.md>), [procedural](<https://devfeed.tech/tags/procedural.md>), [prog](<https://devfeed.tech/tags/prog.md>)

### AI overview

This tutorial explains gradient noise, beginning with its one-dimensional form and progressing through higher dimensions and complexity. It uses a GPU-oriented approach with WebGL2 and GLSL, including deterministic coordinate-based pseudo-random values and hashing considerations.

### Source excerpt

You've most likely heard about gradient noise through the name Perlin noise, which refers to one particular implementation with various CPU optimizations. Because it's an incredible tool for creative work, it's used virtually everywhere: visual effects, video games, procedural mathematical art, etc. While getting it right can sometimes be subtle, a "broken" implementation can still look good or interesting. After all, "it looks fine, and I'm an artist". In order to gain a deeper and more meaningful understanding we will start studying the 1D version (a case often omitted in the literature), then slowly climb our way up in dimensions and complexity. We'll also work from a GPU perspective rather than a CPU-based one, hence all code snippets and visuals here are implemented in WebGL2/GLSL (hopefully without being too heavy on performance). They should run on most modern devices; let me know if you run into issues. Before we begin, credit where it's due: most of the material here are nothing new. This article is the result of weeks of studying and experimenting with the maths from Inigo Quilez's incredible pages and other scattered resources over the Internet. But as rich and valuable these resources are, they sometimes move quickly over the details, assuming they're obvious. This post is an attempt to fill those gaps. A welcoming wavy 1D gradient noise signal Hashing function and pseudo-random values At the most elementary level, we need a deterministic coordinate based pseudo-random system. More specifically, for any given integer coordinate we need a random value, and as uniformly distributed as possible. Something like: \begin{aligned} h(-3) &= -0.006124 \\ h(-2) &= -0.996686 \\ h(-1) &= 0.200864 \\ h(0) &= -1.000000 \\ h(1) &= 0.053313 \\ h(2) &= -0.893312 \\ h(3) &= 0.854923 \\ \text{...} \end{aligned} Perlin's implementation relies on a permutation table, which is convenient when working on the CPU, but more awkward for a shader. On the GPU, most people rely on v

## Fixing the iterative damping interpolation in video games

DevFeed: [Fixing the iterative damping interpolation in video games](<https://devfeed.tech/articles/fixing-the-iterative-damping-interpolation-in-video-games-26115.md>)

Original publisher: [Read original article](<http://blog.pkh.me/p/41-fixing-the-iterative-damping-interpolation-in-video-games.html>)

Published: 2024-05-18T12:22:15Z

Content type: article

Language: en

Sources: [The Last Static Blog RSS](<https://devfeed.tech/sources/the-last-static-blog-rss.md>)

Topics: [Game Development](<https://devfeed.tech/topics/game-development.md>), [Godot](<https://devfeed.tech/topics/godot.md>), [callback](<https://devfeed.tech/topics/callback.md>), [function](<https://devfeed.tech/topics/function.md>), [Mathematics](<https://devfeed.tech/topics/mathematics.md>)

Tags: [callback](<https://devfeed.tech/tags/callback.md>), [fps](<https://devfeed.tech/tags/fps.md>), [game](<https://devfeed.tech/tags/game.md>), [game-development](<https://devfeed.tech/tags/game-development.md>), [games](<https://devfeed.tech/tags/games.md>), [math](<https://devfeed.tech/tags/math.md>), [physics](<https://devfeed.tech/tags/physics.md>), [prog](<https://devfeed.tech/tags/prog.md>)

### AI overview

This article explains why repeatedly applying linear interpolation for damping can make game behavior depend on the refresh rate. Using Godot examples, it analyzes the iterative formula and motivates a frame-rate-independent solution.

### Source excerpt

As I'm exploring the fantastic world of indie game development lately, I end up watching a large number of video tutorials on the subject. Even though the quality of the content is pretty variable, I'm very grateful to the creators for it. That being said, I couldn't help noticing this particular bit times and times again: a = lerp(a, B, delta * RATE) Behind this apparent banal call hides a terrible curse, forever perpetrated by innocent souls on the Internet. In this article we will study what it's trying to achieve, how it works, why it's wrong, and then we'll come up with a good solution to the initial problem. The usual warning: I don't have a mathematics or academic background, so the article is addressed at other neanderthals like myself, who managed to understand that pressing keys on a keyboard make pixels turn on and off. What is it? Let's start from the beginning. We're in a game engine main loop callback called at a regular interval (roughly), passing down the time difference from the last call. In Godot engine, it looks like this: func _physics_process(delta: float): ... If the game is configured to refresh at 60 FPS, we can expect this function to be called around 60 times per second with delta = 1/60 = 0.01666.... As a game developer, we want some smooth animations for all kind of transformations. For example, we may want the speed of the player to go down to zero as they release the moving key. We could do that linearly, but to make the stop less brutal and robotic we want to slow down the speed progressively. Linear (top) versus smooth/exponential (bottom) animation Virtually every tutorial will suggest updating some random variable with something like that: velocity = lerp(velocity, 0, delta * RATE) At 60 FPS, a decay RATE defined to 3.5, and an initial velocity of 100, the velocity will go down to 0 following this curve: Example curve of a decaying variable Note velocity is just a variable name example, it can be found in many other contexts If you

## Improving color quantization heuristics

DevFeed: [Improving color quantization heuristics](<https://devfeed.tech/articles/improving-color-quantization-heuristics-26113.md>)

Original publisher: [Read original article](<http://blog.pkh.me/p/39-improving-color-quantization-heuristics.html>)

Published: 2022-12-31T12:00:43Z

Content type: article

Language: en

Sources: [The Last Static Blog RSS](<https://devfeed.tech/sources/the-last-static-blog-rss.md>)

Topics: [quantization](<https://devfeed.tech/topics/quantization.md>), [color](<https://devfeed.tech/topics/color.md>), [Algorithm](<https://devfeed.tech/topics/algorithm.md>), [FFmpeg (Fast Forward Moving Picture Experts Group)](<https://devfeed.tech/topics/ffmpeg.md>), [Compression](<https://devfeed.tech/topics/compression.md>), [image animation](<https://devfeed.tech/topics/image-animation.md>)

Tags: [algorithm](<https://devfeed.tech/tags/algorithm.md>), [article](<https://devfeed.tech/tags/article.md>), [blog](<https://devfeed.tech/tags/blog.md>), [color](<https://devfeed.tech/tags/color.md>), [compression](<https://devfeed.tech/tags/compression.md>), [ffmpeg](<https://devfeed.tech/tags/ffmpeg.md>), [gif](<https://devfeed.tech/tags/gif.md>), [math](<https://devfeed.tech/tags/math.md>), [prog](<https://devfeed.tech/tags/prog.md>), [quantization](<https://devfeed.tech/tags/quantization.md>)

### AI overview

The article examines improvements to color quantization heuristics, including evaluating color distances in a perceptually uniform color space such as OkLab instead of using Euclidean distance between RGB values. It explains palette quantization as reducing an image's colors to a smaller representative subset, with applications including compression, limited-palette codecs such as GIF, and artistic effects.

### Source excerpt

In 2015, I wrote an article about how the palette color quantization was improved in FFmpeg in order to make nice animated GIF files. For some reason, to this day this is one of my most popular article. As time passed, my experience with colors grew and I ended up being quite ashamed and frustrated with the state of these filters. A lot of the code was naive (when not terribly wrong), despite the apparent good results. One of the major change I wanted to do was to evaluate the color distances using a perceptually uniform color space, instead of using a naive euclidean distance of RGB triplets. As usual it felt like a week-end long project; after all, all I have to do is change the distance function to work in a different space, right? Well, if you're following my blog you might have noticed I've add numerous adventures that stacked up on each others: I had to work out the colorspace with integer arithmetic first ...which forced me to look into integer division more deeply ...which confronted me to all sort of undefined behaviours in the process And when I finally reached the point where I could make the switch to OkLab (the perceptual colorspace), a few experiments showed that the flavor of the core algorithm I was using might contain some fundamental flaws, or at least was not implementing optimal heuristics. So here we go again, quickly enough I find myself starting a new research study in the pursuit of understanding how to put pixels on the screen. This write-up is the story of yet another self-inflicted struggle. Palette quantization But what is palette quantization? It essentially refers to the process of reducing the number of available colors of an image down to a smaller subset. In sRGB, an image can have up to 16.7 million colors. In practice though it's generally much less, to the surprise of no one. Still, it's not rare to have a few hundreds of thousands different colors in a single picture. Our goal is to reduce that to something like 256 colors that r