This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
FlipClock is a minimal desktop flip clock widget built with Go and the Fyne v2 GUI toolkit. It renders a dark-mode window with large hour/minute flip-card digits (24-hour format), a seconds label, flip animation, responsive layout, fullscreen mode, and system tray integration.
| Component | Technology | Version | Notes |
|---|---|---|---|
| Language | Go | 1.22+ | |
| GUI Framework | Fyne | v2.5.1 | |
| Font | Bebas Neue Regular | embedded via go:embed |
|
| System Tray | fyne.io/systray | v1.11.0 (indirect) | |
| OpenGL | go-gl/gl + go-gl/glfw | for hardware-accelerated rendering | |
| Multi-Monitor | go-gl/glfw | v3.3.8 | Monitor detection for screensaver mode |
# Install dependencies (requires Go 1.22+)
go mod tidy
# Run directly
go run .
# Build binary
go build -o flipclock .
# Build stripped binary (smaller, no debug symbols)
go build -ldflags "-s -w" -o flipclock .
# Windows (hide console window)
go build -ldflags "-s -w -H windowsgui" -o flipclock.exe .System prerequisites (Fyne needs a C compiler and OpenGL):
- Linux:
sudo apt install gcc libgl1-mesa-dev xorg-dev - macOS:
xcode-select --install - Windows: TDM-GCC or MSYS2
# Run all tests
go test -v ./...
# Run specific test
go test -v -run TestDetectMonitors
# Check test coverage
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.outCurrent test coverage: 21 tests covering monitor detection, window creation, synchronization, and CLI parsing.
flipclock/
├── main.go # Application code (widgets, layout, tray, main loop)
├── monitors.go # Multi-monitor detection using GLFW
├── font.go # Embedded font resource (BebasNeue via go:embed)
├── bundled.go # Embedded icon resources
├── monitors_test.go # Monitor detection tests
├── window_test.go # Multi-window screensaver tests
├── sync_test.go # Clock synchronization tests
├── screensaver_test.go # CLI argument parsing tests
├── fonts/
│ └── BebasNeue-Regular.ttf # Custom display font (61KB, OFL license)
├── docs/ # SDLC documentation (PRD, ADR, User Stories, Tasks)
├── go.mod # Module definition (flipclock)
├── go.sum # Dependency checksums
├── CLAUDE.md # This file
└── README.md # User-facing documentation
The codebase follows a modular structure with clear separation of concerns.
font.go
- Embeds BebasNeue-Regular.ttf font into binary using
go:embed - Exports
fontBoldasfyne.Resourcefor custom theme
monitors.go (NEW - multi-monitor support)
MonitorInfostruct: holds Name, X, Y, Width, Height for each displaydetectMonitors(): queries GLFW for connected monitors, returns slice- Graceful degradation: returns empty slice on GLFW failure (fallback to single-monitor)
- Logs monitor detection for debugging
main.go sections
- Colors - Dark mode palette (
#000,#1A1A1A,#FFF,#555) - flipTheme - Custom Fyne theme with BebasNeue font
- FlipCard widget - Custom widget with two-phase flip animation (300ms ease-in-out)
- clockLayout - Responsive layout maintaining 5:6 card aspect ratio
- Clock - State struct with
Update()method andpad2helper - Screensaver Mode - Multi-monitor window creation:
ScreensaverWindowstruct: pairs Window with ClocksetupScreensaverWindows(): creates one fullscreen window per monitorstartSharedTicker(): synchronizes clock updates across all windowssetupUnifiedExit(): registers input handlers on all windows
- main() - Two modes:
- Screensaver: Multi-monitor detection → window creation → unified ticker
- Normal: Single window with tray integration and shortcuts
Custom widget rendering
- FlipCard implements
CreateRenderer()returningflipCardRenderer - Manual canvas object positioning in
Layout()- standard Fyne pattern
Two-phase flip animation
fyne.NewAnimation()with 300ms duration, ease-in-out curve- Phase 1 (0-50%): top flap shrinks from top toward hinge
- Phase 2 (50-100%): bottom flap shrinks from bottom toward hinge
Multi-monitor synchronization (NEW)
- GLFW monitor detection via
glfw.GetMonitors() - One Fyne window created per detected monitor
- Shared
time.Tickerupdates all Clock instances simultaneously - Unified exit: any input closes all windows via channel signal
Responsive layout
clockLayoutcalculates card dimensions from height (78%) and width constraints- Minimum dimension prevents overflow
- Seconds label scales proportionally (8% of card height, min 14px)
System tray
- Close-intercept hides window instead of quitting (normal mode only)
- Linux GNOME requires AppIndicator extension
Embedded resources
go:embedfor BebasNeue TTF font (zero runtime I/O)fyne bundlefor app icon resources
| Key | Action |
|---|---|
Esc |
Exit fullscreen, or hide to tray if not fullscreen |
Q |
Hide to tray |
F / F11 |
Toggle fullscreen |
| Item | Action |
|---|---|
| Show | Show and focus window |
| Fullscreen | Toggle fullscreen |
| Quit | Quit application |
- Flip animation (two-phase, 300ms ease-in-out)
- Responsive layout (proportional card sizing)
- Fullscreen toggle (F/F11 keys + tray menu)
- Embedded custom font (BebasNeue)
- 12h/24h toggle
- Always-on-top
- Light theme
- Persistent settings (JSON)
- Custom tray icon
go install fyne.io/fyne/v2/cmd/fyne@latest
fyne bundle icon.png > bundled.go
# Then uncomment in main.go: desk.SetSystemTrayIcon(resourceIconPng)