Lighting diyas with a Rive kid
Tuft is a kid in mustard overalls with a scrap-metal blaster. It doesn't fire a laser. It fires small balls of light, and each one is a real light in the courtyard behind him.
For Diwali I turned him into a small game for a festival sale I made up, Jhilmil Bazaar. You get thirty seconds to light the diyas. Everyone wins a coupon, and the more diyas you light, the bigger it gets.
Walk with the arrow keys or A and D, aim with the mouse, and press and hold to keep firing. On a phone, use the pad under the game. The diyas wait on the window sills and along the roof. Fullscreen opens the first demo, before it was a game: Tuft on his own in the wide courtyard, full screen.
Finding the kid
I started from a reference I liked: a chunky kid with a blaster, side on, on a dark stage. I didn't want a copy of it, so the first round in Paper↗ was four directions of my own, made with GPT Image: a space cadet, a junkyard inventor, a storm ranger and a kid with an arm cannon.

The inventor won. All four had the same generic face, though, so the second round was only faces: three edits of the inventor, flatter and chunkier, ready to become vectors. Tuft is the one with the tuft.
One SVG, 148 shapes
The SVG came from QuiverAI's Arrow model, the whole character in one generation. I didn't try a sheet of separate parts. Parts drawn apart never quite line up, and one drawing does.

The first version had 123 colours, because Arrow gives every shape its own near-duplicate hex. A short script groups colours that look the same and snaps each group to the one it uses most. On the final SVG another drops 39 squiggles and dots of dust, which leaves 148 shapes in 44 colours. That file is Tuft.
Each shape is mapped once to a part: hair, head, face, goggles, torso, both arms, the blaster and both boots. Some of what a rig needs wasn't there at all. His overalls were one shape over both legs, there was nothing under his arms, and he had no eyelids. Those I drew by hand, in code.
Rigged in text
Like Freddy, he's built with the Rive CLI rather than the
editor. Python writes the RML, about 8,000 lines of it, and the CLI compiles it
into a 92 KB .riv. Every motion gets its own nested node. The aim turns one,
the walk bobs the next, the recoil kicks the one inside that, so no two
animations fight over the same transform.
Before rigging anything, I posed the moves from the real SVG and drew them as charts.

The kick runs down the body. The blaster peaks first, then his torso and head, then his hair, and everything swings a little forward before it settles. His hair follows his head through a curve that overshoots, so it drags, swings past and comes back. In the walk, each boot stays where it lands and the leg is solved to reach it, so his feet never slide.
He started with a beam. A beam doesn't push back, so the recoil looked like nothing caused it. Now he fires balls that fly for half a second. Holding down fires one every 180 ms, up to three in the air.
A courtyard in one shader
Behind the transparent Rive canvas is one WebGL2 fragment shader. Each pixel casts a ray into a small courtyard: a stone floor with rangoli, a house with lattice windows, marigold garlands and strings of bulbs, star lanterns, and a sky with fireworks.
Up to 32 point lights light it. The diya flames, the lanterns and the fireworks are lights, and so is every ball Tuft fires. Rive tells the page each time a ball leaves the blaster, and the page puts a light where the ball is drawn, so a shot washes the floor and the wall magenta as it passes.
The game
I drew the three screens in Paper before writing any of it: a welcome screen, the round, and a win screen with a scratch card.
The diyas sit on the sills and the roof because he can't aim down. A level shot reaches the sills, and the roof needs an upward aim. A ball that passes over a dark diya lights it, and the lamps on the floor catch as your score climbs, so the courtyard gets brighter as you play. Six diyas make the coupon ₹250, and ten make it ₹500.
Three in a row is meant to set off a firework. For a while it never did. Diyas come into range about every 1.4 seconds at best, and the combo window was 1.6 seconds. I only noticed when I recorded a run and never saw one. The window is 3.2 seconds now.
Sound, and a recording that drops nothing
Every effect is made in the browser with Web Audio: the blaster, his boots, a bell that climbs the scale with each diya in a combo, rockets, crackling bursts and the scratch. The music is "Diwali" by the_mountain on Pixabay↗. The chips under the game turn the music and the effects off separately.
For the video, the page got a recording mode. Its clock stops following real time: a script steps it one sixtieth of a second at a time, plays the round, and captures each frame, so no frame drops even on a slow laptop. The sound is rendered afterwards from the same run, so every sound lands on its frame.