New plugin: Water / Wavepool LED effect

I made a thing today. It makes light splash out from each keypress like ripples in a lake. Or, when you’re not typing, it simulates gentle rain on the keyboard.

It’s still sort of a work in progress, but it is at least working and I’d love feedback.

I’m half tempted to double the resolution of its virtual swimming pool, to make the motion smoother and more realistic, but I’m not so sure it’s a good idea due to RAM use. The smallest I’ve tried this water effect before was 320x200, which is of course way too big, but at 14x5 it’s a bit noisy. Maybe 28x10 would work a bit better… OTOH, that’s 560 bytes of RAM and the atmega only has 2.5 K. So, not sure.

I could also use some ideas about why the colors skip directly from purplish to greenish without the red-orange-yellow parts between. It seems to repeat the blue-purple spectrum before jumping. To see this happen, just hold a key down and watch as the colors around it change.


Haven’t looked at the code, but would it be possible to make it a compile-time option or something similar? So if one has a lot of RAM free, could use the higher resolution, otherwise the smaller one.

FWIW, I made a video so people can see it without actually having the hardware.

I forgot to show a couple things, though. Like, if you drag across half the keyboard, it’ll create a somewhat stronger wave which flows over to the other side and then bounces back. It can be fun to play with, since it’s actually a physics simulation – partial derivative equations in action. :smiley:


Super impressive. Have you played much with the “impact” level per keypress? In other words, making each keypress make larger/smaller waves?

I pushed some updates today. The main thing which changed is a new ‘idle_timeout’ config option to set the time in ms before the idle animation starts.

Yes, but it’s pretty limited in this 14x5 pixel version. The original from the mid-90s had much more extensive controls for messing with the surface… For example:

With a higher-resolution surface map, it should be able to do smoother animations. However, oversampling would use at least 22% of the atmega’s total RAM and it would require about 8X as much CPU time. And that’s if I leave it at 8 bits instead of upgrading to the a 16-bit surface. So I’m not convinced it’s a good idea. The keyboard is using a very scaled-down version.

1 Like

Another update… It no longer skips the red part of the color spectrum. Colors should be a little less crazy now, though they still get pretty wild while actively typing. If you simply hold a key, though, it should display a nice smooth slowly-rotating rainbow gradient. Then release the key to release pressure and send out an opposite-colored negative wave.

1 Like

… and I made it about 300 bytes smaller, by using a janky custom rand() instead of the libc rand(), and by making some of the other logic smaller. It looks vaguely more noisy now, I think, but it’s hard to tell for sure. It might just be my brain telling me to be done for the night.

1 Like

To my eye, it’s not very noisy. It just moved so quickly that it’s hard to make out that it’s a water effect. If I had one of the units, I’d try making it move more slowly, making the wave smaller, or making the wave attenuate more quickly. Looks like it’ll be fun to tinker with it!

1 Like

Making the wave move more slowly can be done by reducing the frame rate, but it’s already pretty slow. A better way to do it would be to improve the algorithm so the time step isn’t locked to 1, but that could get complicated. So an easier (but probably more expensive) way is to increase the resolution and only display every other pixel (or an average of a few). That should make it slower and smoother and generally nicer-looking.

I might give it a try, but it’ll also reduce how many other plugins can be running at the same time.

That’s cool. It sounds like you know what you’re doing! Looking forward to trying it out some time soon!

Of course, my personal config has plenty of room left… and I’d kinda like it if my keyboard looked a little nicer. So maybe I’ll do it anyway. :slight_smile: But for general use it should probably default to the smaller lower-resource version. I guess it could be a compile-time option, a #define or something.

At least, I’d like it if it was a little less spastic while actively typing. It looks like the LEDs are having a seizure when I type at 100wpm.

1 Like

I tried this tonight. It didn’t go well. It’s acting like something else is interfering, actively overwriting part of the array I’m using for the height map. It’s definitely possible I have a bug somewhere, but it’s also possible that it’s simply using more RAM than what is actually available. Or it could be running too long and getting interrupted by something which corrupt that part of RAM, then getting control back afterward. It’s hard to say for sure.

In any case, I think I’ll have to leave it mostly as-is. I saved that version in case I want to come back to it later, but it doesn’t work. And whatever it’s doing is bad enough that it interferes with reflashing. With the higher-res version, I have to put it into a different lighting mode to update the firmware.

So… fail.

Can you put up your attempts on GitHub? As unlikely as it is that I might find the issue, I’d still would like to have a look, just in case.


Sure. I pushed up two branches:

1 Like

I tried a different approach today, and it’s working better. Doubling the resolution failed, so instead I doubled the frame rate and made it “tween” or interpolate between frames. … and then slowed the frame rate down a little.

The result is that it went from 15 fps to 25 fps, and the motion is both smoother and slower.


I was really excited to try this out on my keyboard tonight. Unfortunately I ran into some build errors. Not sure if maybe I’m doing something wrong… maybe if you have time you could let me know if there’s something simple that needs fixing here? :slight_smile: Some of these errors that are thrown here are just out of my league. I followed the instructions in the README and the example sketch…but no good.

In file included from C:\Users\Eddie\Documents\Arduino\hardware\keyboardio\avr\libraries\Kaleidoscope-LED-Wavepool\src/Kaleidoscope-LED-Wavepool.h:21:0,

                 from C:\Users\Eddie\Documents\Arduino\Model01-Firmware_TEST\Model01-Firmware_TEST.ino:63:

C:\Users\Eddie\Documents\Arduino\hardware\keyboardio\avr\libraries\Kaleidoscope-LED-Wavepool\src/Kaleidoscope/LED-Wavepool.h:32:8: error: virtual function 'virtual void kaleidoscope::WavepoolEffect::begin()'

   void begin(void) final;


In file included from C:\Users\Eddie\Documents\Arduino\Model01-Firmware_TEST\Model01-Firmware_TEST.ino:26:0:

C:\Users\Eddie\Documents\Arduino\hardware\keyboardio\avr\libraries\Kaleidoscope-LEDControl\src/Kaleidoscope-LEDControl.h:83:8: error: overriding final function 'virtual void kaleidoscope::LEDMode::begin()'

   void begin(void) final;


Multiple libraries were found for "HID.h"
 Used: C:\Users\Eddie\Documents\Arduino\hardware\keyboardio\avr\libraries\HID
 Not used: C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\HID
exit status 1
Error compiling for board Keyboardio Model 01.

You will need this pull request applied, and then it should work. Using the f/led-api-update branch of my fork is another - temporary - option.

1 Like

Awesome. It worked. Thanks a lot!

Sorry about that. After my initial involvement, I’ve been bad about sticking around. I finally pulled in the updates a while back though, so hopefully people won’t run into issues any more.

Thanks for this awesome plugin. I love the way the ripple looks on the Model 01 :smiley:

BTW, the plugin is out of date with the latest iteration of the Kaleidoscope plugin API. Please consider this PR that has been waiting in the wings to update the plugin for the latest API (changes are pretty small, it seems):