⚠️
Early Development

Gelectron is a non-commercial, community-driven open source project in early development. APIs may change. Not all features are implemented. Not affiliated with or endorsed by Electron or Mozilla.

Introduction

Gelectron is a drop-in replacement for Electron that uses the OS platform WebView (WKWebView / WebView2 / WebKitGTK) instead of Chromium, with a Rust core for native operations. The goal is to provide the same developer experience with smaller binaries and lower memory usage.

Feature Electron Gelectron
Rendering Engine Chromium Platform WebView (WKWebView / WebView2 / WebKitGTK)
Language C++ / Node.js Rust / Node.js
API Compatibility Native Drop-in replacement (in progress)
Memory Usage High (~586 MB total RSS) Lower (~131 MB total RSS)
Node.js in Renderer Yes No (main process only)

Prerequisites

  • Rust — stable toolchain 1.75+ (rustup.rs)
  • Node.js — 18 or newer
  • npm — comes with Node.js
  • Git — for cloning the repo
Check your versions
rustc --version    # should be 1.75+
node --version     # should be 18+
npm --version

Installation

Clone and install
git clone https://github.com/mileswolfallen2/gelectron.git
cd gelectron
npm install
Build the native binary
cargo build --release -p gelectron

The first build will take a while — the Rust toolchain compiles tao and wry. Subsequent builds are much faster.

Quick Start

The fastest way to see Gelectron running:

Run the demo
cargo run --release -p gelectron -- demo/

This opens a window with an interactive demo app running HTML, CSS, JavaScript, canvas animations, and a live clock.

To run your own Electron app:

cargo run --release -p gelectron -- /path/to/your/electron-app

CLI Reference

Command Description
gelectron <path-to-app> Run an Electron app
gelectron <file.js> Run a main process script directly
gelectron --version Print version
gelectron --help Show help

Node.js Fallback

If you don't want to build the Rust binary, the CLI can fall back to a pure Node.js shim:

node cli/gelectron.js /path/to/electron-app

In fallback mode no real window is created — only the JS API layer loads. Use the native binary for actual rendering.

Running Apps

Gelectron reads your app's package.json to find the main script, just like Electron does. Your existing Electron code should work without changes for basic apps.

Your app's package.json
{
  "name": "my-app",
  "main": "main.js"
}
Your app's main.js
const { app, BrowserWindow } = require('electron');
const path = require('path');

app.whenReady().then(() => {
  const win = new BrowserWindow({ width: 800, height: 600 });
  win.loadFile(path.join(__dirname, 'index.html'));
});

app.on('window-all-closed', () => app.quit());

Then run it:

cargo run --release -p gelectron -- .

Demo App

The included demo showcases Gelectron's capabilities:

  • Interactive counter (DOM updates via JS)
  • Live clock driven by requestAnimationFrame
  • Animated canvas with moving shapes
  • CSS grid, gradients, transitions, and flexbox
Demo structure
demo/
├── package.json    # { "main": "main.js" }
├── main.js         # Creates BrowserWindow, loads index.html
└── index.html      # HTML + CSS + JavaScript

Packaging for Distribution

Use gelectron-packager to build standalone executables:

Package your app
# Install the packager
cd packager && npm link && cd ..

# Package for current platform
gelectron-packager --dir ./my-app --name MyApp

# Package for specific platforms
gelectron-packager --dir ./my-app --name MyApp --platform darwin --arch arm64
gelectron-packager --dir ./my-app --name MyApp --platform win32 --arch x64
gelectron-packager --dir ./my-app --name MyApp --platform linux --arch x64

The packager creates a self-contained distributable with the Rust binary, a bundled Node.js runtime (~20 MB), your app source, node_modules, and the Electron compatibility layer.

Platform Output
macOS .app bundle (double-click to run)
Windows Directory with .exe + .bat launcher
Linux Directory with launcher script + .desktop file
🔄
Auto-update artifacts

Every package also generates an update/ folder with a full-bundle .tar.gz and a latest.yml manifest (version, path, sha512). Upload both to a GitHub release and point the app's autoUpdater.setFeedURL() at latest.yml. Launcher scripts on macOS/Linux/Windows apply staged updates atomically before the app starts.

Main Process Modules

These modules are available via require('electron') in the main process.

