Pekka Väänänen
banner
pekkavaa.bsky.social
Pekka Väänänen
@pekkavaa.bsky.social
Avid reader, computer graphics fan and atmospheric jungle beats enjoyer. Demoscene: cce/Peisik.

Blog at https://30fps.net/
Pinned
Some of you might know that I've been working on a book. Today I'm happy to announce

Palette Programming: A Modern Guide to Color Quantization
paletteprogramming.com

It's a textbook on how to design palettes and represent images using them. Will be out this year. Code in Python & NumPy.
Reposted by Pekka Väänänen
Awesome writeup on the power of pre-splitting for producing high-quality BVHs:
github.com/BoyBaykiller...
One interesting quote: "You may notice PreSplitting improves performance but increases the SAH cost. SAH is not a perfect predictor of performance."
GitHub - BoyBaykiller/IDKEngine: OpenGL Toy-"Engine" with Wavefront Path Tracer and Rasterizer with Voxel Cone Tracing/Global Illumination
OpenGL Toy-"Engine" with Wavefront Path Tracer and Rasterizer with Voxel Cone Tracing/Global Illumination - BoyBaykiller/IDKEngine
github.com
January 29, 2026 at 12:40 PM
I'm starting to get attached to these fast & loose diagram sketches I'm doing for my book. But redrawing them as clean vector art allows easier editing so it's worth the trouble.
January 22, 2026 at 8:32 AM
Here's a little project I've been working on: Liero64 - a port of the 1998 MS-DOS game for the Nintendo 64.

Gameplay video: youtu.be/aemLngAjEi8
ROM: codeberg.org/pekkavaa/Lie...
[N64] Liero64 Gameplay
The classic 1998 MS-DOS game Liero is now on the Nintendo 64! This video shows me (left) playing against the CPU opponent (right). Download the ROM at…
youtu.be
January 18, 2026 at 11:17 AM
Reposted by Pekka Väänänen
screenshots of the startmap I built for qbj3 or Quake Brutalist Jam III
some fancy bits in here will be in the coming update, like the paintings and plaques
January 11, 2026 at 9:52 PM
A comparison of the Pillow library's Maximum Coverage color quantizer settings. A palette that works well for dithering may not look great on its own. Here the top result has garish colors but when it's used when dithering (second from top), it's actually quite OK.
January 12, 2026 at 8:32 AM
Reposted by Pekka Väänänen
Built a palette extractor that thinks like a curator, not a pixel counter.

– Physics-based color repulsion
– Auto-detects muted vs vibrant bias
– Adaptive spacing to hit target count
– OKLCh color space (perceptually uniform)

Early Access: please break it!

chipper-otter-d6c600.netlify.app
January 8, 2026 at 7:51 PM
Some of you might know that I've been working on a book. Today I'm happy to announce

Palette Programming: A Modern Guide to Color Quantization
paletteprogramming.com

It's a textbook on how to design palettes and represent images using them. Will be out this year. Code in Python & NumPy.
January 7, 2026 at 3:13 PM
Reposted by Pekka Väänänen
a couple 3D aabb tricks:

gpfault.net/posts/aabb-t...
A Couple 3D AABB Tricks
gpfault.net
December 24, 2025 at 7:55 AM
Reposted by Pekka Väänänen
Ecstatica II (1997)

