|
1 | | -# Sambar |
| 1 | +# Bun Maska |
2 | 2 |
|
3 | | -> Electron's leaner, meaner, much-less-bundled cousin. Built on [Bun](https://bun.sh) and your operating system's own WebKit, because shipping Chromium with every app is how we ended up with 14 GB of RAM disappearing into a chat window. |
| 3 | +> Dip your Electron in some fresh Bun Maska. Built on Bun and your operating system's own WebKit, because shipping 150 MB of Chromium with every desktop app is one of those ideas that made sense in 2013 and has been quietly ruining lives ever since. |
4 | 4 |
|
5 | 5 | ## What |
6 | 6 |
|
7 | | -A **drop-in replacement for Electron** that does not bundle 100 MB of Chromium with every desktop app you build. |
| 7 | +A **drop-in replacement for Electron** that refuses to bundle an entire browser engine just so you can put a web page in a native window. |
8 | 8 |
|
9 | | -Same `app`, `BrowserWindow`, `ipcMain`, `ipcRenderer` API you already know. Different runtime (Bun, not Node). Different renderer (system WebKit, not Chromium). Same vibe. Smaller fan noise. |
| 9 | +You keep writing against the APIs you already know (`app`, `BrowserWindow`, `ipcMain`, `ipcRenderer`, `Menu`, `dialog`, `clipboard`, `webContents.printToPDF`, `capturePage`, etc.). We swap the heavy parts: runtime becomes Bun instead of Node, renderer becomes whatever WebKit your operating system already ships (WKWebView on macOS, WebKitGTK 6 on Linux). The result is dramatically smaller apps, zero compiled native code in your dependency tree, and a native module system that is just TypeScript calling `dlopen`. |
10 | 10 |
|
11 | | -## Why |
| 11 | +## The part worth paying attention to |
12 | 12 |
|
13 | | -Because your laptop fan deserves a break, and your users deserve apps under 25 MB. |
| 13 | +Most "lighter Electron" projects are just better at gzipping. Bun Maska does something structurally different. |
| 14 | + |
| 15 | +**A native module is a `.ts` file.** |
| 16 | + |
| 17 | +Need to talk to a serial port, USB device, system keychain, IOKit, a custom sensor, or anything else the OS exposes? In Electron this usually means `node-gyp`, N-API, `electron-rebuild`, and hoping the prebuilts match your exact Electron version forever. In Bun Maska you write a small TypeScript file that `dlopen`s `libSystem`, `libc`, or `IOKit` and calls it directly. No compiler. No build step. No ABI compatibility matrix. No Python summoning ritual when you upgrade. |
| 18 | + |
| 19 | +This is not a roadmap item. It is how Bun Maska itself is built — thirty-plus system libraries wired with **zero** `cc` calls anywhere in the tree. |
| 20 | + |
| 21 | +Add the fact that we ship **no browser engine at all**, and your updates stop being hostage situations, your users stop getting Chromium CVEs that have nothing to do with your code, and your laptop fan gets a long-overdue vacation. |
| 22 | + |
| 23 | +That combination — buildless native extensibility + no engine tax — is the thing no amount of tree-shaking inside a bundled Chromium can ever give you. |
| 24 | + |
| 25 | +## Why (the non-marketing reasons) |
| 26 | + |
| 27 | +Your laptop fan has strong opinions about RAM. Your users have data caps and limited patience. And we are allergic to lying in README files. |
| 28 | + |
| 29 | +Honest measured numbers: a packaged Bun Maska app is roughly a **16–23 MB download** and lands at about **61 MB on disk** once Bun unpacks itself. The equivalent minimal Electron app starts north of 150 MB and only grows from there. Updates are tiny because there is no 150 MB engine to re-download. Your OS already patches WebKit. We do not make you participate in the Chromium CVE re-shipping treadmill. |
14 | 30 |
|
15 | 31 | ## Status |
16 | 32 |
|
17 | | -**Alpha. Held together with optimism, `strict: true`, and ~980 passing tests.** |
| 33 | +**Alpha.** Held together with optimism, `strict: true`, and 1,380 tests that were green the last time CI ran. |
| 34 | + |
| 35 | +It works properly on both **macOS** and **Linux** today. You get real native windows, system WebKit rendering, full Electron-style IPC with context isolation, application and context menus, tray icons, dialogs, clipboard (text + HTML + images), `nativeImage`, `safeStorage`, `powerMonitor`, `printToPDF`, `capturePage`, and a growing list of other modules — all implemented with pure `bun:ffi` and zero compiled code in the framework. |
| 36 | + |
| 37 | +There is also a CLI that scaffolds projects, runs them with hot reload, and packages real distributables (`.app`/`.dmg` on macOS, AppDir + `.deb` on Linux) with optional auto-update support. |
| 38 | + |
| 39 | +If you are already running this in production, we admire your courage and decline all responsibility. If you are a large company doing an evaluation, please read the word "alpha" three more times before proceeding. If it is still 2027 and this file still opens with the word "alpha", feel free to open an issue titled "are you OK". |
18 | 40 |
|
19 | | -It genuinely works on **both macOS and Linux**: native windows, pages rendered by |
20 | | -your system's own WebKit (WKWebView / WebKitGTK 6), Electron-style IPC end to end, |
21 | | -application + context menus, tray icons, dialogs, clipboard, `nativeImage`, |
22 | | -`safeStorage`, `powerMonitor`, and more — all on [Bun](https://bun.sh) via FFI, with |
23 | | -**zero compiled native code and zero runtime dependencies**. There is also a CLI |
24 | | -that runs your app and packages it into real distributables (`.app`/`.dmg` on |
25 | | -macOS, AppDir/`.deb` on Linux). |
| 41 | +## The honest trade-offs |
26 | 42 |
|
27 | | -If you are using this in production, we admire your courage and decline all responsibility. If you are a billion-dollar company evaluating this for your next desktop app, talk to us — but read the word "alpha" again first. If you are reading this in 2027 and we still say "alpha," please file an issue titled "are you OK." |
| 43 | +We are not going to sell you a fantasy. |
| 44 | + |
| 45 | +- **Single process.** No Chromium sandbox. No per-window crash isolation. A nasty WebKit or JavaScriptCore crash takes the whole app with it. This is the architectural price of the lightness. |
| 46 | +- **No Windows support yet.** We are waiting for a usable WebKit port on Windows that does not involve shipping Chromium. We are aware this is a hill. We are comfortable dying on it. |
| 47 | +- **~70–80% weighted API parity** for the things most real apps actually use. The long tail (`BrowserView`, sync IPC, Web Serial/WebHID/WebUSB from the renderer, deeply Chromium-internal surfaces) is either out of scope by design or will throw a clear error so you know immediately what is missing. |
28 | 48 |
|
29 | 49 | ## Platforms |
30 | 50 |
|
31 | | -| OS | Status | |
32 | | -|---|---| |
33 | | -| macOS | actively developed — AppKit + WKWebView via `objc_msgSend` | |
34 | | -| Linux | actively developed — GTK 4 + WebKitGTK 6 + GIO/GDBus + libsecret via `dlopen` | |
35 | | -| Windows | deferred until WebKit on Windows is a thing humans can actually use. **We will not ship Chromium.** Yes, we are aware this is a hill. Yes, we are willing to die on it. | |
| 51 | +| OS | Status | |
| 52 | +|---------|------------------------------------------------------------------------| |
| 53 | +| macOS | Actively developed — AppKit + WKWebView via `objc_msgSend` and hand-built ObjC blocks | |
| 54 | +| Linux | Actively developed — GTK 4 + WebKitGTK 6 via `dlopen` | |
| 55 | +| Windows | Deferred. We will not ship Chromium. | |
36 | 56 |
|
37 | 57 | ## Install |
38 | 58 |
|
39 | | -Not on npm yet (it really is alpha). For now, use it from a clone: |
| 59 | +Not on npm yet (it really is alpha). For now: |
40 | 60 |
|
41 | 61 | ```sh |
42 | | -git clone https://github.com/indrajeetor/sambar.git |
43 | | -cd sambar && bun install |
| 62 | +git clone https://github.com/indrajeetor/bunmaska.git |
| 63 | +cd bunmaska && bun install |
44 | 64 | ``` |
45 | 65 |
|
46 | | -You will need [Bun](https://bun.sh) ≥ 1.3. Yes, that is the point. |
47 | | - |
48 | | -## Hello world |
| 66 | +You need [Bun](https://bun.sh) ≥ 1.3. Yes, that is the entire point. |
49 | 67 |
|
50 | | -It opens a real window now. We are as surprised as you are. |
| 68 | +## Quick start |
51 | 69 |
|
52 | 70 | ```ts |
53 | | -import { app, BrowserWindow } from 'sambar'; |
| 71 | +import { app, BrowserWindow } from 'bunmaska'; |
54 | 72 |
|
55 | 73 | app.whenReady().then(() => { |
56 | | - const win = new BrowserWindow({ width: 960, height: 720, title: 'Hello Sambar' }); |
| 74 | + const win = new BrowserWindow({ |
| 75 | + width: 1024, |
| 76 | + height: 768, |
| 77 | + title: 'Hello Bun Maska' |
| 78 | + }); |
57 | 79 | win.loadURL('https://example.com'); |
58 | 80 | }); |
59 | 81 | ``` |
60 | 82 |
|
61 | | -Run it with `bun run main.ts` (or `sambar run main.ts` — see below). A native |
62 | | -window appears, rendered by your operating system's own WebKit — no 100 MB of |
63 | | -Chromium in sight. |
64 | | - |
65 | | -### IPC, the way you remember it |
66 | | - |
67 | | -```ts |
68 | | -// main process |
69 | | -import { ipcMain } from 'sambar'; |
70 | | -ipcMain.handle('add', (_event, a, b) => a + b); |
71 | | -``` |
72 | | - |
73 | | -```ts |
74 | | -// preload |
75 | | -import { contextBridge, ipcRenderer } from 'sambar/renderer'; |
76 | | -contextBridge.exposeInMainWorld('api', { |
77 | | - add: (a, b) => ipcRenderer.invoke('add', a, b), |
78 | | -}); |
79 | | -``` |
80 | | - |
81 | | -`window.api.add(20, 22)` resolves to `42`, round-tripped through real WebKit — in a |
82 | | -dedicated isolated world, the way `contextIsolation: true` works in Electron. |
83 | | - |
84 | | -## Shipping an app |
| 83 | +Run it with `bun run main.ts` (or `bunmaska run main.ts` once you have the CLI). |
85 | 84 |
|
86 | | -Sambar ships a CLI (`sambar`) that runs and packages your app — pure Bun, no Xcode |
87 | | -project, no `electron-builder`: |
| 85 | +## The CLI |
88 | 86 |
|
89 | 87 | ```sh |
90 | | -sambar run main.ts # run your app |
91 | | -sambar build # produce distributables for the current OS |
| 88 | +bunmaska init my-app # scaffold a full starter (main + preload + renderer + config) |
| 89 | +bunmaska dev # run with file watching and auto-restart |
| 90 | +bunmaska run main.ts # just run it |
| 91 | +bunmaska build # produce distributables for the current OS |
| 92 | +bunmaska build --update # also emit the auto-update feed (update.json + .tar.zst) |
92 | 93 | ``` |
93 | 94 |
|
94 | | -`sambar build` compiles your app with `bun build --compile`, bundles it next to the |
95 | | -Bun runtime (it `dlopen`s system WebKit, so there is no Chromium to ship), and emits: |
96 | | - |
97 | | -- **macOS** — a `.app` bundle (with a `.icns` converted from your PNG), optional |
98 | | - code-signing/notarization, and a `.dmg`. |
99 | | -- **Linux** — an AppDir `.tar.gz` and a `.deb`. |
100 | | - |
101 | 95 | ## Migrating from Electron |
102 | 96 |
|
103 | | -Point your existing Electron imports at Sambar's drop-in shim: |
| 97 | +Change your imports: |
104 | 98 |
|
105 | 99 | ```ts |
106 | | -import { app, BrowserWindow } from 'sambar/electron'; |
| 100 | +// Before |
| 101 | +import { app, BrowserWindow, ipcMain } from 'electron'; |
| 102 | + |
| 103 | +// After |
| 104 | +import { app, BrowserWindow, ipcMain } from 'bunmaska'; |
| 105 | +// or use the explicit shim that throws helpful errors on unimplemented modules: |
| 106 | +import { app, BrowserWindow } from 'bunmaska/electron'; |
107 | 107 | ``` |
108 | 108 |
|
109 | | -Implemented modules behave like Electron's; anything not yet implemented throws an |
110 | | -actionable error naming the module (rather than failing silently), so you find the |
111 | | -gaps immediately. Sambar covers the architectural core (windows, web contents, IPC, |
112 | | -context isolation, menus, dialog, clipboard, tray, protocol, power, safeStorage, |
113 | | -nativeImage) on both platforms; see [docs/PARITY.md](./docs/PARITY.md) for the |
114 | | -module-by-module status and what is still pending. |
| 109 | +Most core modules behave the same. Anything not yet implemented throws an actionable error naming the exact missing module instead of failing mysteriously at 2 a.m. |
| 110 | + |
| 111 | +One migration detail worth knowing up front: Web Serial, WebHID, and WebUSB are Chromium-only. System WebKit does not expose them. If your app uses them from the renderer, that code needs to move to the main process and cross IPC (which, conveniently, is exactly where Bun Maska makes talking to hardware via FFI much more pleasant than the old `node-gyp` dance). |
115 | 112 |
|
116 | 113 | ## Contributing |
117 | 114 |
|
118 | | -If you have somehow found this repo before we invited anyone — hi. Open an issue, lower your expectations, and try not to be a jerk. The full contributing guide will appear once we have a working build to contribute to. |
| 115 | +You somehow found this repo before we told anyone. Hello. |
| 116 | + |
| 117 | +Open an issue. Keep your expectations realistic. Try not to be a jerk. A proper contributing guide will exist once the project is less "held together with optimism." |
119 | 118 |
|
120 | 119 | ## License |
121 | 120 |
|
|
0 commit comments