npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lotus-gui/core

v0.3.0

Published

The runtime engine for Lotus applications. Provides the Servo rendering engine, window management, and IPC system as a Node.js native addon.

Downloads

1,702

Readme

@lotus-gui/core

The runtime engine for Lotus applications. Provides the Servo rendering engine, window management, and IPC system as a Node.js native addon.

🪷 Lotus Core (@lotus-gui/core)

The high-performance, low-latency engine at the heart of the Lotus ecosystem.

🚀 What’s New in v0.3.0 (Windows & Linux Hardening)

This release focuses on distribution-grade stability. We’ve moved beyond the prototype phase and into a "hardened" runtime that handles the "dirty work" of desktop development automatically. I think this is the first release that I would feel comfortable shipping to users for some apps.

⚡ Sub-Millisecond IPC: Our new tokio + axum WebSocket bridge now achieves a deterministic ~0.11ms latency. We’ve added opportunistic 500μs flushing and MsgPack batching to ensure your UI thread never starves, even under extreme telemetry loads. Replacing the old tiny_http was a bit of a dance but it seems to be well worth it for the performance gains.

🛡️ Reload-Safe Queuing: Introducing WS_PENDING. If your window reloads, Rust automatically buffers outgoing IPC messages and drains them the moment the new JS context connects. No more lost "init" data.

👻 Native Stealth Mode: On Windows, we now hard-patch the PE Subsystem header. Your app launches as a true GUI process—no black Node.js console window, ever.

🎨 Ghost-Mode Transparency: Zero-white-flash startup with true OS-level transparency. If your CSS is transparent, your window is transparent.

"Node.js runs the logic. Servo paints the pixels. Lotus Core makes them talk at the speed of light."

Installation

npm install @lotus-gui/core

Note: Pre-built binaries are available for Linux (x86_64) and Windows (x64). You likely do not need to build from source. Seriously, save your CPU cycles. I bled so you don't have to.

API Reference

Exports

const { ServoWindow, ipcMain, app } = require('@lotus-gui/core');

app

The application lifecycle controller.

| Method | Description | |--------|-------------| | app.warmup() | Pre-initialize the Servo engine. Call before creating windows for faster startup. Like revving the engine at a red light. | | app.quit() | Shut down the application. Terminate with extreme prejudice. |

app.warmup(); // Pre-warm the engine

ServoWindow

Creates and manages a native window powered by the Servo rendering engine. Extends EventEmitter.

Constructor Options

const win = new ServoWindow(options);

