Imba is a Web programming language that's fast in two ways: Imba's time-saving syntax with built-in tags and styles results in less typing and switching files so you can build things fast. Imba's groundbreaking memoized DOM is an order of magnitude faster than virtual DOM libraries, so you can build fast things.
Imba's syntax is minimal, beautiful, and packed with clever features. Less keystrokes, and less switching files means you'll be able to build things fast.
import './canvas'
import './pickers'
global css body m:0 p:0 rd:lg bg:yellow1 of:hidden
const strokes = [1,2,3,5,8,12]
const colors = ['#F59E0B','#10B981','#3B82F6','#8B5CF6']
const state = {stroke: 5, color: '#3B82F6'}
tag App
<self>
<div[ta:center pt:20 o:0.2 fs:xl]> 'draw here'
<app-canvas[pos:abs inset:0] state=state>
<div.tools[pos:abs b:0 w:100% d:hgrid ja:center]>
<stroke-picker options=strokes bind=state.stroke>
<color-picker options=colors bind=state.color>
imba.mount <App[pos:abs inset:0]>
There is no hidden code or stylesheets here. What you see is what you get.
Imba is neither an academic exercise or a toy project. We've built Imba over many years to build the frontend and backend of scrimba.com. Our goal has always been to create the most fun and powerful language for creating rich web applications.
import express from 'express'
import passport from 'passport'
import index from './index.html'
import image from './confused-cat.png'
const app = express()
app.get '/404' do(req,res)
res.send String <html> <body>
<h1> "We could not find this page!"
<img src=image>
<a href='/'> "Go home!"
app.get '/:page' do(req,res)
res.send index.body
app.get '/' do(req,res)
res.redirect('/top')
imba.serve app.listen(8001)
Imba works just as well on the server as on the client. It interoperates fully with the npm + node ecosystem. The whole stack of Scrimba is written in Imba.
Inspired by tailwind, Imba brings styles directly into your code. Styles can be scoped to files, components, and even parts of your tag trees. Style modifiers like
import './styles'
tag app-clock
<self autorender=1fps>
let ts = Date.now! / 60000 + utc * 60
<div.location> <slot>
<div.dial.hour[rotate:{ts / 720}]>
<div.dial.minute[rotate:{ts / 60}]>
<div.dial.second[rotate:{ts % 1000}]>
<div.circle>
document.body.appendChild <div.grid>
<app-clock[bg:pink2] utc=-5> 'New York'
<app-clock[bg:purple2] utc=-8> 'San Fran'
<app-clock[bg:indigo2] utc=0> 'London'
<app-clock[bg:sky2] utc=9> 'Tokyo'
Styles can also be set directly on elements. Inline styles works with all modifiers.
tag app-clock
<self>
css div pos:abs b:50% l:50% x:-50% origin:50% 100%
let ts = Date.now! / 60000 + utc * 60
<header[fs:xl fw:700 ta:center c:gray8/40 p:2]> name
<div[rd:1 bg:gray8 h:13vmin w:5px rotate:{ts / 720}]>
<div[rd:1 bg:gray6 h:18vmin w:4px rotate:{ts / 60}]>
<div[rd:1 bg:red5 h:21vmin w:2px rotate:{ts % 1000}]>
<div[rd:full bg:red5 size:10px y:50%]>
tag app
<self[d:grid gtc:1fr 1fr gap:4 pos:abs w:100% h:100% p:4]>
css app-clock pos:rel w:100% rd:2
<app-clock[bg:pink2] name='New York' utc=-5>
<app-clock[bg:purple2] name='San Fran' utc=-8>
<app-clock[bg:indigo2] name='London' utc=0>
<app-clock[bg:sky2] name='Tokyo' utc=9>
imba.mount <app autorender=1fps>
Imba comes with a built-in bundler based on the blazing fast esbuild. Import stylesheets, images, typescript, html, workers and more without any configuration. Bundling is so fast that there is no difference between production and development mode - it all happens on-demand.
import Game from './state.imba'
import {Tile} from './tile.imba'
css .tiles
fl:1 w:100% h:100% c:blue1 fs:30px
d:grid grid: 1fr 1fr 1fr / 1fr 1fr 1fr
tag App
game = new Game
<self[d:vflex pos:abs inset:0]>
<div.tiles> for tile,i in game.tiles
<Tile data=game nr=i @click=game.place(i)> tile
document.body.appendChild <App autorender=yes>
Getting started with Imba is as simple as running
let number = 42
let bool = yes
# strings
let string = 'the answer is 42'
let dynamic = "the answer is {number}"
let template = `the answer is {number}`
# dimensions
let length = 20px
let duration = 150ms
let regex = /answer is (\d+)/
let array = [1,2,3]
let object = {name: 'Imba', type: 'language'}
class Todo
# properties
title
completed = no
due = null
# methods
def complete
completed = yes
# getters
get overdue
due and due < new Date
let todo = new Todo title: 'Read introduction'
# elements are first class citizens
const list = <ul title="reminders">
<li> "Remember milk"
<li> "Greet visitor"
# setting classes on elements
<div.panel.large> "Hello world"
# setting dynamic and conditional classes
<div.panel.state-{state} .hidden=condition> "Panel"
# binding handlers (with modifiers)
<div.panel @click.prevent=handler> "Panel"
# looping over iterables
for {id,name} of iterable
"{name} has id {id}"
# looping over Object.keys/values pairs
for own key,value of object
[key,value]
# fast looping over arrays
for member,index in array
member
We are a small but active community of early Imba users. Jump on our Discord to say hi! Recordings of all our community meetings can be found on the official Imba YouTube Channel.
Imba has been under active development for 6+ years now, and activity is only ramping up. We're looking for contributors who would like to help improve documentation and the ecosystem around Imba.
Everyone is welcome to the community meetings (via Zoom)! This is a great place to report your issues, hangout and talk about your project using Imba. For the exact meeting times please use the Meetup group, this is where you can see the timezone, cancellations, etc.