Open Source Adventures: Episode 21: Imba 2 Matrix Rain
Tomasz Wegrzanowski
Posted on March 24, 2022
Let's port another Imba 1 app to Imba 2, this time Matrix Rain, a screensaver similar to the Matrix.
You can see it in action here, and the source code of Imba 1 version here.
Imba 1 app.imba
This app uses two components - App
(top level) and Stream
(a single stream of falling characters), and a few lifecycle hooks, with setInterval
, and setup
.
There's also a few loose functions with unusually looking let def
.
let def random_int(min, max)
min + Math.floor( Math.random() * (max - min + 1) )
let def random_katakana
String.fromCharCode(random_int(0x30A0, 0x30FF))
let def random_symbols
for i in [0..random_int(5, 30)]
{ v: random_katakana() }
tag Stream
def render
<self css:top=data:y css:left=data:x>
for symbol, index in data:symbols
<div.symbol .first=(index==0)>
symbol:v
tag App
def setup
@streams = []
let x = 10
while x + 30 < window:inner-width
@streams.push({
x: x,
y: Math.random() * window:inner-height,
speed: 10 + Math.random() * 20,
symbols: random_symbols()
})
x += 30
def mount
setInterval(&,10) do
for stream in @streams
stream:y += stream:speed
if stream:y > window:inner-height + stream:symbols:length * 20
stream:symbols = random_symbols()
stream:speed = 10 + Math.random() * 20
stream:y = - stream:symbols:length * 20
for symbol in stream:symbols
if Math.random() < 0.01
symbol:v = random_katakana()
Imba.commit
def render
<self>
for stream in @streams
<Stream[stream]>
Imba.mount <App>
Imba 1 app.scss
There's a bit of unusual styling here, featuring rarely used flex-direction: column-reverse
. As usual, SCSS used only for nesting, and not for anything fancy.
@import 'normalize-scss';
@include normalize();
body {
overflow: hidden;
}
.App {
background-color: black;
height: 100vh;
width: 100vw;
overflow: hidden;
.Stream {
position: absolute;
display: flex;
flex-direction: column-reverse;
.symbol {
height: 20px;
width: 20px;
line-height: 20px;
position: relative;
font-size: 16px;
text-align: center;
color: #8f4;
&.first {
color: #dfa;
}
}
}
}
Imba 2 app.imba
Here's the app ported to Imba 2:
global css body
background-color: black
overflow: hidden
margin: 0
height: 100vh
width: 100vw
def random_int(min, max)
min + Math.floor( Math.random() * (max - min + 1) )
def random_katakana
String.fromCharCode(random_int(0x30A0, 0x30FF))
def random_symbols
for i in [0 .. random_int(5, 30)]
{ v: random_katakana() }
tag stream
prop x
prop y
prop symbols
<self[top:{y}px left:{x}px]>
for symbol, index in symbols
<div.symbol>
symbol.v
css
position: absolute
display: flex
flex-direction: column-reverse
.symbol
height: 20px
width: 20px
line-height: 20px
position: relative
font-size: 16px
text-align: center
color: #8f4
&:first-child
color: #dfa
tag app
def setup
streams = []
let x = 10
while x + 30 < window.innerWidth
streams.push({
x: x
y: Math.random() * window.innerHeight
speed: 3 + Math.random() * 5
symbols: random_symbols()
})
x += 30
def mount
imba.setInterval(&, 10) do
for stream in streams
stream.y += stream.speed
if stream.y > window.innerHeight
stream.symbols = random_symbols()
stream.speed = 3 + Math.random() * 5
stream.y = - stream.symbols.length * 20
for symbol in stream.symbols
if Math.random() < 0.01
symbol.v = random_katakana()
<self>
for stream in streams
<stream x=stream.x y=stream.y symbols=stream.symbols>
css
height: 100vh
width: 100vw
overflow: hidden
imba.mount <app>
Some notes:
- syntax is a bit closer to standard JavaScript
-
imba.setInterval
is like regularsetInterval
, except it also tells Imba that properties might have changed. It's a different model of reactivity than Svelte's. - each symbol is wrapped with
{v: ...}
to make update in a loop easier - one baffling thing was
<self[top:{y}px left:{x}px]>
- I first tried<self[top:{y} left:{x}]>
expecting pixels to be the default units, as that's how everything about DOM works, but somehow Imba converted10
to40px
. Like what an actual fuck? It makes no sense whatsoever. It's some weird Tailwind nonsense, whereh-1
meansheight: 0.25rem
, and that's4px
. That's just totally baffling at framework level. - Imba's CSS has enough SCSS features (like
&:first-child
) that there's no need to use SCSS
Source code
Source code is in imba2-matrix-rain repository. At some point I'll try to add GitHub Pages support for it.
Coming next
In the next few episodes I'll try to port a few more Imba 1 apps to Imba 2, and then I guess I'll summarize my thoughts about Imba situation.
Posted on March 24, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.