# How the RAM Indicator in the Top Bar Sources and Displays Memory Usage in Modly

> Learn how the Modly RAM indicator sources and displays memory usage by polling Node.js APIs and rendering a color-coded progress bar. Understand your system's memory at a glance.

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

---

**The RAM indicator polls Node.js `os` APIs every 2 seconds via an Electron IPC bridge, formats bytes to gigabytes, and renders a color-coded progress bar that can be toggled in application settings.**

The Modly desktop application includes a real-time memory monitor in its top bar. This guide examines the complete data flow—from user preference to OS-level queries—based on the [lightningpixel/modly](https://github.com/lightningpixel/modly) source code.

## Architecture Overview

The RAM indicator spans four architectural layers:

| Layer | Key File | Purpose |
|-------|----------|---------|
| **Settings UI** | [`src/areas/settings/components/ApplicationSection.tsx`](https://github.com/lightningpixel/modly/blob/main/src/areas/settings/components/ApplicationSection.tsx) | Toggle visibility |
| **Global State** | [`src/shared/stores/appStore.ts`](https://github.com/lightningpixel/modly/blob/main/src/shared/stores/appStore.ts) | Persist preference across sessions |
| **Top Bar** | [`src/shared/components/layout/TopBar.tsx`](https://github.com/lightningpixel/modly/blob/main/src/shared/components/layout/TopBar.tsx) | Conditional rendering |
| **Indicator Logic** | [`src/shared/components/layout/MemoryIndicator.tsx`](https://github.com/lightningpixel/modly/blob/main/src/shared/components/layout/MemoryIndicator.tsx) | Sample, format, and visualize memory |

---

## User Preference and Global State

The visibility of the RAM indicator is controlled through a **zustand** store with persistence.

### Settings Toggle

In the Application settings panel, a boolean toggle wires directly to the store:

```tsx
// src/areas/settings/components/ApplicationSection.tsx
const { showRamIndicator, setShowRamIndicator } = useAppStore()

<Toggle
  value={showRamIndicator}
  onChange={setShowRamIndicator}
  label="RAM indicator"
/>

```

### Persisted Store Configuration

`appStore` uses **zustand-persist** to survive application restarts:

```ts
// src/shared/stores/appStore.ts
showRamIndicator: true,
setShowRamIndicator: (v) => set({ showRamIndicator: v }),

```

The store rehydrates automatically on launch, restoring the user's last preference.

---

## Top Bar Integration

The `TopBar` component consumes the flag and conditionally mounts the indicator:

```tsx
// src/shared/components/layout/TopBar.tsx
const { patchUpdateReady, platform, showRamIndicator } = useAppStore()

{showRamIndicator && <MemoryIndicator />}

```

This pattern keeps the top bar lightweight when the indicator is disabled.

---

## Memory Sampling and Display

[`MemoryIndicator.tsx`](https://github.com/lightningpixel/modly/blob/main/MemoryIndicator.tsx) handles all OS communication, formatting, and rendering.

### Polling Mechanism

On mount, the component establishes a 2-second polling interval:

```tsx
// src/shared/components/layout/MemoryIndicator.tsx
useEffect(() => {
  let cancelled = false;
  
  const tick = async () => {
    const stats = await window.electron.system.memory(); // IPC call
    if (!cancelled) setMem(stats);
  };
  
  tick(); // immediate first sample
  const id = setInterval(tick, 2000);
  
  return () => {
    cancelled = true;
    clearInterval(id);
  };
}, []);

```

The `cancelled` flag prevents state updates after unmount, avoiding memory leaks.

### Data Transformation

Raw bytes are converted for human-readable display:

```tsx
const pct = mem.total > 0 
  ? Math.min(100, Math.round((mem.used / mem.total) * 100)) 
  : 0;

// fmtGB converts bytes → GB with fixed decimal precision
<span>{fmtGB(mem.used)} / {fmtGB(mem.total)} GB</span>

```

### Visual Rendering

The indicator renders as a compact progress bar with dynamic coloring:

```tsx
<div className="w-20 h-1.5 bg-zinc-900 rounded-full overflow-hidden">
  <div
    className={`h-full ${barColor} transition-all duration-500 ease-out`}
    style={{ width: `${pct}%` }}
  />
</div>
<span className={`text-[11px] ${textColor}`}>
  {fmtGB(mem.used)} / {fmtGB(mem.total)} GB
</span>

```

**Color thresholds** (implemented via Tailwind classes):
- **Green** — low usage
- **Amber** — moderate usage  
- **Red** — high usage

A multi-line tooltip exposes exact byte values on hover.

---

## Electron IPC Bridge

The `window.electron.system.memory()` call traverses Electron's context bridge:

| Step | Location | Action |
|------|----------|--------|
| Preload | [`electron/preload/electron-api.ts`](https://github.com/lightningpixel/modly/blob/main/electron/preload/electron-api.ts) | Exposes `system.memory()` to renderer |
| Main | [`electron/main/system.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/system.ts) | Executes Node.js `os.totalmem()` and `os.freemem()` |
| Calculation | Main process | `used = total - free` |
| Return | IPC | Plain object `{ total, used, available }` |

This architecture isolates privileged OS calls to the main process while keeping the renderer sandboxed.

---

## Complete Implementation Example

To replicate the indicator's core logic in your own component:

```tsx
import { useEffect, useState } from 'react';

type MemStats = { total: number; used: number; available: number };

export function MemoryIndicator() {
  const [mem, setMem] = useState<MemStats | null>(null);

  useEffect(() => {
    let cancelled = false;
    
    const tick = async () => {
      const stats = await window.electron.system.memory();
      if (!cancelled) setMem(stats);
    };
    
    tick();
    const id = setInterval(tick, 2000);
    
    return () => { cancelled = true; clearInterval(id); };
  }, []);

  if (!mem) return null;

  const pct = Math.round((mem.used / mem.total) * 100);
  const fmtGB = (b: number) => (b / 2 ** 30).toFixed(1);

  return (
    <div className="flex items-center gap-2">
      <div className="w-20 h-1.5 bg-zinc-900 rounded-full overflow-hidden">
        <div 
          className="h-full bg-green-500 transition-all"
          style={{ width: `${pct}%` }}
        />
      </div>
      <span className="text-[11px]">
        {fmtGB(mem.used)} / {fmtGB(mem.total)} GB
      </span>
    </div>
  );
}

```

---

## Summary

- **Preferences** live in [`appStore.ts`](https://github.com/lightningpixel/modly/blob/main/appStore.ts), persisted via zustand-persist
- **Conditional rendering** happens in [`TopBar.tsx`](https://github.com/lightningpixel/modly/blob/main/TopBar.tsx) via boolean guard
- **OS queries** execute every 2 seconds through `window.electron.system.memory()`
- **Data flows** from Node.js `os` module → main process → preload → renderer
- **Visual output** includes percentage bar, GB readout, color coding, and tooltip

---

## Frequently Asked Questions

### How do I disable the RAM indicator in Modly?

Open Settings → Application, then toggle off **"RAM indicator"**. The preference persists across restarts through zustand-persist in [`appStore.ts`](https://github.com/lightningpixel/modly/blob/main/appStore.ts).

### Why does the indicator update every 2 seconds?

The `setInterval(tick, 2000)` in [`MemoryIndicator.tsx`](https://github.com/lightningpixel/modly/blob/main/MemoryIndicator.tsx) balances real-time responsiveness with minimal CPU overhead. Shorter intervals increase IPC traffic without meaningful usability gains.

### What Node.js APIs provide the memory data?

The main process uses `os.totalmem()` and `os.freemem()`, then calculates `used = total - free`. These are cross-platform APIs that work on Windows, macOS, and Linux.

### Can I change the color thresholds for memory usage?

The bar colors in [`MemoryIndicator.tsx`](https://github.com/lightningpixel/modly/blob/main/MemoryIndicator.tsx) are determined by Tailwind classes applied based on percentage ranges. Modify the `barColor` logic to adjust thresholds—though the source uses standard green/amber/red conventions.