Taps can be unreliable inside this app's built-in browser. For the full experience, use its menu to open this page in your browser.
Skip to content

The Candy Colours That Rendered Mud

A devlog by Neeraj Kotwani, who builds every game on Elipar.

Stack Tower was already finished when I came back to it. It had sound effects, a music loop, a real mute button, shadows, a squash-and-pop bounce on each placed block, and a camera that tracks the tower as it grows. Everything the catalogue entry promised was there.

Except one thing. The description calls it a "candy-coloured 3D tower", and the tower was dusty olive-brown. Not subtly — you would not use the word candy about it under any lighting.

You cannot read a WebGL canvas back the easy way

I wanted numbers rather than an opinion, so the first attempt was to pull the canvas into a 2D context and sample pixels. Every pixel came back zero with zero alpha.

The renderer is not created with preserveDrawingBuffer, and without it the backing buffer can already be cleared by the time script runs after the browser's own composite. There is nothing left to copy.

The way round it is to take a real screenshot — which always works, because it goes through the compositor — and then sample that PNG's pixels in a second page. Slightly absurd, but it turns "does this look candy-coloured" into a saturation figure, and from there it is an engineering problem.

The lighting maths is a floor you cannot tune past

Measured, the rendered blocks were sitting at roughly 0.15 to 0.19 saturation. Candy is not that.

The first instinct is that the source colours are too weak, so I pushed them. The blocks were generated from a formula — walk the hue wheel in fixed steps at fixed saturation and lightness — so saturation went from 0.62 to 0.88, a big jump.

Rendered saturation moved from about 0.15 to about 0.27.

That ratio turned out to be remarkably stable: MeshStandardMaterial was desaturating every block by roughly 0.31× its source colour, more or less regardless of how saturated the source was. Physically-based shading mixes in the light's own colour and the ambient term, and the result is a hard ceiling on how vivid a lit surface can read. Whitening the light tint and dropping roughness each moved it by about the same small amount, and then stopped. The lighting maths is the floor, not the light colour.

So "turn the saturation up" is not a fix here. It was worth measuring rather than iterating on, because three more rounds of nudging numbers would have produced three more barely-different screenshots.

The hue wheel was the actual villain

The second problem was independent of the first and, in hindsight, larger.

The colour was a continuous walk round the hue wheel: 26 degrees per block. That sounds pleasant and it has a nasty property. Marching in even steps means you spend an even amount of time in every hue band, including the stretch from about 78 to 156 degrees — yellow-green through green. At 26 degrees a step that is four or five consecutive blocks in that band.

Four blocks in a row of yellow-green, at the saturation ceiling above, reads as olive. As vegetable. You do not perceive the tower as a hue ramp, you perceive the three or four blocks currently on screen, and for a good fraction of any tower those were all in the one band nobody would call candy.

I stopped trying to tune the formula. The blocks now cycle through a curated palette of eight hex colours — pink, gold, mint, sky blue, lavender, coral, magenta, teal — with no two adjacent entries in the same hue family. Same fix pattern as the match-3 game on this site, which draws its candies from a fixed set rather than generating them.

Chosen by rendering candidates and re-measuring after each round, not by eye: rendered saturation came out between 0.35 and 0.47, against 0.15 to 0.19 for the formula even with its source saturation boosted. The screenshot finally shows a tower you would describe as candy.

A hand-picked list of eight is less elegant than one line of hue arithmetic. It is also the only version that produced the thing the description had been claiming for months.

The camera was fine, and I checked anyway

This catalogue has a history of broken isometric follow-cameras, so I did not want to assume. With a 30-block tower built through a debug hook, the top block projected to within 0.004 of the exact centre of the frame, and the moving block at the extreme of its swing projected to 0.981 — tight against the edge of the view, but inside it.

No change needed. That is still a real check rather than padding, because the alternative was finding out from a player that the block they were aiming disappeared off the side at tower height 30.

Which axis is this block sliding on, exactly

Two test failures in a row, both mine, both the same misunderstanding.

The moving block alternates its axis by the tower height — odd heights slide along X, even heights along Z. So which stored dimension gets sliced flips on every single drop.

A test that reads the width unconditionally is therefore right half the time and silently wrong the other half. Mine first reported a real slice as "unsliced". Then, after I fixed that, it computed a "total miss" offset using the previous drop's sliced dimension instead of the current axis's real size — which produces a partial slice instead of a miss, so the test sat waiting for a game-over screen that was never going to appear.

Both times the game was correct. I traced it with a dedicated hook that returns the axis, the offset and the resulting overlap from inside the closure, rather than trying to guess the expected values from outside. When a test is wrong about which of two symmetric cases it is in, asking the code which case it is in beats reasoning about it.

The suite that came out of it is sixteen checks: a perfect drop keeps the full size, a partial overlap slices to exactly the measured overlap width on the correct axis, the next moving block inherits the sliced size rather than the old one, a genuine total miss ends the run, and exactly one score is reported matching the blocks actually stacked.

Stack Tower is free in a browser, no account, no download. The blocks are the colour the description says they are now.

We use cookies to keep games running and, once ads are live, to show relevant content. See our Privacy Policy for details.