This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
If the user is ever confused or ignorant about anything, a good friend would inform them of it. Be a good friend.
The source code of the libraries in package cache is a useful source of information.
This is a user who's very specific in what they want. Usually any code they will have written themselves will be extremely intentional. Don't do things that the user doesn't want. Instead, suggest them.
Don't leave excessive comments, if the code is self-explanatory, no comment.
Mako's Timer is an ergonomic Flutter timer app that optimizes the user experience through visual compactness, color-coding, and gesture-based interactions. The app uses a custom reactive persistence system called Mobj that combines Signals for reactivity with Drift (SQLite) for persistence.
# Initial setup
flutter create .
flutter pub get
flutter pub run build_runner build # Generate database.g.dart
# Run the app
flutter run
# Rebuild generated files (after schema changes)
flutter pub run build_runner build --delete-conflicting-outputs
# Analyze code
flutter analyzeThe Mobj system (lib/mobj.dart) is a custom reactive key-value persistence layer that:
- Uses Signals (
signalspackage) for reactivity instead of streams - Automatically persists to SQLite via Drift whenever values change
- Provides type-safe serialization via
TypeHelp<T>parsers - Manages loading/caching with
MobjRegistry - Supports cross-isolate sharing when configured with
DriftNativeOptions(shareAcrossIsolates: true)
Root Mobjs: Pre-defined UUIDs in lib/main.dart for app-wide state:
timerListID: Pinned timers listtransientTimerListID: Temporary timers listnextHueID: Next color hue for timer creationdbVersionID: Database schema version
Usage Pattern:
// Initialize root mobjs in initializeDatabase()
await Mobj.getOrCreate(id, type: SomeType(), initial: () => defaultValue);
// Access in widgets
final mobj = Mobj.getAlreadyLoaded<T>(id, type);
mobj.value = newValue; // Automatically persists- Schema: Defined in lib/database.dart using Drift
- Generated code: lib/database.g.dart (don't edit manually)
- Storage: Single
KVstable for Mobj persistence (id, value pairs as JSON) - Connection: Uses
drift_flutter'sdriftDatabase()with background isolate support
Timer state is stored as TimerData objects (defined in lib/type_help.dart) containing:
digits: List of integers representing timer durationstartTime: When timer was started/pausedrunning: Boolean statushue: Color hue (0-360) for visual identification
- TimerScreen: Main widget managing timer list and input pad
- Timer: Individual timer widget using Mobj for reactive state
- Input pad: Numeral entry with swipe-up gesture to start timer
- Color system: HSLuv-based pastel colors for visual distinction
Currently in development. Reference implementation in openhiit/ symlink shows:
- Uses
flutter_background_servicewith foreground service typemediaPlayback - Requires Android manifest service declaration with
android:foregroundServiceType="mediaPlayback" - Uses
AudioPlayer.global.setAudioContext()for background audio mixing - Note:
audioplayershas known issues on Linux (issue #1749)
- lib/main.dart: App entry point, timer UI, and business logic
- lib/mobj.dart: Reactive persistence system
- lib/database.dart: Drift schema definition
- lib/type_help.dart: Type serialization helpers for Mobj
- lib/boring.dart: Utility code (audio, math, helpers)
- lib/background_service_stuff.dart: Foreground task handlers
- Start typing implicitly creates a new timer
- Swipe up on final numeral to start the timer (saves a tap)
- Visual feedback via
numeralDragIndicatoranimation
- User enters digits → creates temporary timer in
transientTimerListMobj - Timer started → moves to persistent
timerListMobj - Color assigned via
nextRandomHue()using golden ratio spacing for visual distinction
- Widget-level:
providerpackage for dependency injection (JukeBox, Thumbspan) - App-level: Mobj system for persistent reactive state
- UI reactivity: Signals via
signals_flutterpackage
- Background audio playback needs foreground service implementation
- "Bark once" option not yet implemented
- Chained timers feature planned but not implemented
- Looping timers planned but not implemented
- Audio assets not committed to repo (credit: Kenney.nl)