Gnome Garden — one T-pose, chopped: how the gnome finally got a face
Play it → sparkonelabs.com/gnomegarden
Four things landed in Gnome Garden this week. Three of them are about a single idea — that a picture made of independently generated pieces cannot agree with itself — and the fourth is a caching bug that made a day of work invisible.
The gnome came apart, and that is why he finally works
The gnome is an eleven-part cut-out puppet: hat, hat tip, head, beard, nose, body, two arms, two legs, tool. Thirteen animation clips pose those parts. For months he was drawn as vectors, because every attempt to give him real art produced the same wreck — and the note left in the source at the time is worth quoting, because it turned out to be the specification for the fix:
Eleven parts rendered independently cannot agree with each other. Even with every part correctly isolated, they disagree on proportion, on light direction, on line weight and on palette, because nothing told render #7 what render #3 looked like.
Asked for “the drooping tip of a gnome hat”, a diffusion model draws the gnome the tip belongs to — that is what the words are about. Four whole gnomes came back and the renderer stacked them.
The fix is not a better prompt. It is to stop asking a model for a part at all. One figure is drawn once, in a T-pose, and cut into eleven. The parts then share one lighting, one palette and one line weight by construction, because they were never separate. That is the whole difference, and it is structural rather than lucky.
Two things about the cut are not geometry, and both were learned the hard way. A limb has to rotate with its pivot: a T-pose arm is drawn horizontally and the rig hangs it from a shoulder, so cutting without rotating puts a 30×17 sleeve into a 30×71 socket and the gnome wears his arms as epaulettes. And the body has to keep its own beard pixels: the tidy instinct is to subtract them so nothing is stored twice, and the result is a body with a beard-shaped hole you see straight through the first frame the beard swings. The beard draws over the body, so the overlap is free and the hole is not.
The proportions were the actual finding
The vector gnome is deliberately chibi — his hat is 39% of his height. A gnome cut from a real drawing is not; the painted hat is 24%. Forcing the art into the vector rig’s sockets reproduces the original stacked-parts wreck exactly, and the parts are fine — the sockets are the wrong shape.
So the art was given its own geometry table rather than the rig being re-proportioned to suit it, and the reason is a contract: the game must be fully playable with the art directory deleted. That makes the vector gnome a tested fallback rather than a placeholder, and re-proportioning him to fit one sheet of imported art spends a guarantee to save a table.
The thirteen clips are not duplicated either. A clip frame is an offset from rest, not a position — so the renderer computes sprite_rest + (pose − vector_rest) and a wave is a wave on either gnome. That single property is what makes this a table and not a second rig.
He is behind Settings → Your gnome → Storybook gnome, off by default.
A bard frog, and thirty-two gnome-genre songs
There is now a frog on a toadstool in the bottom-left corner holding a lute. Tap him and he offers the two volume sliders and his whole repertoire.
He is a character rather than a settings cog on purpose. Every other control in this game is a garden object — the gnome is the avatar, the lantern is the light, the pouch is the purse — and a cog floating over a cottage garden is the one piece of furniture that would admit the whole thing is software.
His repertoire is thirty-two new tracks, written as parameter rows for a Csound engine and rendered on the CPU: gnome rap, techno, house, funk, disco, garage, breakbeat, trip-hop, afrobeat, ska, second line, samba, bhangra, rock, country, folk, bluegrass, surf, metal, sea shanty, waltz, polka, bossa nova, swing, lullaby, ragtime, klezmer, calypso, western, and two kinds of reggae. The joke is that every genre is played on a toy-box orchestra by a very small person who is thrilled about gardening — a four-on-the-floor kick under a marimba riff, not a warehouse — and it only works played completely straight.
The dub is real dub
Dub was requested by name, and dub is a problem for a parameter-driven engine, because the defining feature of the genre is not a timbre or a tempo — it is the echo, and there is no echo dial.
There is, however, a layer nobody had used. The engine’s layers are not patches, they are writers, each with its own idiom, and one of them writes a phrase and then answers it with its own quieter repeat three eighths later, mirrored across the stereo field, with real silence between. That is a tape delay written as notes rather than applied as an effect — so the dub track is the one place in the catalogue where the echo genuinely is the instrument. Reverb 0.88 against density 0.22 at a 72 bpm one-drop, because in dub the gaps are the arrangement.
Nine of thirty-two had to be re-rolled
A procedural loop can end on a value that does not match where it began, and the wrap then clicks. It is completely invisible in a waveform view and completely obvious on the fourth pass. Nine tracks came back over the threshold, and the fix was to re-roll the seed and nothing else — re-tuning tempo or density to dodge a seam would change what was written in order to fix a rendering artefact, whereas the seed changes which of the infinitely many loops a spec permits you get, and nothing about the spec.
The path tiles say what the level wants
The level-select screen was numbers and stars. The obvious upgrade is a painted tile per level, and there are 120 levels — most of a GPU day spent on decoration that says nothing.
The information a tile should carry was already in the data. Every level has an objective, and the simulation handles exactly nine kinds. So there are nine emblems, one per objective, and the tile now answers the question somebody actually has in front of a row they have not played: what does this one want? Both ends derive it — the screen reads the level’s first objective, and the build walks the levels to work out which emblems must exist — so a grove written with a new objective joins the vocabulary the moment it is authored rather than showing a blank tile in a screenshot.
The grove chips at the top get the same treatment, taken from each grove’s commonest objective. Bramblewick Lane gets brambles, Cocoon Copse a cocoon, Acorn Hollow an acorn — as a measurement, not an assignment.
The bug: a cache that made a day of work invisible
New soil went in — four painted bands, one per kingdom, replacing a three-stop gradient. It shipped, it was correct on the server, and it did not appear.
The loader fetches every picture with cache: 'force-cache': use the cached copy, never revalidate. That was right for as long as every key meant a fresh render into a fresh filename, and until then every one did. The soil was the first art ever replaced in place — same filenames, different pictures — so every browser that had already seen the old loam kept serving it. The manifest updated, the bytes updated, the screen did not, and the symptom was indistinguishable from the work never having shipped.
The manifest already carried a SHA-256 per asset for its integrity check, so the fix was to spend twelve characters of it on the URL. A changed picture is a changed URL and the cache misses honestly; an unchanged picture keeps its URL and stays exactly as fast as before.
Content-addressing is what makes an aggressive cache correct rather than merely quick.
force-cacheon a mutable name is a bug waiting for its first in-place replacement.
Everything above is live now. It runs in a phone browser, there is nothing to install, and nothing in it ever goes wrong.
Play it → sparkonelabs.com/gnomegarden