Code,Draw,Beep,Repeat: The development of Looper

Introduction:

Being the fourth Fantasy Console project we did, Looper pretty much follows from our experience with fantasy console programming for Lovebyte 2021. Like Bamboozled, the intro uses a small resolution grid of scaling circles to represent a pixel-based effect, but with a little more love and care put into the color selection and overall progression.

Development:

The intro uses a grid-resolution of 30x17 where we will calculate both a colorvalue as well as a scaling value for each of the circles on screen. First the scaling value is calculated using z=(x*x+y*y)/p+.1 with variable p representing a distortion factor that slowly changes over time.

Then the u,v values are calculated using u=s(t/7)*32+x/z v=s(t/9)*32+y/z.
As you can see these calculations use the previously calculated scaling value as well (including the distortion over time). This UV pair is then used to calculate the final colorvalue color=u&v&3 which is then altered depending on the part number

Text and Audio:

As a small nod to ziphead, at some point in the intro, it flashes the texts "code,draw,beep,repeat" on the screen. This is done by the way-too-overengineered instruction print(a[((P-W)*t//(W+8))%5+1],86,62,12,0,2) which essentially pseudo-randomly cycles through the texts defined in a[] whilst also taking care of the progression-timing and the fact that LUA arrays start at 1 (Insert Tom Scott fragment).

The register bitbanging is done inside the inner drawloop using poke(65435+(P+y+x)/(P+3),t*27%32)

Color usage and Progression:

The intro uses the default Sweetie16 palette, but only the red-orange and blue bits, which is enforced by using the &(3+P)+W on the final color calculations. A lot of development time went into tweaking the stuff in such a way that we get a bit of variation and buildup going. By changing the scaling and perspective we are able to switch from the flat led-display to the polar-distortion shape and back, then using either the Blue or Orange part of the color scheme to make each subsection look distinct.

Sourcecode:

Here is the code for the TIC-80 version (formatted a bit for readability):

a={""," code"," draw"," beep","repeat"}
function TIC()t=time()/399
cls()
s=math.cos
p=s(t/9)*2200+2500
P=t//6&8Z=t//32&5+1
W=t//12&8
for y=-104,104,4 do
for x=-120,120,4 do
z=(x*x+y*y)/p+.1
u=s(t/7)*32+x/z
v=s(t/9)*32+y/z
circ(x+120,y+68,Z*z/4,(u//1&v//1&3+P)+W)
poke(65435+(P+y+x)/(P+3),t*27%32)
end end
print(a[((P-W)*t//(W+8))%5+1],86,62,12,0,2)
end

And here for the PICO-8 port

function _draw()n=t()cls()
d=(cos(n/32)*1100)+1600p=n\3&8
q=n/16&5+1w=n\4&8for y=-64,64,4 do
poke(12869,n*21&3)sfx(1)for x=-64,64,4 do
z=(x*x+y*y)/d
u=cos(n/13)*32+x/z v=cos(n/9)*32+y/z
circfill(x+64,y+64,z/3,({1,13,6})[u&v&3])end end
?({""," code"," draw"," beep","repeat"})[(n*w\5%5)+1],53,62,7

The intro was finished and released at Shadow Demoparty 2021 where it won the tiny intro competition.

Conclusion:

While its a fine intro that ended up winning the Shadow Party Tiny Intro competition, its definitely a product of its time. I wouldn't release it today as a stand-alone intro, but rather something that you would do on a Bytejam.

For more information, you can check out the intro at demozoo: Looper (2021)

Return to blog overview