# Framebuffer Display API

A high-level Go package for easily creating text-based status displays on Linux framebuffers. Perfect for system monitors, embedded displays, IoT dashboards, and more.

## API Design Concepts

Below are four different API design approaches for creating framebuffer displays. Each example shows how you might implement a system status display.

### Concept 1: Builder Pattern

```go
package main

import (
    "time"
    fb "github.com/example/framebufferdisplay"
)

func main() {
    // Create and configure display with fluent interface
    display := fb.New().
        AutoDetect().                    // Find first available framebuffer
        WithFont("IBM Plex Mono", 14).   // Default font
        WithUpdateInterval(time.Second). // Auto-refresh rate
        Build()
    
    defer display.Close()
    
    // Define the layout
    display.Layout(func(canvas *fb.Canvas) {
        // Header section
        canvas.Section("header", fb.TopCenter).
            Font("IBM Plex Mono", 24).
            Color(fb.White).
            Text("System Status")
        
        // System info section
        canvas.Section("info", fb.TopLeft).
            Margin(20).
            Rows(
                fb.Row().Label("Hostname:").Value(getHostname()),
                fb.Row().Label("Uptime:").Value(getUptime()),
                fb.Row().Label("Load:").Value(getLoad()).Color(fb.Red),
            )
        
        // CPU meters
        canvas.Section("cpu", fb.CenterLeft).
            Title("CPU Usage").
            Meters(getCPUMeters()...)
        
        // Memory bar
        canvas.Section("memory", fb.BottomLeft).
            Title("Memory").
            ProgressBar(getMemoryPercent(), fb.Green)
    })
    
    // Start the display loop
    display.Run()
}
```

### Concept 2: Declarative/React-like

```go
package main

import (
    fb "github.com/example/framebufferdisplay"
)

type SystemStatus struct {
    fb.Component
    hostname string
    uptime   time.Duration
}

func (s *SystemStatus) Render() fb.Element {
    return fb.Screen(
        fb.Header(
            fb.Text("System Status").
                Font("IBM Plex Mono", 48).
                Color(fb.RGB(100, 200, 255)),
        ),
        
        fb.Grid(fb.GridOptions{Columns: 2, Gap: 20},
            // Left column
            fb.Column(
                fb.Card(
                    fb.Title("System Info"),
                    fb.List(
                        fb.ListItem("Hostname", s.hostname),
                        fb.ListItem("Uptime", formatDuration(s.uptime)),
                        fb.ListItem("OS", getOS()),
                    ),
                ),
                fb.Card(
                    fb.Title("Network"),
                    fb.List(getNetworkInfo()...),
                ),
            ),
            
            // Right column
            fb.Column(
                fb.Card(
                    fb.Title("CPU Usage"),
                    fb.BarChart(getCPUData(), fb.ChartOptions{
                        Height: 200,
                        Color:  fb.Gradient(fb.Green, fb.Red),
                    }),
                ),
                fb.Card(
                    fb.Title("Memory"),
                    fb.CircularProgress(getMemoryPercent(), fb.Blue),
                    fb.Text(getMemoryDetails()).Size(12),
                ),
            ),
        ),
    )
}

func main() {
    fb.Run(&SystemStatus{})
}
```

### Concept 3: Immediate Mode

