Creating Meters

Build custom battery indicators using HTML, CSS, and JavaScript.

Quick Start

  1. Create a new template: In Multimeter, right-click the menu bar icon and select "New Meter Template..."
  2. Edit the files: A folder will open in Finder containing your template files. Edit them in your favorite code editor.
  3. See live changes: Multimeter automatically reloads your template when you save changes.
  4. Share your creation: Export your meter and share it with others!

File Structure

Each meter template is a folder containing:

my-meter/
├── manifest.json    # Meter metadata
├── index.html       # Main HTML file
├── styles.css       # Styles
└── meter.js         # JavaScript logic

manifest.json

The manifest file describes your meter:

{
  "name": "My Custom Meter",
  "description": "A brief description of your meter",
  "version": "1.0.0",
  "width": 60,
  "minWidth": 40,
  "maxWidth": 100,
  "author": "Your Name",
  "supportsLightMode": true,
  "supportsDarkMode": true
}

JavaScript API

Multimeter injects battery data into window.meterData:

window.meterData = {
  level: 0.67,           // 0.0 to 1.0
  isCharging: false,     // true when plugged in and charging
  isPluggedIn: true,     // true when connected to power
  timeRemaining: 167,    // minutes until empty (or null)
  timeToFullCharge: null,// minutes until full (or null)
  cycleCount: 245,       // battery cycle count
  health: 0.92,          // battery health (0.0 to 1.0)
  colorScheme: 'dark',   // 'light' or 'dark'
  percentage: 67,        // level as integer (0-100)
  formattedTime: '2:47'  // formatted time string
}

Listening for Updates

Battery data updates periodically. Listen for changes:

class Meter {
  constructor() {
    this.data = window.meterData || { level: 0.5 };

    // Listen for updates
    window.addEventListener('meterUpdate', (e) => {
      this.data = e.detail;
      this.render();
    });

    this.render();
    window.meterReady = true;
  }

  render() {
    // Update your UI here
    const percent = Math.round(this.data.level * 100);
    document.getElementById('level').textContent = percent + '%';
  }
}

new Meter();

Light & Dark Mode

Support both light and dark menu bars with CSS:

/* Dark mode (default) */
body {
  color: white;
}

/* Light mode via system preference */
@media (prefers-color-scheme: light) {
  body {
    color: black;
  }
}

/* Light mode via app toggle */
body.light-mode {
  color: black;
}

body.dark-mode {
  color: white;
}

Tips

  • Keep your meter height at 22px to match the menu bar
  • Use system fonts for consistency: -apple-system
  • Test with both light and dark menu bars
  • Use the "Simulate Draining & Charging" feature to test all states
  • Keep file sizes small for fast loading

Example: Simple Percentage

Here's a complete example of a simple percentage meter:

index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <div id="meter">
    <span id="level">--</span>%
  </div>
  <script src="meter.js"></script>
</body>
</html>

styles.css

body {
  margin: 0;
  font-family: -apple-system, sans-serif;
  font-size: 12px;
  color: white;
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 22px;
}

@media (prefers-color-scheme: light) {
  body { color: black; }
}

meter.js

class Meter {
  constructor() {
    this.data = window.meterData || { level: 0.5 };
    window.addEventListener('meterUpdate', (e) => {
      this.data = e.detail;
      this.render();
    });
    this.render();
    window.meterReady = true;
  }

  render() {
    document.getElementById('level').textContent =
      Math.round(this.data.level * 100);
  }
}

new Meter();

Ready to create?

Download Multimeter and start building your own meters today.

Get Multimeter