DEV Community

JoeStrout
JoeStrout

Posted on

Make a Mini Micro Kaleidoscope

You have got to try this.

Inspired by a Facebook post, I decided this morning to make a kaleidoscope demo for Mini Micro. And man, this thing is trippy!

Screen shot of kaleidoscope program

There are a lot of knobs to tweak and settings to explore, so fire up Mini Micro (download it free here if you don't have it already), and follow along!

The Big Idea

A kaleidoscope is a set of mirrors that reflect onto some interesting "stuff" (traditionally, colorful little bits of plastic at the end of the tube) to provide a multiple views of the same content. In Mini Micro, we're going to provide those views by using Sprites, each using the same image, and stretched out to a diamond shape. Those are arranged in a circle, providing a star shape overall, like this:

Screen shot of Mini Micro showing six diamonds arranged into a 6-pointed star.

I've made the diamonds smaller, and shifted one of the diamonds out a bit so you can see it in the image above. In the real program, we'll scale these up enough that they fill the screen without gaps.

Then, we set the texture coordinates or "UVs" on each diamond to the same portion of a colorful texture, which represents the "interesting stuff" at the end of the tube. Importantly, the UV coordinates are flipped on alternating diamonds. That causes the texture at the edge of one diamond to match up perfectly with the texture on its neighbor, and results in the trippy symmetrical patterns.

Finally, we just move those UV coordinates around on the texture, causing the pattern to whirl and change. It's mesmerizing!

Getting Started

Start by downloading one or both of these images:

I called them "kaltex1.png" and "kaltex2.png". Save them to whatever folder you want to do this project in. Then launch Mini Micro, and mount that same folder (using the disk-slot icon below the screen; or on Mac/Windows, you can just drop the folder onto the Mini Micro window to mount it).

Type view "kaltex1.png" and press Return in Mini Micro to verify that you're set up with everything in the right place. Then use the edit command, and paste in this code:

clear
texture = file.loadImage("kaltex1.png")
cx = 480; cy = 320; r = 600  // screen center and radius
n = 6  // number of wedges

for i in range(n-1)
    sp = new Sprite
    sp.image = texture
    a = i * 2*pi/n
    a1 = a + pi/n
    a2 = a1 + pi/n
    sp.setCorners [[cx, cy],
      [cx+cos(a)*r, cy+sin(a)*r],
      [cx+cos(a1)*r*2, cy+sin(a1)*r*2],  
      [cx+cos(a2)*r, cy+sin(a2)*r]]
    display(4).sprites.push sp
end for
Enter fullscreen mode Exit fullscreen mode

Save that as "kaleidoscope" (or whatever you like), then run it. It should fill your screen with repeating copies of the full texture.

This code mostly just figures out the angle (in radians) to the corners of each diamond, and then calculates the positions of those using cos and sin. If you need a review of how angles, sin, and cos work, run /sys/demo/angles. (And you thought you'd never need trigonometry in real life!)

Setting UVs

edit your program again, and append this code:

uvs = function(t, flip=false)
    cx = 0.5 + 0.25 * sin(t * 0.13)
    cy = 0.5 + 0.25 * cos(t * 0.17)
    a = t * 0.21
    r = 0.25 + 0.08 * sin(t * 0.31)
    result = []
    for i in range(0,3)
        result.push [cx + cos(a)*r, cy + sin(a)*r]
        if flip then a -= pi/2 else a += pi/2
    end for
    return result
end function
Enter fullscreen mode Exit fullscreen mode

We're just defining a function here, not actually calling it, so if you run now it shouldn't behave any differently. But let's take a moment to understand what's going on.

This code is somewhat similar to the diamond-positioning code we had before. It's basically defining a four points arranged in a square that moves around, scales, and rotates, sampling different areas of the sprite texture.

First we calculate a center (cx, cy) position that depends on the value t (representing "time"). When you read cx = 0.5 + 0.25 * sin(t * 0.13), think "cx is going to vary around 0.5, by up to 0.25 in either direction". The factor 0.13 controls how quickly cx varies with time. cy is similar but varies at a different rate.

Then we calculate an angle a, as a straight-up multiple of t. This makes our square rotate steadily with time. (What would happen if you threw a factor of sin in this one too?) Finally, we calculate a radius r that uses the same sin trick to vary by +/- 0.08 around 0.25.

With our center, angle, and radius ready to go, the for loop just calculates each point and stuffs them into result. But note the if statement that adjusts our angle after each point. When flip is true, we subtract pi/2 (90°, or a quarter circle) as we go; otherwise we add it. This is what flips the texture on every other diamond, so that they mesh properly at the edges.

Screenshot of kaleidoscope program

Animation!

edit your code again, and paste in this final piece:

while not key.pressed("escape")
    yield
    t = time
    //t = mouse.x/100 + mouse.y/71
    for i in range(n-1)
        display(4).sprites[i].setUVs uvs(t, i%2)
    end for
end while
key.clear
Enter fullscreen mode Exit fullscreen mode

This is the main loop. We start with a yield, as all good main loops do, fixing the animation rate to 60 frames/sec. Then we choose a t value equal to the time (or, if you uncomment the line after that, a t value that depends on the mouse!). Then we just call setUVs for each of our diamond sprites, passing in t, and with flip set to true (1) for the odd-numbered diamonds.

That's it. Run the program now, and you'll be in trippy kaleidoscope land! But you're not done. Now you get to do the fun part:

Tinkering

This is code that just begs to be played with! Here are some places to start:

  • Change the texture loaded at the top of the program! This makes a dramatic difference in the overall feel. Try both of the ones above, or try making your own. (Or ask an AI to make one for you.)
  • Change the value of n (number of diamonds) at the top. 4, 6, 8, and 10 all work well. But push it till it breaks! What happens if you use 5 or 7 or 30?
  • Uncomment that t = mouse line, and instead of animating with time, you can actually control the thing by moving your mouse around. Play with the constants on that line. Or, can you think of useful ways to combine time and mouse position?
  • Change the constants in the uvs method. Can you find values you like better?
  • Throw a .mp3 or .ogg file of background music into your folder, and have your program load and play it.

It's such a small program, but so fun to mess with. There's a good chance this will end up being one of the built-in demos in Mini Micro 2, but for now, only those sharp enough to follow this blog post will get to have that fun. Enjoy!

Top comments (0)