| name | electrobun-core |
| description | This skill should be used when the user is working on any Electrobun desktop app, asks about "BrowserWindow", "BrowserView", "electrobun events", "app lifecycle", "ApplicationMenu", "Tray", or "electrobun.config.ts". Activates automatically when editing Electrobun project files. |
| version | 1.0.0 |
Electrobun Core Patterns
Electrobun is a cross-platform desktop app framework (macOS/Windows/Linux) using Bun as runtime and a native system webview (or CEF) as renderer. The bun process and renderer run as separate processes; they communicate via RPC (see electrobun-rpc skill).
Project Structure
src/
├── bun/ # Main process (Bun side)
│ └── index.ts # Entry point
└── mainview/ # Renderer process
├── index.html
├── index.css
└── index.ts
electrobun.config.ts
import { defineConfig } from "electrobun/config";
export default defineConfig({
app: {
name: "MyApp",
identifier: "com.example.myapp",
version: "1.0.0",
urlSchemes: ["myapp"],
},
build: {
bun: { entrypoint: "src/bun/index.ts" },
views: {
mainview: { entrypoint: "src/mainview/index.ts" },
},
mac: {
bundleWGPU: false,
bundleCEF: false,
defaultRenderer: "native",
codesign: true,
notarize: true,
icons: "assets/icon.icns",
},
win: { bundleWGPU: false, bundleCEF: false, icon: "assets/icon.ico" },
linux: { bundleWGPU: false, bundleCEF: false },
copy: { "assets/": "assets/" },
},
runtime: { exitOnLastWindowClosed: true },
scripts: {
preBuild: "bun run generate-assets.ts",
postBuild: "echo Build complete",
},
release: {
baseUrl: "https://releases.example.com/myapp",
generatePatch: true,
},
});
BrowserWindow
import { BrowserWindow } from "electrobun/bun";
const win = new BrowserWindow({
title: "My App",
frame: { x: 100, y: 100, width: 1200, height: 800 },
url: "http://localhost:3000",
html: "<h1>Hello</h1>",
preload: "src/mainview/preload.ts",
renderer: "native",
titleBarStyle: "hiddenInset",
transparent: false,
sandbox: false,
});
The primary webview is win.webview (a BrowserView instance).
BrowserView (additional views)
import { BrowserView } from "electrobun/bun";
const sidebar = new BrowserView({
url: "src/sidebar/index.html",
frame: { x: 0, y: 0, width: 300, height: 800 },
renderer: "native",
rpc: sidebarRPC,
navigationRules: {
allowedUrls: ["http://localhost:*"],
deniedUrls: ["*"],
},
});
win.addBrowserView(sidebar);
Each BrowserView is a separate renderer process.
Events
import { Electrobun } from "electrobun/bun";
Electrobun.events.on("open-url", (e) => {
console.log("Deep link:", e.data.url);
});
Electrobun.events.on("application-menu-clicked", (e) => {
const { action, role } = e.data;
win.webview.rpc?.send.menuAction({ action, role });
});
win.on("close", () => { });
win.webview.on("dom-ready", () => { });
win.webview.on("will-navigate", (e) => { });
win.webview.on("did-navigate", (e) => { });
win.webview.on("page-title-updated", (e) => { });
ApplicationMenu
import { ApplicationMenu } from "electrobun/bun";
ApplicationMenu.setMenu([
{
label: "File",
submenu: [
{ label: "New", action: "file-new", accelerator: "CmdOrCtrl+N" },
{ label: "Open", action: "file-open", accelerator: "CmdOrCtrl+O" },
{ type: "separator" },
{ label: "Quit", role: "quit" },
],
},
{
label: "Edit",
submenu: [
{ label: "Undo", role: "undo" },
{ label: "Redo", role: "redo" },
{ type: "separator" },
{ label: "Cut", role: "cut" },
{ label: "Copy", role: "copy" },
{ label: "Paste", role: "paste" },
],
},
]);
Tray
import { Tray } from "electrobun/bun";
const tray = new Tray({
icon: "assets/tray-icon.png",
tooltip: "My App",
});
tray.setMenu([
{ label: "Show", action: "tray-show" },
{ label: "Quit", role: "quit" },
]);
Platform Quirks
- Linux: ApplicationMenu renders as app menu bar. Tray click events don't fire with AppIndicator.
- Windows:
titleBarStyle: "hiddenInset" has no effect — use "hidden".
- macOS: Full native feel. All APIs work as documented.
- CEF renderer: Requires
bundleCEF: true in config; adds ~120MB to bundle size.
CLI Commands
bunx electrobun init
electrobun dev
electrobun dev --watch
electrobun build
electrobun build --env=canary
electrobun run