| Option | Type | Default | Description | |--------|------|---------|-------------| | id | string | Random UUID | Window identifier. Required for state persistence (unless you want goldfish memory). | | root | string | undefined | Absolute path to UI directory. Enables Hybrid Mode (lotus-resource://). Keeps your files properly jailed. | | index | string | 'index.html' | Entry HTML file (relative to root). | | initialUrl | string | -- | URL to load (alternative to root + index). | | width | number | 1024 | Window width in pixels. | | height | number | 768 | Window height in pixels. | | title | string | 'Lotus' | Window title. | | transparent | boolean | false | Enable OS-level window transparency. Make your app look like a ghost. | | visible | boolean | true | Show window immediately. Set false to show after frame-ready to avoid the dreaded white flash of death. | | frameless | boolean | false | Remove the native window frame. Enables custom drag regions. The OS doesn't own your title bar anymore. | | resizable | boolean | true | Allow window resizing. | | maximized | boolean | false | Start maximized. Assert dominance immediately. | | fullscreen | boolean | false | Start in fullscreen. | | alwaysOnTop | boolean | false | Keep window above others. Because you're the main character. | | restoreState | boolean | true | Restore previous position/size (requires id). |

Methods

| Method | Description | |--------|-----------| | win.loadUrl(url) | Navigate to a URL. | | win.executeScript(js) | Execute JavaScript in the renderer context. | | win.sendToRenderer(channel, data) | Send data to the renderer on a named channel. | | win.setTitle(title) | Update the window title. | | win.setDecorations(bool) | Toggle native window decorations at runtime. | | win.setSize(width, height) | Resize the window. | | win.setMinSize(width, height) | Set the minimum size the user can resize to. Pass 0, 0 to remove the constraint. | | win.setMaxSize(width, height) | Set the maximum size the user can resize to. Pass 0, 0 to remove the constraint. | | win.setPosition(x, y) | Move the window. | | win.minimize() | Minimize the window to the taskbar/dock. | | win.unminimize() | Restore the window from a minimized state. | | win.maximize() | Maximize the window to fill the screen. | | win.unmaximize() | Restore the window from a maximized state. | | win.focus() | Bring the window to the front and request focus. | | win.show() | Show the window. | | win.hide() | Hide the window. | | win.close() | Close and destroy the window. |

Events

| Event | Callback | Description | |-------|----------|-------------| | 'ready' | () | Window has been created and is operational. Ready for orders. | | 'frame-ready' | () | First frame has been rendered. Best time to call show() unless you actually enjoy blinding your users. | | 'load-status' | (status: string) | Page load status changed ('loading', 'complete', etc.). | | 'moved' | ({ x: number, y: number }) | Window position changed on the screen. | | 'resize' | ({ width: number, height: number }) | Window size changed. | | 'focus' | () | Window gained focus. | | 'blur' | () | Window lost focus. | | 'closed' | () | Window was closed. | | 'file-hover' | ({ path: string }) | A file is being dragged over the window. Fires once per file. | | 'file-hover-cancelled' | () | A drag operation left the window without dropping. | | 'file-drop' | ({ path: string }) | A file was dropped onto the window. Fires once per file -- accumulate multiple events if you need multi-file support. |

const win = new ServoWindow({
    id: 'main',
    root: path.join(__dirname, 'ui'),
    transparent: true,
    visible: false // Don't show until ready
});

// Show only after first frame (prevents white flash)
win.once('frame-ready', () => win.show());

ipcMain

Handles communication between the main process (Node.js) and renderer (webpage). Extends EventEmitter.

Main Process

const { ipcMain } = require('@lotus-gui/core');

// Listen for messages from the renderer (fire-and-forget)
ipcMain.on('channel-name', (data) => {
    console.log('Got:', data);
});

// Send to all windows
ipcMain.send('response-channel', { status: 'ok' });

// Request/reply handler -- works with window.lotus.invoke() in the renderer
ipcMain.handle('get-user', async ({ id }) => {
    const user = await db.findUser(id); // may return a Promise
    return user;                         // auto-sent back to the renderer
});

Renderer (Webpage)

The window.lotus bridge is automatically injected into every page.

// Fire-and-forget: send a message to Node.js
window.lotus.send('channel-name', { key: 'value' });

// Binary data
window.lotus.send('binary-channel', new Blob(['binary data']));

// Listen for messages pushed from Node.js
window.lotus.on('response-channel', (data) => {
    console.log('Got:', data);
});

// Promise-based invoke -- awaits a reply from ipcMain.handle()
const user = await window.lotus.invoke('get-user', { id: 42 });
console.log(user.name);

IPC Pattern Reference

| Pattern | Renderer | Node.js | Use when | |---------|----------|---------|----------| | Fire-and-forget | lotus.send(ch, data) | ipcMain.on(ch, fn) | Notifications, events | | Push from Node | lotus.on(ch, fn) | ipcMain.send(ch, data) | Server-initiated updates | | Request/reply | await lotus.invoke(ch, data) | ipcMain.handle(ch, async fn) | Queries, CRUD, any async call |

Note: handle and on can coexist on the same channel. handle only fires when the message includes a _replyId (i.e., sent via invoke). Plain send calls still reach on listeners.

Concepts

Hybrid Mode (lotus-resource://)

Instead of spinning up a whole HTTP server just to serve your UI files (which, let's be honest, is embarrassing), Lotus serves them directly from disk via the lotus-resource:// custom protocol.

const win = new ServoWindow({
    root: path.join(__dirname, 'ui'),  // Files served from here
    index: 'index.html'               // Entry point
});
// Internally loads: lotus-resource://localhost/index.html

Benefits:

  • No HTTP server overhead. Because you're serving static files, not running a datacenter.
  • No port collisions. Because EADDRINUSE on port 8080 is cursed.
  • Directory jailing. You can't escape the root path. Try ../../, I dare you.

Transparency (No White Flash)

const win = new ServoWindow({
    transparent: true,
    visible: false
});

win.once('frame-ready', () => win.show());

The window background is fully transparent until your CSS paints it. Combined with visible: false, this entirely eliminates the white flash that plagues web gui based apps. You're welcome.

body { background: transparent; }
.app { background: rgba(0, 0, 0, 0.9); }

Window State Persistence

Windows with an id automatically save their position, size, and maximized state to ~/.config/<app-name>/window-state.json. By default, windows are amnesiac. Give them an id so they remember where they parked.

const win = new ServoWindow({
    id: 'main-window',    // Required for state saving
    restoreState: true     // Default
});

Frameless Windows

Remove native window decorations and implement your own title bar, controls, and drag behavior entirely in HTML/CSS.

const win = new ServoWindow({
    frameless: true,
    transparent: true,   // Pair with transparent for a fully custom look
    visible: false,
});
win.once('frame-ready', () => win.show());

Drag Regions

Lotus automatically detects elements with -webkit-app-region: drag or data-lotus-drag and registers them as drag handles. No JavaScript needed on your side.

<!-- Option 1: CSS property (same as macOS/Electron convention) -->
<div style="-webkit-app-region: drag; cursor: grab; height: 36px;">
    Drag to move window
</div>

<!-- Option 2: Data attribute -->
<div data-lotus-drag="true" style="cursor: grab; height: 36px;">
    Drag to move window
</div>

How it works:

  1. Injected JS scans the DOM for matching elements using MutationObserver + ResizeObserver.
  2. Their bounding rects are sent to Rust via the IPC batch channel (lotus:set-drag-regions).
  3. On MouseDown inside a registered region, Lotus calls drag_window() on the OS.
  4. On MouseDown on the 8px resize border, Lotus calls drag_resize_window() on the OS.
  5. Servo handles all other mouse events and cursor changes normally.

Resize Borders

Frameless windows automatically get 8px invisible hit-zones on every edge and corner. No configuration needed. Move the mouse to any edge to see the resize cursor and click-drag to resize.

Cursor Behavior

| Zone | Who controls the cursor | |------|--------------------------| | 8px resize border | Rust (shows directional resize cursors) | | Drag region | Servo/CSS (cursor: grab, etc.) | | Content area | Servo/CSS (cursor: pointer, cursor: text, etc.) |

CSS cursors work normally inside the window -- cursor: grab, cursor: pointer, cursor: text, cursor: wait all function exactly as expected on hover.

Multi-Window

Each window costs ~80MB (shared renderer). No new browser instances. We don't spawn a whole new universe (or download more RAM) just for a popup.

const win1 = new ServoWindow({ id: 'editor', title: 'Editor' });
const win2 = new ServoWindow({ id: 'preview', title: 'Preview' });

Architecture

@lotus-gui/core
├── src/lib.rs           # Rust N-API bindings, Servo event loop, IPC
├── src/window_state.rs  # Window position/size persistence
├── src/platform.rs      # OS-specific integrations (themes, cursors)
├── lotus.js             # High-level JS API (ServoWindow, IpcMain, App)
├── index.js             # Native .node binary loader
└── resources/           # IPC bridge injection scripts

The Rust layer (src/lib.rs) handles:

  • Servo lifecycle and rendering
  • Native window creation via winit/glutin(winit/surfman/mozangle on Windows)
  • IPC server (tokio + axum on 127.0.0.1:0 via WebSockets)
  • lotus-resource:// protocol handler
  • Event dispatch to Node.js via MsgPack

The JavaScript layer (lotus.js) provides:

  • ServoWindow class wrapping native window handles
  • IpcMain event emitter for message routing, including handle() for request/reply patterns
  • Auto-fix for Linux TLS allocation issues
  • Profiling support (--profile flag)

Building from Source

Prerequisites

  • Rust stable toolchain
  • Node.js v22+
  • System libraries (OpenGL, OpenSSL, fontconfig)

Build

# From the monorepo root
cd packages/lotus-core

# Debug build
npm run build:debug

# Release build (optimized)
npm run build

Warning: First build compiles the Servo rendering engine. This takes a while. Go grab a coffee, or question your life choices. Subsequent builds are much faster.

Runtime Dependencies

| Package | Purpose | |---------|---------| | msgpackr | MsgPack serialization for IPC (binary message packing) |

These are installed automatically when you npm install @lotus-gui/core.

License

MIT