SPRK

Build native desktop apps that a person, your program and an agent can all drive.

JavaScript · Python · Shell · any language over a pipemacOS · Windows · Linux

Every control has a name, and it is the same name for all four: what a screen reader reads out, what your script writes to, what a pipe asks for, what an agent presses.

294 KBthe whole framework, macOS

git clone https://github.com/eddime/spark-native
cd spark-native && ./spark new myapp
./spark dev myapp/index.html
Every control has a name · One tree, four callers · Checked on three systems · Real OS widgets · Any language · No browser · Nothing to keep patched · Every control has a name · One tree, four callers · Checked on three systems · Real OS widgets · Any language · No browser · Nothing to keep patched · Every control has a name · One tree, four callers · Checked on three systems · Real OS widgets · Any language · No browser · Nothing to keep patched · Every control has a name · One tree, four callers · Checked on three systems · Real OS widgets · Any language · No browser · Nothing to keep patched ·
Addressable
01

Addressable
means this.

Every control has a name, and that name is the same one for all four of them. Not four APIs bolted together, one tree, reached four ways.

One name. Four callers.

Which means the same line, whatever you write it in, no bindings, no FFI, nothing generated.

out.textContent = "Hello, " + who.value;

And the name is what gets checked: spark cross asks all three systems what a keyboard can reach, by name. The first run found twenty-five of twenty-six Windows controls unreachable without a mouse.

Which makes the fourth caller free.

$ spark mcp notes.html
spark: 5 tool(s) from Notes — press_save, fill_what, read_screen …

The buttons are the tools, under the names you gave them. Nothing to write: the app already answers every question MCP asks.

What that buys you → Your window as an MCP server → The second question →

What it makes
02

One file.
Three toolkits.

The same markup becomes a real NSButton, a real Win32 button and a real GtkButton.

Measured once, in shared C, and only then handed to each system to build, so none of the three does the arithmetic, and none of them can get it different.

Spark on macOS
macOS · AppKit
Spark on Windows
Windows · Win32
Spark on Linux
Linux · GTK 3

swipe →

Every screenshot came out of spark cross, which asks each system whether every widget landed where the layout put it.

Why it exists
03

The machine already
has all of it.

Your computer has shipped a window system, a widget set, a text engine and a JavaScript engine for thirty years. It draws every other app you own.

Then a desktop app arrives carrying its own, a second browser, a second engine, eighty-five megabytes of them, to draw a button the machine could already draw. And once it is yours, so is keeping it patched.

What a webview app ships
  • a browser engine
  • a JavaScript runtime
  • a renderer, a font stack, a compositor
  • every security fix in all of them, forever
What Spark ships
  • a parser
  • a layout engine
  • three thin hosts, one per system
  • that is the entire list

Spark asks the machine instead.

What it weighs
04

What it weighs.

App on disk

0.35 MBone file, nothing beside it

Cold start

146 mswindow up, scripts run

Idle memory

20 MBphysical footprint

Measured on this machine, and none of it is cleverness: there is no renderer and no engine to carry, because the widgets and the JavaScript are already on the system. Against what, and how →

Is this for you?

Yes
  • a small tool that must stay small
  • the same look on three systems, checked rather than hoped for
  • an app whose every control must be reachable by name, and checked that way rather than hoped about
  • a window in front of a CLI, a build or a model you already have
  • something a test or an agent has to drive
No
  • you want the web platform, CSS, arbitrary HTML, anything off npm
  • heavy custom rendering: a video editor, a 3D scene
  • your design is a web design, pixel for pixel
  • you need mobile, or a screen reader that can operate the app: names and events are published on all three, values and field contents are not yet

Not on either list: needing a widget Spark does not have. That is a shared library and one function, a plugin, not a fork.

Start here  Read the guide  Compared →