Module Status Notes
app Full All methods, properties, events, quit lifecycle, dock, badge, GPU, about panel, secure keyboard, window tracking
ipcMain Full handle(), handleOnce(), on(), once(), removeHandler(), full EventEmitter
BrowserWindow Partial create/show/hide/focus/min/max/close/destroy/setTitle/setSize/loadURL/loadFile. Missing: DevTools, navigation, capturePage, print, printToPDF
Menu Partial buildFromTemplate/append/insert/getMenuItemById, native setApplicationMenu via muda, _serialize. Missing: click events from native menu, role-based items
MenuItem Partial All properties (id/label/type/role/accelerator/enabled/visible/checked/submenu/click). Missing: role auto-behavior
dialog Partial showOpenDialog/showSaveDialog/showMessageBox/showErrorBox. Native dialogs not wired
shell Partial openExternal(), openPath() (Node mode). Missing: moveItemToTrash deletes permanently, shortcut stubs
Notification Partial API surface complete, show via browser Notification API if available. No native OS integration
nativeImage Partial createFromPath/Buffer/DataURL, toDataURL, getSize. Missing: resize/crop pixel transform, proper toPNG/toJPEG
net Partial fetch delegates to globalThis.fetch. Missing: net.request(), ClientRequest API
process Partial WebView mode polyfill: pid/argv/env/platform/versions/cwd/nextTick. Missing: memoryUsage/cpuUsage/uptime/kill
webContents Partial loadURL/loadFile/send/executeJavaScript/reload, session stub. Missing: navigation history, DevTools CDP, zoom, print, capturePage
Tray Stub API surface present, no native system tray
safeStorage Stub Base64 encoding, not real encryption
autoUpdater Partial Real implementation: setFeedURL/checkForUpdates/downloadUpdate/quitAndInstall/checkForAndNotifyIfAvailable, full event set, sha512-verified download, staged atomic apply on relaunch. Packaged apps only, requires a hosted latest.yml feed
session Stub defaultSession + fromPartition stubs, all no-ops
clipboard Full Full API: readText/writeText/readHTML/writeHTML/readRTF/writeRTF/readImage/writeImage/readBookmark/writeBookmark/readFindText/writeFindText/clear/availableFormats/has. Sync via Unix FIFO channel (macOS/Linux) or async bridge (Windows); RTF/bookmark/find-text/formats via NSPasteboard on macOS
nativeTheme Partial shouldUseDarkColors (getter + method), themeSource (getter/setter), shouldSystemUseDarkColors, queries Rust for system theme. Missing: theme change events
screen Partial getPrimaryDisplay/getAllDisplays/getDisplayMatching/getCursorScreenPoint/getMenuBarHeight via Rust bridge (tao). Missing: display event listeners
systemPreferences Stub Hardcoded dark mode / accent color
powerMonitor Stub getSystemIdleState returns 'active', no real monitoring
globalShortcut Stub register() always returns true, does nothing

Renderer Process Modules

Module Status Notes
ipcRenderer Partial invoke(), send(), sendSync(), on(), once(), removeListener(). Bridge not always wired, sendSync returns undefined
contextBridge Partial exposeInMainWorld with deep freeze. No real world isolation
clipboard (renderer) Full Same as main process: readText/writeText/readHTML/readImage/readRTF/readBookmark/readFindText/clear/availableFormats/has via bridge
ℹ️
No Node.js in the renderer

Gelectron's renderer is a clean browser context. There is no require(), no file system access, no native modules in the renderer. This is architecturally different from Electron. All Node.js code runs in the main process.

Common Modules

These modules are available in both main and renderer processes.

Module Status Notes
nativeImage Partial createFromPath/Buffer/DataURL, toDataURL, getSize. Missing: resize/crop transform
shell Partial openExternal/openPath in Node mode

Deprecated / Internal

Module Status Notes
BrowserView Missing Deprecated, replaced by WebContentsView
remote Missing Removed in Electron 14+
webviewTag Missing Deprecated, replaced by BrowserView/WebContentsView
process (polyfill) Partial WebView mode polyfill: pid/argv/env/platform/versions/cwd/nextTick. Missing: memoryUsage/cpuUsage/uptime/kill
contextIsolation Stub webPreferences.contextIsolation stored but no actual V8 isolate separation