Developed by Andrew Spencer Studios.
December 21, 2025 at 9:48 AM
I've been reading up on k-means clustering again. I learned that scikit-learn's default "k-means++" init is actually "greedy": it does multiple attempts when randomly picking the next center to add. And the default value for the number of tries is based on an offhand remark in the original paper.
December 19, 2025 at 8:32 AM
I tried to use premultiplied alpha on the Nintendo 64 but I don't think it's actually possible. The hw blending equation does an unfortunate rounding when mixing colors, adding some black even in fully transparent pixels. Left: Straight alpha, Right: My attempt at premultiplied alpha.
December 12, 2025 at 8:32 AM
I was looking for how to make deleting files a tiny bit safer in shell scripts and found this subtly terrible StackOverflow answer. Consider the case where $SOMEPATH is empty and what does `cd` do then 🤠
December 9, 2025 at 6:56 PM
I've been reading about color science for my book and I wanted to verify the claim that Oklab gives better linear gradients than the otherwise excellent "CAM16-UCS" color space. And yes, its gradient obviously too desaturated in this test. Oklab's ancestor "IPT" also works fine.
December 4, 2025 at 5:32 PM
It's lovely when I see dedication to an experiment: keeping a CRT on for a month to avoid affecting its color reproduction. From Fritz Ebner's 1998 dissertation: repository.rit.edu/theses/2858/ The same hue matching experiment data was used by Björn Ottosson when creating the Oklab color space.
November 27, 2025 at 2:00 PM
Here's an unexpectedly brilliant introduction to perceptual color spaces www.youtube.com/watch?v=nJlZ...
A perceptual color space in Minecraft (Oklab)
What is a perceptual uniform color space and how can we use it in Minecraft. Link to Oklab post https://bottosson.github.io/posts/oklab/ World…
www.youtube.com
November 25, 2025 at 6:56 PM
I recently translated my book manuscript (it's about palettes) to Typst and been pretty happy so far. Today instead of writing I procrastinated by moving code snippets' line numbers over the left margin to salvage three extra characters of horizontal space😃
November 21, 2025 at 6:56 PM
The Wikipedia page on Color appearance models at en.wikipedia.org/wiki/Color_a... surprisingly good: to the point but still feels comprehensive. Includes a quick comparison of different perceptual color spaces.
Color appearance model - Wikipedia
A color appearance model (CAM) is a mathematical model that seeks to describe the perceptual aspects of human color vision, i.e. viewing conditions under which the appearance of a color does not…
en.wikipedia.org
November 17, 2025 at 8:32 AM
Reposted by Pekka Väänänen
via the magic of laion_clap embeddings and umap, my live coding thingy has a sample browser at last!
October 31, 2025 at 6:27 PM
What if Doom's "colormap" was computed in Oklab instead of RGB?

A short article about it on my site: 30fps.net/pages/doom-o...
October 30, 2025 at 8:32 AM
Reposted by Pekka Väänänen
Silent Hill 4 uses interesting volumetric light / light glare approximation.
Instead of drawing sprites at each light source, full-screen subdivided plane with procedural vertex colors is rendered and blended with game frame.
#gamedev
October 29, 2025 at 12:53 AM
Relatable😑
From: doomwiki.org/wiki/Carmack...
The line in question: github.com/linguica/dmu...
October 27, 2025 at 8:32 AM
A new article: Why CIELAB doesn’t improve median cut

It's a common misconception that CIELAB will instantly improve palettes produced by the median cut algorithm. Unfortunately it's not that simple.

📜 30fps.net/pages/median...

It gets pretty technical but I added some context to the intro.
October 24, 2025 at 12:50 PM
Wow I didn't know Python has cute chained comparisons: "e.g., x < y <= z is equivalent to x < y and y <= z, except that y is evaluated only once (but in both cases z is not evaluated at all when x < y is found to be false)."

docs.python.org/3/reference/...
6. Expressions
This chapter explains the meaning of the elements of expressions in Python. Syntax Notes: In this and the following chapters, extended BNF notation will be used to describe syntax, not lexical anal...
docs.python.org
October 23, 2025 at 11:52 AM
A fun look into Source 2's precomputed visibility from a mapper's perspective: www.youtube.com/watch?v=XLT2... It's not a BSP anymore but an octree whose nodes get grouped into clusters. Spoiler: Visleaks can still happen😀
CS2 Mapping Academy #10 - VIS Optimization (Counter Strike 2)
VIS is one of the most important facets of Source 2 level design. Learning how the engine optimizes your maps is important so that everyone can enjoy it! Learn how to take control of VIS in this…
www.youtube.com
October 21, 2025 at 11:52 AM