```go
package main

import (
    fb "github.com/example/framebufferdisplay"
)

func main() {
    // Auto-detect and initialize
    ctx := fb.Init()
    defer ctx.Close()
    
    // Main render loop
    ctx.Loop(func(d *fb.Draw) {
        // Clear with background
        d.Clear(fb.Black)
        
        // Draw header
        d.SetFont("IBM Plex Mono Bold", 36)
        d.SetColor(fb.White)
        d.TextCenter(d.Width/2, 50, "System Monitor")
        
        // System info box
        d.SetFont("IBM Plex Mono", 14)
        d.Box(20, 100, 400, 200, fb.Gray)
        d.SetColor(fb.Green)
        d.Text(30, 120, "Hostname: %s", getHostname())
        d.Text(30, 140, "Uptime: %s", getUptime())
        d.Text(30, 160, "Load: %.2f %.2f %.2f", getLoad())
        
        // CPU visualization
        cpus := getCPUPercents()
        for i, cpu := range cpus {
            y := 320 + i*30
            d.Text(30, y, "CPU%d", i)
            d.ProgressBar(80, y-10, 300, 20, cpu, fb.Heat(cpu))
        }
        
        // Memory meter
        mem := getMemoryPercent()
        d.SetFont("IBM Plex Mono", 18)
        d.Text(30, 500, "Memory: %.1f%%", mem)
        d.Gauge(30, 520, 350, 40, mem, fb.Blue)
        
        // Update display
        d.Present()
    })
}
```

### Concept 4: Template/Widget-based

```go
package main

import (
    fb "github.com/example/framebufferdisplay"
)

func main() {
    // Create display with auto-detection
    display := fb.NewDisplay()
    
    // Create a dashboard with predefined widgets
    dashboard := fb.Dashboard{
        Title: "System Status",
        Theme: fb.Themes.Dark,
        
        Layout: fb.GridLayout(3, 3), // 3x3 grid
        
        Widgets: []fb.Widget{
            // Row 1
            fb.BigNumber{
                GridPos: fb.Pos(0, 0),
                Label:   "CPU Temp",
                Value:   getCPUTemp,
                Unit:    "°C",
                Color:   fb.TempColor, // Auto-colors based on value
            },
            fb.LineGraph{
                GridPos:  fb.Pos(1, 0).Span(2, 1), // Spans 2 columns
                Title:    "CPU History",
                Duration: 5 * time.Minute,
                Source:   streamCPUData,
            },
            
            // Row 2
            fb.InfoTable{
                GridPos: fb.Pos(0, 1),
                Rows: []fb.TableRow{
                    {"Host", getHostname},
                    {"Kernel", getKernel},
                    {"Uptime", getUptime},
                },
            },
            fb.MultiMeter{
                GridPos: fb.Pos(1, 1),
                Title:   "CPU Cores",
                Meters:  getCPUCoreMeters,
                Compact: true,
            },
            fb.PieChart{
                GridPos: fb.Pos(2, 1),
                Title:   "Disk Usage",
                Data:    getDiskUsage,
            },
            
            // Row 3
            fb.MemoryWidget{
                GridPos:     fb.Pos(0, 2).Span(2, 1),
                ShowDetails: true,
            },
            fb.NetworkTraffic{
                GridPos:   fb.Pos(2, 2),
                Interface: "eth0",
            },
        },
        
        // Optional: Add alerts
        Alerts: []fb.Alert{
            fb.Alert{
                Condition: func() bool { return getCPUTemp() > 80 },
                Message:   "High CPU Temperature!",
                Color:     fb.Red,
            },
        },
    }
    
    // Run the dashboard
    display.RunDashboard(dashboard)
}
```

## Key Features Across All Concepts

- **Auto-detection**: Automatically finds and configures the first available framebuffer
- **Resolution independence**: Layouts adapt to the detected resolution
- **Font management**: Easy font loading and sizing
- **Color utilities**: Named colors, RGB, gradients, and conditional coloring
- **Common widgets**: Progress bars, meters, graphs, tables, etc.
- **Refresh control**: Configurable update intervals or manual control
- **Error handling**: Graceful fallbacks for missing fonts, permissions, etc.

## Design Considerations

Each approach offers different benefits:

1. **Builder Pattern**: Familiar to Go developers, good for static layouts
2. **Declarative**: Clean separation of data and presentation, easy to test
3. **Immediate Mode**: Simple and direct, good for dynamic content
4. **Widget-based**: Highest level abstraction, fastest to build common dashboards

The final API could combine elements from multiple approaches, such as using the widget system from Concept 4 with the immediate mode drawing primitives from Concept 3 for custom widgets.