849 bytes brotli

The engine
AI writes to.

Frameworks were designed for human teams. mx is the rendering engine that fits inside a context window - zero dependencies, zero build step, direct DOM reconciliation.

849B
Brotli
0
Dependencies
0
Build Steps
4
Globals
Scroll

The next million apps won't be scaffolded with npm install. They'll be prompted into existence - single files, generated and discarded. The engine that powers them should be small enough to fit in a system prompt.

01

Token tax

Every import statement, every JSX transpilation hint, every config file is tokens the model reasons about but the user never sees. Framework ceremony is inference cost.

02

Config gravity

Minification is real. But webpack.config.js, tsconfig.json, babel presets, vite plugins - AI misconfigures these more than it misconfigures code. mx works as a raw script tag. You can still minify, but you never have to configure.

03

API surface

useEffect, useMemo, useCallback, forwardRef, Suspense, Server Components... Every API is a hallucination vector. mx exposes three globals: mx, dom, define.

04

Weight mismatch

React 19 + ReactDOM is 272KB minified. mx is under 2KB. Less surface area means less to misuse, less to hallucinate, less to debug when AI gets it wrong.

mx - Lightweight nodes
Describe what you want.
// Array descriptions. No JSX, no build step.
mx.div({ class: "card" },
  mx.h2("Hello"),
  mx.p("World")
)

Hello

World

dom - Real elements
Build it now. Mount it anywhere.
// Same syntax. Returns real DOM nodes.
let el = dom.button(
  { onclick: () => alert("shipped") },
  "Deploy"
)
document.body.append(el)
define - Components
State, reactivity, re-rendering. Done.
define("counter", {
  $({ count = 0 }) {
    return mx.div(
      mx.button({
        onclick: () => this.$({ count: count - 1 })
      }, "−"),
      mx.span(count),
      mx.button({
        onclick: () => this.$({ count: count + 1 })
      }, "+")
    )
  }
})

// Render it
document.getElementById("app").render(mx.counter())
0
MetricReact 19Vue 3Preactmx
Minified272,028105,40114,8262,001
Gzip67,98239,8676,087996
Brotli56,22535,7885,514849
Build stepYes (JSX)Yes (SFC)Yes (JSX)No
npm packagesreact + react-domvuepreact0
Component systemYesYesYesYes
Fits in system promptNo (272KB)No (105KB)No (15KB)Yes (2KB)

These demos are live - inspect the page or switch to the source tabs to see how they're built.

#
Name
Role
City
1
Person 1
Engineer
New York
2
Person 2
Designer
Los Angeles
3
Person 3
PM
Chicago
4
Person 4
Data Scientist
Austin
5
Person 5
DevOps
Seattle
6
Person 6
Engineer
New York
7
Person 7
Designer
Los Angeles
8
Person 8
PM
Chicago
9
Person 9
Data Scientist
Austin
April 2026
SuMoTuWeThFrSa
1234
567891011
12131415161718
19202122232425
2627282930
// ── Virtual scroll container ──
define('virtual-container', {
  $({ height = 400, rowHeight = 48, rows = [] }) {
    this.$visibleRows = Math.floor((height - 1) / rowHeight)
    this.$lastOffset = 0
    this.style.height = height + 'px'

    let renderVisible = offset => {
      let visible = rows.slice(offset, offset + this.$visibleRows + 1)
      return [
        mx.div({ style: `height:${offset * rowHeight}px` }),
        ...visible,
        mx.div({ style: `height:${(rows.length - offset - visible.length) * rowHeight}px` })
      ]
    }

    this.onscroll = e => {
      let scrollTop = Math.max(0, e.target.scrollTop)
      let offset = Math.floor(scrollTop / rowHeight)
      if (offset === this.$lastOffset) return
      this.$lastOffset = offset
      this.render(...renderVisible(offset))
      this.scrollTop = scrollTop
    }
    return renderVisible(0)
  }
})

// ── Table row ──
define('a-row', {
  $({ columns, data }) {
    return columns.map(col =>
      mx.div({ class: 'table-cell' },
        col.fn?.(data[col.key], data) || data[col.key]
      )
    )
  }
})

// ── 10,000 rows, virtualized ──
let cols = [
  { key: 'name', label: 'Name' },
  { key: 'role', label: 'Role' },
  { key: 'city', label: 'City' },
  { key: 'id',   label: '#', fn: v => v }
]
let data = Array.from({ length: 10000 }, (_, i) => ({
  name: `Person ${i + 1}`,
  role: ['Engineer','Designer','PM','Data','DevOps'][i % 5],
  city: ['NYC','LA','Chicago','Austin','Seattle'][i % 5],
  id: i + 1
}))

let rows = data.map(d => mx.aRow({ columns: cols, data: d }))
let header = mx.div({ class: 'table-header' },
  ...cols.map(c => mx.div({ class: 'table-cell' }, c.label))
)

demo.render(header, mx.vC({ height: 400, rowHeight: 48, rows }))
// ── Date picker ──
let selectedDate = new Date()

function renderDatePicker() {
  let year = selectedDate.getFullYear()
  let month = selectedDate.getMonth()
  let daysInMonth = new Date(year, month + 1, 0).getDate()
  let firstDay = new Date(year, month, 1).getDay()

  let days = []
  for (let i = 0; i < firstDay; i++) days.push('')
  for (let d = 1; d <= daysInMonth; d++) days.push(d)

  let weeks = []
  for (let w = 0; w < Math.ceil(days.length / 7); w++) {
    let cells = days.slice(w * 7, (w + 1) * 7).map(day => {
      let cls = !day ? 'empty' : day === selectedDate.getDate() ? 'selected' : ''
      return mx.td({ class: cls, onclick() {
        if (day) { selectedDate.setDate(day); renderDatePicker() }
      }}, day || '')
    })
    weeks.push(mx.tr(...cells))
  }

  host.render(
    mx.div({ class: 'dp' },
      mx.div({ class: 'dp-nav' },
        mx.button({ onclick() { selectedDate.setMonth(month - 1); renderDatePicker() } }, '←'),
        mx.span({ class: 'dp-title' },
          new Date(year, month).toLocaleString('default', { month: 'long' }) + ' ' + year
        ),
        mx.button({ onclick() { selectedDate.setMonth(month + 1); renderDatePicker() } }, '→')
      ),
      mx.table(
        mx.thead(mx.tr(
          mx.th('Su'), mx.th('Mo'), mx.th('Tu'), mx.th('We'),
          mx.th('Th'), mx.th('Fr'), mx.th('Sa')
        )),
        mx.tbody(...weeks)
      )
    )
  )
}
renderDatePicker()

Give AI an engine
that fits.

849 bytes brotli. Zero dependencies. The entire engine fits inside a system prompt - not as a reference, but as source code. The app is the prompt. The engine is mx.

mx - 849 bytes brotli. Zero dependencies. Zero build steps.
ENGINE: 849B BROTLI