# IPC Channels Between Electron Renderer and Main Process in Modly: Complete Reference

> Explore Modly's IPC channels connecting Electron renderer and main processes. Understand typed preload bridges and API routing for efficient communication.

- Repository: [lightningpixel/modly](https://github.com/lightningpixel/modly)
- Tags: api-reference
- Published: 2026-08-15

---

**Modly implements a typed preload bridge where domain-specific API objects exposed to the React renderer route method calls to specific IPC channels handled in the main process via `ipcMain.handle` and `ipcMain.on`.**

Modly is an Electron-based 3D content creation platform that relies on structured inter-process communication to coordinate between its React frontend and Node.js backend capabilities. Understanding the IPC channels between the Electron renderer and main process in Modly reveals how the application manages window controls, file system operations, model downloads, and Python backend integration. The implementation centers on a strongly-typed preload bridge defined in [`electron/preload/electron-api.ts`](https://github.com/lightningpixel/modly/blob/main/electron/preload/electron-api.ts) that maps high-level JavaScript methods to low-level Electron IPC calls, with corresponding handlers registered in [`electron/main/ipc-handlers.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/ipc-handlers.ts).

## The Preload Bridge Architecture

Modly follows Electron's best practices for **context isolation** by using a preload script to safely expose main process capabilities to the renderer. The architecture consists of three core files:

- **[`electron/preload/index.ts`](https://github.com/lightningpixel/modly/blob/main/electron/preload/index.ts)** – Uses `contextBridge.exposeInMainWorld` to inject the API into `window.electron`
- **[`electron/preload/electron-api.ts`](https://github.com/lightningpixel/modly/blob/main/electron/preload/electron-api.ts)** – Defines typed methods that wrap `ipcRenderer.invoke`, `ipcRenderer.send`, and `ipcRenderer.on`
- **[`electron/main/ipc-handlers.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/ipc-handlers.ts)** – Registers main process handlers using `ipcMain.handle` (for request-response) and `ipcMain.on` (for fire-and-forget)

Each domain-specific namespace (window, filesystem, models, extensions) maps to a set of explicit channel strings following the pattern `domain:action`.

## Window Control IPC Channels

Window management uses a mix of fire-and-forget events and state queries:

| Channel | Direction | Handler Type | Source Location |
|---------|-----------|--------------|-----------------|
| `window:minimize` | Renderer → Main | `ipcMain.on` | [`electron/main/ipc-handlers.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/ipc-handlers.ts) |
| `window:maximize` | Renderer → Main | `ipcMain.on` | [`electron/main/ipc-handlers.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/ipc-handlers.ts) |
| `window:close` | Renderer → Main | `ipcMain.on` | [`electron/main/ipc-handlers.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/ipc-handlers.ts) |
| `window:isMaximized` | Renderer → Main | `ipcMain.handle` | [`electron/main/ipc-handlers.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/ipc-handlers.ts) |
| `window:maximizeChanged` | Main → Renderer | `ipcRenderer.on` | [`electron/preload/electron-api.ts`](https://github.com/lightningpixel/modly/blob/main/electron/preload/electron-api.ts) |

The `window:isMaximized` channel uses `invoke` to return a boolean promise, while `window:maximizeChanged` is a main-to-renderer event for state synchronization.

## File System and Dialog IPC Channels

The filesystem API provides comprehensive file and directory operations:

- `fs:selectImage` – Opens image picker dialog
- `fs:selectMeshFile` – Opens 3D mesh file picker
- `fs:selectDirectory` – Opens directory picker with default path
- `fs:selectTextFile` – Opens text file picker
- `fs:saveModel` – Saves model with dialog
- `fs:savePath` – Gets save path dialog
- `fs:readFileBase64` – Reads file as base64
- `fs:readScreenshotDataUrl` – Reads screenshot data
- `fs:listDir` – Lists directory contents
- `fs:listFiles` – Lists files in directory
- `fs:moveDirectory` – Moves directories between locations
- `fs:deleteDirectory` – Removes directories recursively

All filesystem channels use `ipcMain.handle` for request-response patterns, returning promises that resolve to file paths or data.

## Model Management IPC Channels

Model operations handle downloads, exports, and lifecycle management:

| Channel | Pattern | Purpose |
|---------|---------|---------|
| `model:listDownloaded` | Invoke | List cached models |
| `model:isDownloaded` | Invoke | Check if specific model exists |
| `model:download` | Invoke | Start model download |
| `model:pauseDownload` | Invoke | Pause active download |
| `model:cancelDownload` | Invoke | Cancel download job |
| `model:delete` | Invoke | Remove downloaded model |
| `model:unloadAll` | Invoke | Clear all loaded models |
| `model:showInFolder` | Invoke | Open model location in system file manager |
| `model:export` | Invoke | Export model to format |
| `model:downloadProgress` | Event | Push updates from main to renderer |

The `model:downloadProgress` channel uses `event.sender.send` from the main process to stream progress updates to the renderer, which listens via `ipcRenderer.on` in the preload bridge.

## Extension System IPC Channels

Extensions support installation, management, and process execution:

- `extensions:list` – List installed extensions
- `extensions:installFromGitHub` – Install from GitHub URL
- `extensions:installFromLocal` – Install from local path
- `extensions:uninstall` – Remove extension
- `extensions:repair` – Repair corrupted extension
- `extensions:reload` – Reload extension without restart
- `extensions:runProcess` – Execute extension subprocess
- `extensions:installProgress` – Event channel for installation feedback

The `extensions:installProgress` event provides real-time feedback during GitHub installations, streaming progress from the main process handler to the React UI.

## Python Backend Bridge Channels

Modly integrates a Python FastAPI backend using dedicated IPC channels:

| Channel | Direction | Purpose |
|---------|-----------|---------|
| `python:start` | Invoke | Spawn Python process |
| `python:status` | Invoke | Check if Python backend is running |
| `python:crashed` | Main → Renderer | Notify of Python process crash |
| `python:log` | Main → Renderer | Stream Python stdout/stderr logs |

The `python:start` handler in [`electron/main/ipc-handlers.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/ipc-handlers.ts) manages the Python subprocess lifecycle, while `python:crashed` and `python:log` push events from main to renderer for monitoring backend health.

## System, Settings, and Utility Channels

### System Information

- `system:memory` – Returns total, used, and available memory via `ipcMain.handle`

### Application Settings

- `settings:get` – Retrieve configuration value
- `settings:set` – Persist configuration change

### Cache Management

- `cache:clear` – Clear application cache directories

### Auto-updater

- `updater:check` – Check for application updates
- `updater:quitAndInstall` – Apply update and restart
- `updater:applying` – Event indicating update in progress
- `updater:major-minor-available` – Event for version availability

### Logging

- `log:error` – Send error logs from renderer to main
- `log:getPath` – Get log file location
- `log:readAll` – Read complete log contents
- `log:listSessions` – List available log sessions

### First-Run Setup

- `setup:check` – Verify first-run status
- `setup:saveDataDir` – Persist data directory selection
- `setup:run` – Execute setup workflow
- `setup:progress` – Event for setup step updates
- `setup:complete` – Event signaling setup finished
- `setup:error` – Event for setup failures

### Workspace Management

- `workspace:listCollections` – List project collections
- `workspace:createCollection` – Create new collection
- `workspace:renameCollection` – Rename existing collection
- `workspace:deleteCollection` – Remove collection
- `workspace:listJobs` – List processing jobs
- `workspace:saveJobMeta` – Persist job metadata
- `workspace:deleteJob` – Remove job record
- `workspace:library:list` – List asset library
- `workspace:library:read` – Read asset data
- `workspace:library:open` – Open asset location

Workspace library handlers are registered via `registerWorkspaceAssetLibraryIpcHandlers` in [`electron/main/artifact-registry-service.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/artifact-registry-service.ts).

## IPC Communication Patterns

Modly uses three distinct communication patterns:

**`ipcRenderer.invoke` / `ipcMain.handle`** – Used for request-response operations where the renderer needs data or confirmation. Returns a Promise that resolves with the handler's return value. Used by `fs:selectImage`, `model:download`, and `system:memory`.

**`ipcRenderer.send` / `ipcMain.on`** – Used for fire-and-forget messages where no response is needed. Common for window controls like `window:minimize` and logging via `log:error`.

**`ipcRenderer.on` / `event.sender.send`** – Used for main-to-renderer events. The main process pushes data to the renderer using `event.sender.send(channel, data)`, while the preload bridge sets up listeners via `ipcRenderer.on`. Used for progress updates (`model:downloadProgress`, `extensions:installProgress`) and backend notifications (`python:log`).

## Practical Usage Examples

### Controlling Window State

```typescript
// Minimize the application window
window.electron.window.minimize();

// Check if window is maximized
const isMaximized = await window.electron.window.isMaximized();

// Listen for maximize state changes
window.electron.window.onMaximizeChange((isMax) => {
  console.log(`Window maximized: ${isMax}`);
});

```

### Selecting Files and Directories

```typescript
// Open image picker dialog
const imagePath = await window.electron.fs.selectImage();

// Select directory with default path
const dirPath = await window.electron.fs.selectDirectory('/home/user/projects');

// Read file as base64 for preview
const base64Data = await window.electron.fs.readFileBase64('/path/to/model.obj');

```

### Managing Model Downloads with Progress

```typescript
// Start downloading a model
await window.electron.model.download('stable-diffusion-xl');

// Listen for progress updates
window.electron.model.onProgress((data) => {
  console.log(`Downloaded ${data.percent}% of ${data.modelId}`);
});

// Pause an active download
await window.electron.model.pauseDownload('stable-diffusion-xl');

```

### Installing Extensions

```typescript
// List installed extensions
const extensions = await window.electron.extensions.list();

// Install from GitHub with progress tracking
const result = await window.electron.extensions.installFromGitHub(
  'https://github.com/username/extension-repo'
);

// Listen to installation progress
window.electron.extensions.onInstallProgress((progress) => {
  console.log(`Installation: ${progress.stage} - ${progress.percent}%`);
});

```

### Querying System Resources

```typescript
// Get memory statistics
const mem = await window.electron.system.memory();
console.log(`Available: ${mem.available}MB / Total: ${mem.total}MB`);

```

## Summary

- **Modly uses a typed preload bridge** defined in [`electron/preload/electron-api.ts`](https://github.com/lightningpixel/modly/blob/main/electron/preload/electron-api.ts) that exposes `window.electron` to the React renderer, providing type-safe access to main process capabilities.
- **IPC channels follow a `domain:action` naming convention**, with domains including `window`, `fs`, `model`, `extensions`, `python`, `system`, and `workspace`.
- **Three communication patterns** are implemented: `invoke`/`handle` for request-response, `send`/`on` for fire-and-forget, and `event.sender.send`/`ipcRenderer.on` for main-to-renderer events.
- **File system operations** use `invoke` exclusively to return paths and file contents asynchronously.
- **Progress tracking** relies on main-to-renderer events for real-time updates during long-running operations like model downloads and extension installations.
- **Python backend integration** uses bidirectional IPC to manage subprocess lifecycle and stream logs to the UI.

## Frequently Asked Questions

### How does Modly secure IPC communications between renderer and main process?

Modly implements **context isolation** by using a preload script ([`electron/preload/index.ts`](https://github.com/lightningpixel/modly/blob/main/electron/preload/index.ts)) that explicitly exposes only necessary APIs via `contextBridge.exposeInMainWorld`. The [`electron-api.ts`](https://github.com/lightningpixel/modly/blob/main/electron-api.ts) file defines a typed interface that restricts renderer access to specific whitelisted channels, preventing arbitrary IPC calls and following Electron security best practices.

### Can I add custom IPC channels to Modly?

Yes. To add a new channel, define the method in [`electron/preload/electron-api.ts`](https://github.com/lightningpixel/modly/blob/main/electron/preload/electron-api.ts) using `ipcRenderer.invoke`, `send`, or `on`, then register the corresponding handler in [`electron/main/ipc-handlers.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/ipc-handlers.ts) using `ipcMain.handle` or `ipcMain.on`. Ensure channel names follow the existing `domain:action` convention and update the TypeScript interfaces to maintain type safety across the bridge.

### Why do some channels use `invoke` while others use `send`?

**`invoke`** is used when the renderer requires a response or confirmation from the main process, such as retrieving file paths (`fs:selectImage`) or checking system memory (`system:memory`). **`send`** is used for fire-and-forget operations where no return value is needed, such as window minimization (`window:minimize`) or logging errors (`log:error`). Event channels like `model:downloadProgress` use `ipcRenderer.on` to receive push notifications from the main process.

### Where are the IPC handlers for workspace library operations defined?

While most IPC handlers reside in [`electron/main/ipc-handlers.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/ipc-handlers.ts), the workspace library-specific channels (`workspace:library:list`, `workspace:library:read`, `workspace:library:open`) are registered through the `registerWorkspaceAssetLibraryIpcHandlers` function in [`electron/main/artifact-registry-service.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/artifact-registry-service.ts), demonstrating how Modly modularizes IPC registration across different service files.