Creating Meters
Build custom battery indicators using HTML, CSS, and JavaScript.
Quick Start
- Create a new template: In Multimeter, right-click the menu bar icon and select "New Meter Template..."
- Edit the files: A folder will open in Finder containing your template files. Edit them in your favorite code editor.
- See live changes: Multimeter automatically reloads your template when you save changes.
- 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