8/17/2025
After my ADHD diagnosis, the Pomodoro Technique became essential for managing my focus. As someone who spends most of my day in Obsidian, I wanted a timer that lived seamlessly within my note-taking environment without cluttering my workspace.
That’s how PomoBar was born: a minimalist Pomodoro timer that sits quietly in Obsidian’s status bar, ready when I need it but invisible when I don’t.
PomoBar was one of those projects I built during my year of silence, focused on solving a real problem I faced daily, but never taking the time to document the process. Looking back, that was a mistake. The development journey taught me lessons about constraints, user experience, and the value of building tools you actually use.
Before diving into Obsidian plugin development, I built a standalone HTML version in CodePen to test the concept. Working with familiar HTML, CSS, and JavaScript let me focus on the user experience without learning new APIs. The prototype had a full visual interface with buttons and progress rings – essentially a traditional web app.
But when I moved to create the Obsidian plugin, everything changed. This was my first plugin and my first real TypeScript project. I was suddenly wrestling with type definitions, Obsidian’s API patterns, and figuring out how to cram a full timer interface into a tiny status bar element.
Before building PomoBar, I tried several Pomodoro apps and browser extensions. They all shared similar problems:
I needed something that followed the Unix philosophy: do one thing and do it well. A timer that would stay out of my way but be instantly accessible when needed.
What started as a single-file experiment evolved into a properly structured project. I learned the hard way that even simple plugins benefit from clean architecture.
The current structure separates concerns clearly:
main.ts
: Plugin lifecycle and Obsidian integrationtimer.ts
: All timer logic and state managementSettingsTab.ts
: Configuration interfacetypes.ts
: TypeScript interfaces and type definitionsconstants.ts
: Application constants and enumsThis modular approach made the codebase easier to test, debug, and extend. When I needed to add features like optional status bar icons or improved memory management, I could modify individual components without touching the core timer logic.
The core design principle for PomoBar remained radical simplicity, but with thoughtful flexibility:
MM:SS
The interface stays minimal, but users can customize duration settings and choose whether to show the timer icon. Smart defaults (25/5/15 minutes) work for most people, but the plugin adapts to different workflows.
Building something simple sounds easy until you actually try it. What seemed like “just put a timer in the status bar” quickly revealed layers of complexity I hadn’t anticipated.
The timer tracks multiple pieces of state: current mode, remaining time, work interval count, and running status. Getting this right required careful attention to cleanup:
cleanup() {
// Clean up any remaining intervals
this.registeredIntervals.forEach(intervalId => {
window.clearInterval(intervalId);
});
this.registeredIntervals.clear();
}
JavaScript’s setInterval
can create memory leaks if not handled correctly, especially in a plugin environment where code gets reloaded frequently during development. Obsidian’s registerInterval
method helps, but proper manual cleanup ensures reliability.
Early feedback taught me important lessons about user expectations. A GitHub issue pointed out that users wanted the plugin to automatically cycle through the traditional Pomodoro sequence: work → short break → work → short break → work → long break. The user noted they were using “25/5 cycles with the occasional 15 extended break” and wanted the timer to default to 5-minute breaks instead of requiring manual selection each time.
This feedback was really helpful. It highlighted a core workflow need I hadn’t fully considered. Instead of adding buttons or dropdowns, I implemented automatic cycling while keeping the same three-click interaction model.
Moving from vanilla JavaScript to TypeScript added complexity I hadn’t expected, but the benefits became clear quickly:
interface PomodoroSettings {
workTime: number;
shortBreakTime: number;
longBreakTime: number;
intervalsBeforeLongBreak: number;
showIcon: boolean;
}
TypeScript caught several bugs during development that would have been runtime errors in JavaScript. The type safety made refactoring safer and the code more self-documenting.
Building PomoBar taught me the value of proper development tooling, even for small projects.
I experimented with different build systems before settling on esbuild. While I briefly tried Vite for its development features, esbuild proved more stable and performant for an Obsidian plugin. The build process handles TypeScript compilation, bundling, and development hot-reloading.
ESLint and proper TypeScript configuration catch issues before they reach users. The development experience improved dramatically once I had reliable linting and type checking in place.
I added a Jest test suite to verify timer logic, settings validation, and plugin lifecycle management. Testing Obsidian plugins requires mocking the API, but the effort pays off in confidence and easier refactoring.
The settings validation alone prevented several user-facing bugs:
private validateAndUpdateSetting(
value: string,
settingProperty: 'workTime' | 'shortBreakTime' | 'longBreakTime',
resetAction: 'resetTimer' | 'resetPomodoroSession'
): boolean {
const numValue = parseInt(value.trim());
if (!isNaN(numValue) && numValue > 0 && Number.isInteger(Number(value.trim()))) {
this.plugin.settings[settingProperty] = numValue;
return true;
}
return false;
}
One lesson from my year of building in silence: document as you build, not after. PomoBar now includes:
Writing documentation forces you to think clearly about user experience and API design. It also makes the project more welcoming to contributors and users.
PomoBar today is a robust, well-tested plugin that hundreds of users use daily. What started as a simple timer evolved into a thoughtful tool that balances simplicity with reliability.
The biggest lessons weren’t about TypeScript syntax or Obsidian APIs. They were about building software people actually use:
If you’re interested in building Obsidian plugins, here’s what I wish I’d known starting out:
@ts-ignore
commentsThe complete source code for PomoBar is available on GitHub, along with comprehensive documentation. If you decide to build your own plugin, I’d love to hear what problems you’re solving. Sometimes the best ideas come from scratching your own itch.
Building PomoBar taught me that effective tools don’t need complex interfaces. Sometimes the software you forget you’re using is exactly what you need.
This project also taught me something about the value of writing alongside building. I shipped PomoBar months ago, but only now am I capturing the lessons learned and design decisions made. The technical details are still fresh, but some of the emotional journey – the frustration with existing tools, the satisfaction of solving my own problem – has already faded.
Writing about projects after the fact is harder than writing during development, but it’s still valuable. The technical lessons remain clear even if some of the emotional journey has faded. This is my reminder to document the process, not just the results.