DEV Community

Tomasz Wegrzanowski
Tomasz Wegrzanowski

Posted on

Open Source Adventures: Episode 21: Imba 2 Matrix Rain

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> 
Enter fullscreen mode Exit fullscreen mode

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; } } } } 
Enter fullscreen mode Exit fullscreen mode

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> 
Enter fullscreen mode Exit fullscreen mode

Some notes:

  • syntax is a bit closer to standard JavaScript
  • imba.setInterval is like regular setInterval, 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 converted 10 to 40px. Like what an actual fuck? It makes no sense whatsoever. It's some weird Tailwind nonsense, where h-1 means height: 0.25rem, and that's 4px. 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.

Top comments (0)