omxlabs › omxplorer
omxplorer · by omxlabs · built in Mojo

Ask your data in a sentence.

A data workspace where a million rows answer in under a millisecond, on your own GPU, and every button is a tool an AI agent can call.

arrow keys, space or swipe · 18 slides, about two minutes

Why

Data tools make you wait, and make agents guess.

⏳

You wait.

Spreadsheets choke past a million rows. Warehouses answer in seconds and send a bill.

🖱️

Agents squint.

AI agents drive apps through screenshots and pixel coordinates. It's slow and it breaks.

💤

Your GPU naps.

Most workstations have one. Data apps leave it idle while the CPU struggles.

What it is
omxplorer's Report over a million orders

Numbers and Power BI, on the GPU.

Sheets, pivots, charts and reports over your CSV and Parquet files.

About 2,100 lines of Mojo, built from omxcode's components, run by omxcore.

a million orders, every tile recomputed in 0.3 ms · RTX 3090

The big idea

The title is the chart.

Sum of revenue by product, largest first, as bars

41.2MLaptop
33.0MPhone
22.8MMonitor
13.4MTablet
3.6MCable
Tap a word. Or type it.

Tap Sum, pick Median.

Median of revenue by product, largest first, as bars

1,240Laptop
940Monitor
780Phone
560Tablet
12Cable

a median per group over 1M rows: 6.4 ms on the GPU · omxcode README

How it's built

One language, from the button to the GPU kernel.

omxplorer the app · app.mojo · view() and update()
omxcode components, the sentence, five hosts
omxcore GPU dataframes and SQL
Your GPU NVIDIA today · CPU fallback

all Mojo: no Python, no JavaScript framework, no C++ in the middle

A tap, as it runs

You tap “Median”. 6.4 ms later, new bars.

omxplorerupdate(): the word changes
omxcoremedian by product
GPUone kernel, 1M rows
omxcodeview(): only what changed is redrawn

No round trip. The engine is linked into the app, like SQLite.

No copy, on Linux. GPU frames go straight to the window (saves 4–5 ms a frame).

Just the diff. The host patches the native widgets that changed.

How you'd write one

An app is a struct: state, update, view.

examples/hello/app.mojo · real code, trimmed
struct Main(App):
    var name: String
    var clicks: Int

    def update(mut self, event: Event):
        if event.message == GREET:
            self.clicks += 1

    def view(self) -> View:
        var greeting = "Hello, " + self.name + "! (click " + String(self.clicks) + ")"
        return VStack(
            Text(greeting, style=TITLE),
            Button("Greet", on_tap=GREET, style=PROMINENT),
            spacing=20,
        )

the same file opens on Linux (GTK) and the web, and on CI Macs; Android on the emulator; iPhone builds

How the sentence works

Words are buttons. Buttons are tools.

mojoui/sentence.mojo · real code, trimmed
Sentence([Word("Sum", ASK_COMBINE, "word-combine"), Word(" of "), Word("amount", ASK_VALUE, "word-value")])

for w in words:
    if w.msg != NO_MSG:      # a token: tap it to see its choices
        line.append(Button(w.text, w.msg, TOKEN).tag(w.tag))
    else:                    # plain words: " of ", ", "
        line.append(Text(w.text, style))
# a tag names the button; the agent host turns every tagged button into an MCP tool,
# so "word-combine" is something a person taps and an agent calls
The numbers

Fast enough that you stop waiting.

0.6ms

a chart over 1M rows

0.8ms

a frame, scrolling a 1M-row grid (p95)

1.5ms

20M points in one frame

0.2s

to open a 100M-row file, streamed

RTX 3090 · the repo's own checks re-run each one · honest edge: a 100M-row median chart takes about 0.7 s

100 million rows

A dashboard over 100M rows: 30 ms a click.

median, measured at 856a7e9, before the release build · docs/data-benchmark.md

omxplorer
30.3 ms
Rust + Polars
37.0 ms
JS + Polars
44.2 ms
JS + DuckDB
104.9 ms

goal 38 · median of medians, p95 49.1 ms · Rust + Polars + egui · JS + FastAPI + Polars · JS + DuckDB-WASM · docs/data-benchmark.md

Built for agents

Every button is a tool.

$ scripts/agent.sh omxplorer
claude mcp add omxplorer -- …agent.py build/omxplorer/web
→ choose-a-file {"path": "orders_1m.csv"}
→ create-table
→ insert-chart
→ ask {"text": "revenue by product, largest first, top 5"}
← Now: chart0: 0.6 ms

No screenshots, no coordinates. A button's tag is its tool's name.

The screen is the permission model. A disabled button is no tool. A dialog's buttons exist only while it's open.

One sentence for both. The words you tap are the words the agent asks.

a real session · omxcode README, docs/agent.md

Where it runs

Written once. Native everywhere.

🐧Linuxruns
🌐Webruns
🤖Androidemulator
🍎Macruns on CI Macs
📱iPhonebuilds

Mac: GitHub's macOS runners · Android: the emulator · iPhone compiles and signs, hasn't run on a phone yet · the GPU: NVIDIA on Linux, Metal on CI Macs

Every kind of data live

A video becomes rows, 400 frames a second.

the warehouse: rows → a reel, faces blurred, ID burned in

the drone: what got worse → the next flight plan

How a video becomes rows

Frames in, rows out. Then it's just data.

VideoSourceffmpeg decodes; frames go to the GPU
GPU kernelscolour, motion, printed codes
VisionModel slotOWLv2, SAM 2.1, in process
Rowsframe, track, code, damaged, face box
SQL · the sentencejoin with shipments.csv
The reelblur, burn in, H.264

One slot, two engines. Classic GPU vision today; a model plugs into the same place and gives the same rows.

Rows are rows. "Delivered, but the label never shows on camera" is one SQL join.

Every step is a tool. Analyze, Make a reel, Cut it: an agent calls what you tap.

Linked evidence live

A video, a sheet and the paperwork answer one question.

which damaged pallets does the carrier owe for?

You make the links. Drag a column onto a card and confirm. Nothing joins until you do.

Documents become rows. The OCR runs locally, inside the app.

Every answer shows its proof: the frame with the damage, and the page with "Exceptions: None".

Find more like this

Tap one example. It finds the rest.

One tapped cropa damaged pallet
VisionModel: OWLv2image-guided, in process
Rows: every frame with a hitno colour rules, no labels
1.000

recall on the damaged frames

0.886

precision

8.4s

to scan the 1,140-frame warehouse

on our generated footage, scored against its truth · RTX 3090 · models run on Linux + NVIDIA only, for now

Where it's going

From tables to every kind of data.

Now
  • Sheets, pivots, charts, reports
  • The sentence chart
  • 100M-row files, streamed
  • Agent host (MCP)
  • Video becomes rows; the reel; the drone
  • Linked evidence: video, sheet, paperwork
  • The robot story: 63,344 DROID episodes, 13 labs, 16.8M telemetry rows, a question in ~40 ms
Next
  • Try it in the browser
  • Ask, answered by omxconsole
  • Real-world footage, audio
Later
  • Share with a team
  • Apple GPUs on real Macs (CI Macs today)
omxlabs

One app. Three technologies under it, local AI beside it.

omxcore

powers it: the GPU engine

omxcode

builds it: write once, native everywhere

omxconsole

local AI, on the same GPU

omxqua

the look: springs and solid surfaces (this site; omxplorer next)

Read on: GitHub · the agent docs · omxlabs