Missing Modules

These modules have not been started.

BaseWindow BrowserView contentTracing crashReporter desktopCapturer ImageView inAppPurchase MessageChannelMain netLog powerSaveBlocker protocol pushNotifications ServiceWorkerMain sharedTexture ShareMenu TouchBar utilityProcess View WebContentsView webFrameMain crashReporter (renderer) sharedTexture (renderer) webFrame webUtils remote webviewTag navigation-history parent-port web-request web-socket window-open local-ai-handler
📋
Additional missing APIs

BaseWindow, ImageView, inAppPurchase, MessageChannelMain, powerSaveBlocker, ServiceWorkerMain, sharedTexture, View, WebContentsView, webFrameMain, webFrame, webUtils, navigation-history, parent-port, web-request, web-socket, window-open, local-ai-handler

How It Works

Gelectron has two execution paths:

1. Native Binary (recommended)

A standalone Rust binary using tao (windowing) and wry (WebView). It:

  1. Reads the target app's package.json to find the main script
  2. Generates a Node.js setup script that patches require('electron') to point at Gelectron's JS compatibility layer
  3. Spawns Node.js as a child process with piped stdin/stdout
  4. Runs a tao event loop with wry WebView windows
  5. Communicates with Node.js via JSON-line IPC

2. Node.js Fallback

When the native binary is not built, the CLI falls back to pure Node.js:

  1. Patches Module._resolveFilename so require('electron') resolves to Gelectron's shim
  2. Loads the app's main script — the app runs against the JS compatibility layer
  3. No real window is created (API-only mode)
Your App
HTML / CSS / JavaScript + package.json
Gelectron JS Compatibility Layer
app · BrowserWindow · Menu · Tray · ipcMain · ipcRenderer · dialog · shell · Notification · nativeImage · contextBridge
Gelectron Core (Rust)
tao (windowing) · wry (WebView) · JSON-line IPC to Node.js
Servo Engine (future)
Stylo (CSS) + WebRender (GPU) — currently using platform native WebView

Project Structure

Repository layout
gelectron/
├── Cargo.toml                    # Rust workspace root
├── package.json                  # npm package
├── cli/
│   └── gelectron.js              # CLI entry point (Node.js fallback)
├── src/electron/                 # JS Electron compatibility layer
│   ├── index.js                  # Main exports
│   ├── app.js                    # app lifecycle
│   ├── browser-window.js         # BrowserWindow + WebContents
│   ├── ipc-main.js              # ipcMain
│   ├── ipc-renderer.js          # ipcRenderer
│   ├── menu.js                  # Menu + MenuItem
│   ├── tray.js                  # Tray
│   ├── dialog.js                # File/message dialogs
│   ├── shell.js                 # Shell operations
│   ├── notification.js          # Notifications
│   ├── native-image.js          # Image handling
│   ├── context-bridge.js        # contextBridge
│   └── auto-updater.js          # autoUpdater (real implementation)
├── crates/
│   ├── gelectron-core/          # N-API addon (Rust → Node.js)
│   └── gelectron-app/           # Standalone native binary
├── demo/                        # Demo app
├── packager/                    # gelectron-packager CLI
└── npm/darwin-arm64/            # Platform-specific npm packages

Environment Variables

Variable Description
GELECTRON_DEV=1 Enable development mode
GELECTRON_LOG=1 Enable verbose logging
VITE_DEV_SERVER_URL=<url> Connect to a Vite dev server
RUST_LOG=info Enable Rust-side logging

Contributing

  1. Fork the repo
  2. Create a feature branch
  3. Make your changes
  4. Build and test: cargo build --release -p gelectron
  5. Test with the demo: cargo run --release -p gelectron -- demo/
  6. Submit a PR

Known Limitations

  • Servo not fully embedded — current WebView uses platform native (WebKit on macOS, WebView2 on Windows, webkit2gtk on Linux)
  • No Node.js in renderer — all Node.js code runs in the main process only
  • Auto-updater is packaged-app only — real checks/downloads/installs for packaged apps with a hosted feed; no-op in development and Node.js fallback mode
  • Single-window only in the standalone binary
  • Preload scripts are injected via WebView init scripts, not true Electron preload isolation
  • Some APIs are stubs — see the API reference for details