zone

package
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 27, 2026 License: MIT Imports: 29 Imported by: 0

Documentation

Overview

Package zone implements the zone-based layout system for the display.

Package zone manages per-zone plugin configuration. ConfigManager delegates storage to the shared store.DB, reading and writing zones.config_json as the single source of truth for per-zone plugin config (zone_plugin_config was removed in schema migration v5).

Package zone manages display zones, plugin sampling, and page transitions.

Index

Constants

View Source
const (
	DisplayWidth  = 640
	DisplayHeight = 48
)
View Source
const (
	// MaxZonesPerPage is the maximum number of zones allowed on a single page.
	MaxZonesPerPage = 6
	// DisplayWidthPx is the total pixel width of the Nexus display strip.
	DisplayWidthPx = 640
	// MinZoneWidthPx is the minimum pixel width of any zone.
	MinZoneWidthPx = 80
)
View Source
const (
	DetailCloseX = DisplayWidth - 10
	DetailCloseY = 10
)

DetailCloseX/Y are the hardware pixel centre of the close (✕) glyph.

Variables

View Source
var (
	SeverityColorWarn = design.Warn
	SeverityColorCrit = design.Crit
)

Severity display colors — sourced from design tokens; never configurable.

Functions

func ExportConfigToYAML

func ExportConfigToYAML(cfg *Config) ([]byte, error)

ExportConfigToYAML serialises cfg to YAML bytes using the struct's yaml tags. The result can be written directly to a .yaml file or returned as an HTTP download.

func NormalizePluginID

func NormalizePluginID(id string) string

normalizePluginID converts legacy path-form exec IDs to the canonical short form.

exec:./plugins/cpu-temp/nexus-cpu-temp  →  exec:nexus-cpu-temp
exec:nexus-cpu-temp                     →  exec:nexus-cpu-temp  (unchanged)
builtin:clock                           →  builtin:clock        (unchanged)

func RenderDetailFrame

func RenderDetailFrame(_ *slog.Logger, payload plugin.DetailPayload, theme Theme) *image.RGBA

RenderDetailFrame blits the pre-rendered pixel buffer from payload.RawFrame onto a 640×48 RGBA image. If RawFrame is absent or the wrong size, a plain error frame is returned so the display always shows something.

func RenderPlaceholder

func RenderPlaceholder(width, height int, text string, bgColor, fgColor color.RGBA) *image.RGBA

RenderPlaceholder renders a placeholder zone (for loading or errors).

func SaveConfigToDB

func SaveConfigToDB(db LayoutImporter, cfg *Config) error

SaveConfigToDB persists cfg to the database as a full atomic replace using ImportLayout. Page IDs are assigned sequentially from 1; callers should reload from DB after commit so the manager has the canonical IDs.

Types

type Alignment

type Alignment string

Alignment options for zone content

const (
	AlignLeft   Alignment = "left"
	AlignCenter Alignment = "center"
	AlignRight  Alignment = "right"
)

type CatalogEntry

type CatalogEntry struct {
	ID         string            `json:"id"`   // e.g. "builtin:clock" or "exec:nexus-cpu-temp"
	Kind       string            `json:"kind"` // "builtin" or "exec"
	Descriptor plugin.Descriptor `json:"descriptor"`
}

CatalogEntry is one entry in the plugin catalog returned by GetCatalog.

type Compositor

type Compositor struct {
	// contains filtered or unexported fields
}

Compositor composites multiple zone renderers into a single display image.

func NewCompositor

func NewCompositor(logger *slog.Logger, theme Theme, page *Page) *Compositor

NewCompositor creates a new compositor for a page.

func (*Compositor) ClearBackground

func (c *Compositor) ClearBackground()

ClearBackground removes the background layer (reverts to solid bg colour).

func (*Compositor) Composite

func (c *Compositor) Composite(dst *image.RGBA, zoneImages map[string]*image.RGBA, theme Theme) (*image.RGBA, error)

Composite renders all zones and composites them into dst. If dst is nil a new 640×48 RGBA image is allocated. Pass a pre-allocated buffer to avoid allocation on the hot path. theme is passed in so live UpdateTheme calls are reflected immediately.

func (*Compositor) SetBackground

func (c *Compositor) SetBackground(img *image.RGBA)

SetBackground sets a static image as the background layer.

func (*Compositor) SetBackgroundGIF

func (c *Compositor) SetBackgroundGIF(g *gif.GIF)

SetBackgroundGIF sets an animated GIF as the background layer. The GIF is decoded into paletted frames and played back at its own frame rate.

type Config

type Config struct {
	Name    string    `yaml:"name" json:"name"`                                 // Layout name
	Version string    `yaml:"version" json:"version"`                           // Layout version
	Theme   Theme     `yaml:"theme" json:"theme"`                               // Global theme
	Pages   []Page    `yaml:"pages" json:"pages"`                               // Pages (swipeable layouts)
	Nav     NavConfig `yaml:"navigation,omitempty" json:"navigation,omitempty"` // Navigation settings
}

Config represents the complete layout configuration

func CopyConfig

func CopyConfig(cfg *Config) *Config

CopyConfig returns a deep copy of cfg without JSON round-tripping. Only the two reference types in ZoneConfig need explicit copying:

  • PluginConfig map[string]any — shallow map copy (values are JSON scalars)
  • ThemeOverride *Theme — copy the pointed-to struct

func LoadConfig

func LoadConfig(path string) (*Config, error)

LoadConfig loads a zone configuration from YAML.

func LoadConfigFromDB

func LoadConfigFromDB(db *store.DB) (*Config, error)

LoadConfigFromDB reconstructs a Config from the layout stored in the database. Pages are returned in ord order; zones within each page are returned in ord order.

The global theme is always DefaultTheme() because theme is not persisted per-layout in the DB — per-zone ThemeOverrides are stored in theme_json and are applied to individual zones.

Returns an error (and the caller should fall back to YAML) when the DB contains no pages.

func (*Config) Validate

func (c *Config) Validate() error

Validate checks if the configuration is valid

type ConfigManager

type ConfigManager struct {
	// contains filtered or unexported fields
}

ConfigManager manages zone-specific plugin configurations. It is a thin adapter between the zone package and the store layer.

func NewConfigManager

func NewConfigManager(s *store.DB, logger *slog.Logger) *ConfigManager

NewConfigManager creates a ConfigManager backed by the given store.

func (*ConfigManager) BroadcastConfigChange

func (m *ConfigManager) BroadcastConfigChange(_ map[string]any)

BroadcastConfigChange is a no-op: global config changes flow through settings.Manager and are delivered to plugins via the sampler.

func (*ConfigManager) BroadcastZoneConfigChange

func (m *ConfigManager) BroadcastZoneConfigChange(zoneID string, cfg map[string]any) error

BroadcastZoneConfigChange persists the config for a single zone.

func (*ConfigManager) DeleteZoneOverride

func (m *ConfigManager) DeleteZoneOverride(zoneID string) error

DeleteZoneOverride clears the plugin config for a zone (resets to {}).

func (*ConfigManager) Get

func (m *ConfigManager) Get(zoneID, _ string) map[string]any

Get returns the plugin config for a zone from zones.config_json. Returns nil when the zone has no stored config or does not exist.

func (*ConfigManager) GetZoneOverride

func (m *ConfigManager) GetZoneOverride(zoneID string) map[string]any

GetZoneOverride returns the stored config for zoneID.

func (*ConfigManager) SetZoneOverride

func (m *ConfigManager) SetZoneOverride(zoneID string, cfg map[string]any) error

SetZoneOverride stores the plugin config for a specific zone.

type LayoutImporter

type LayoutImporter interface {
	ImportLayout(pages []store.StoredPage, zonesByPage map[int64][]store.StoredZone) error
}

LayoutImporter can atomically replace the full layout in the database.

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager manages zones, their renderers, and lifecycle.

Implementation is split across four files for readability:

manager.go       — struct, NewManager, lifecycle (Start/Stop/Reload)
manager_page.go  — page/config/navigation/cache methods
manager_render.go — payload/theme/compositing/frame methods
manager_swipe.go  — live swipe and transition methods

func NewManager

func NewManager(ctx context.Context, logger *slog.Logger, db *store.DB, fallbackYAMLPath string) (*Manager, error)

NewManager creates a new zone manager.

When db is non-nil the manager loads the layout from SQLite first; if the DB contains no pages it falls back to fallbackYAMLPath and seeds the DB so subsequent starts use the DB path. Pass nil for db (and any string for fallbackYAMLPath) to operate in YAML-only mode (used by the cmd/ binaries).

func (*Manager) CancelLiveSwipe

func (m *Manager) CancelLiveSwipe() error

CancelLiveSwipe cancels an in-progress live swipe and springs back to the current page.

func (*Manager) ClearDetail

func (m *Manager) ClearDetail()

ClearDetail dismisses the detail overlay with a slide-down transition.

func (*Manager) CycleZonePlugin

func (m *Manager) CycleZonePlugin(zoneID string) error

CycleZonePlugin advances the zone to its next plugin choice and notifies the sampler via the onZoneCycle callback.

func (*Manager) EffectiveTapAction

func (m *Manager) EffectiveTapAction(z ZoneConfig) TapAction

effectiveTapAction returns the tap action for a zone. If the zone's configured on_tap is empty, the plugin's Tapper implementation is the authority: any plugin implementing Tapper gets TapActionDetail automatically. This means on_tap never needs to be set in the layout for detail-capable plugins — the interface is the declaration.

func (*Manager) FinalizeLiveSwipe

func (m *Manager) FinalizeLiveSwipe(progress float32, velocity float32, isLeft bool) error

FinalizeLiveSwipe commits an in-progress live swipe and smoothly completes the transition using spring physics seeded with the finger's release velocity.

func (*Manager) GetConfig

func (m *Manager) GetConfig() *Config

GetConfig returns the current configuration pointer. The pointer is stable for the duration of the current config — callers must not mutate it.

func (*Manager) GetCurrentPage

func (m *Manager) GetCurrentPage() int

GetCurrentPage returns the current page index.

func (*Manager) GetDetailFrame

func (m *Manager) GetDetailFrame() *image.RGBA

IsShowingDetail reports whether the detail overlay is active or animating IN. Returns false during the slide-down dismiss transition so taps pass through. GetDetailFrame returns the most recently rendered detail frame, or nil if none. The caller receives a copy safe to read without holding any lock.

func (*Manager) GetLastFrame

func (m *Manager) GetLastFrame() *image.RGBA

GetLastFrame returns a copy of the most recently rendered frame, or nil.

func (*Manager) GetPageInfos

func (m *Manager) GetPageInfos() []PageInfo

GetPageInfos returns lightweight page + zone descriptors for the Flutter preview UI.

func (*Manager) GetZones

func (m *Manager) GetZones() map[string]*Zone

GetZones returns all zones for the current page.

func (*Manager) HandleDetailTap added in v0.3.0

func (m *Manager) HandleDetailTap(x, y int)

HandleDetailTap routes a tap within the active detail overlay to the plugin. If the plugin implements DetailTapper, it calls OnDetailTap and dismisses only if the plugin returns false. If the plugin does not implement DetailTapper, the detail is dismissed unconditionally.

func (*Manager) HandleZoneTap

func (m *Manager) HandleZoneTap(zoneID string) error

HandleZoneTap looks up the plugin for zoneID, calls OnTap if it implements plugin.Tapper, and shows the result as a detail overlay. Safe to call from any goroutine.

Detail payloads contain pre-rendered pixel frames (RawFrame) with ephemeral content baked in (playback position, live temperatures, etc.). They must always be fetched fresh — caching them produces stale visuals on re-tap. Plugins that need to avoid repeated expensive work (network calls, geocoding) maintain their own in-process cache and return quickly from OnTap.

func (*Manager) HandleZoneTapAtX

func (m *Manager) HandleZoneTapAtX(x int) error

HandleZoneTapAtX resolves the zone at hardware X coordinate x (0–639) on the current page and executes its OnTap action — identical to what the hardware touch handler does. Used by the debug tap API so the Flutter preview can drive the same code path with mouse clicks.

func (*Manager) IsShowingDetail

func (m *Manager) IsShowingDetail() bool

func (*Manager) IsTransitioning

func (m *Manager) IsTransitioning() bool

IsTransitioning reports whether a page transition is currently in progress. Used by the render loop to decide whether to broadcast at full rate (30fps).

func (*Manager) NextPage

func (m *Manager) NextPage() error

NextPage switches to the next page with a slide-left transition.

func (*Manager) NumPages

func (m *Manager) NumPages() int

NumPages returns the total number of pages.

func (*Manager) PrevPage

func (m *Manager) PrevPage() error

PrevPage switches to the previous page with a slide-right transition.

func (*Manager) Reload

func (m *Manager) Reload() error

Reload reloads the configuration. When a DB is available it reloads from the database; otherwise it falls back to the YAML file on disk.

func (*Manager) ReloadFromConfig

func (m *Manager) ReloadFromConfig(config *Config) error

ReloadFromConfig replaces the running layout with the given config and re-initialises the current page. Used by the layout editor so changes take effect immediately without restarting the application.

func (*Manager) RenderFrame

func (m *Manager) RenderFrame() (*image.RGBA, error)

RenderFrame renders the current frame (transition or live zones composited). When no payload, theme, or page has changed since the last render, it returns the cached lastFrame directly — skipping allocation and the full compositor pipeline. This keeps idle CPU and GC pressure near zero at 30fps.

func (*Manager) SetBackground

func (m *Manager) SetBackground(path string) error

SetBackground loads an image or GIF from disk and sets it as the background layer on the current compositor. Passing an empty path clears the background. Supported formats: PNG, JPEG, GIF (animated GIFs play at their own frame rate).

func (*Manager) SetDetailStateCallback

func (m *Manager) SetDetailStateCallback(fn func(active bool))

SetDetailStateCallback registers a function called whenever the detail overlay is shown or hidden. Safe to call before Start.

func (*Manager) SetOnPageChange

func (m *Manager) SetOnPageChange(callback func(pageIndex int) error)

SetOnPageChange sets a callback to be called when the page changes.

func (*Manager) SetOnZoneCycle

func (m *Manager) SetOnZoneCycle(callback func(zoneConfig ZoneConfig) error)

SetOnZoneCycle sets a callback invoked when a tap action cycles a zone's plugin.

func (*Manager) SetPluginLookup

func (m *Manager) SetPluginLookup(pl PluginLookup)

SetPluginLookup wires in the sampler so HandleZoneTap can resolve plugins.

func (*Manager) ShowDetail

func (m *Manager) ShowDetail(payload plugin.DetailPayload)

ShowDetail renders payload into a detail overlay and starts the slide-up transition.

func (*Manager) Start

func (m *Manager) Start() error

Start starts the zone manager.

func (*Manager) StartDetailRefresh added in v0.3.0

func (m *Manager) StartDetailRefresh(zoneID string, tapper plugin.Tapper, interval time.Duration)

StartDetailRefresh begins polling tapper every interval while the detail overlay is active, updating the frame in place. Call immediately after ShowDetail. A previous refresh goroutine (if any) is cancelled first.

func (*Manager) StartTapRipple added in v0.2.0

func (m *Manager) StartTapRipple(tapX int)

StartTapRipple begins a ripple animation centred on the tapped x coordinate. Safe to call from any goroutine.

func (*Manager) Stop

func (m *Manager) Stop() error

Stop stops the zone manager.

func (*Manager) SwitchPage

func (m *Manager) SwitchPage(pageIndex int) error

SwitchPage switches to a different page with a slide-left transition.

func (*Manager) SwitchPageWithTransition

func (m *Manager) SwitchPageWithTransition(pageIndex int, transitionType TransitionType, direction int) error

SwitchPageWithTransition switches to a different page with a specified transition.

func (*Manager) UpdateLiveSwipe

func (m *Manager) UpdateLiveSwipe(progress float32, isLeft bool) error

UpdateLiveSwipe updates the live swipe progress for interactive transitions. Called continuously while the user's finger is moving.

func (*Manager) UpdatePayload

func (m *Manager) UpdatePayload(zoneID string, payload plugin.Payload) error

UpdatePayload updates the rendered data for a zone and invalidates the page cache.

func (*Manager) UpdateTheme

func (m *Manager) UpdateTheme(theme Theme)

UpdateTheme applies a new theme to all subsequent rendered frames. Per-zone ThemeOverrides (accent colour, font size, etc.) are re-merged on top of the incoming global theme so they are never stomped by a settings save.

type NavConfig struct {
	SwipeEnabled        bool `yaml:"swipe_enabled" json:"swipe_enabled"`
	AutoRotate          bool `yaml:"auto_rotate" json:"auto_rotate"`
	AutoRotateIntervalS int  `yaml:"auto_rotate_interval_s,omitempty" json:"auto_rotate_interval_s,omitempty"`
}

NavConfig represents navigation settings

type Page

type Page struct {
	Name  string       `yaml:"name" json:"name"`   // Page name
	Zones []ZoneConfig `yaml:"zones" json:"zones"` // Zone configurations
}

Page represents a single page of zones

func (*Page) ComputeOffsets

func (p *Page) ComputeOffsets()

ComputeOffsets calculates X offsets for all zones by accumulated width. Always overwrites X — never skip zones with X==0, since the first zone legitimately has X=0 and stale values from a previous layout must not persist.

func (*Page) RedistributeWidths

func (p *Page) RedistributeWidths(totalPx, floorPx int) error

RedistributeWidths sets every zone's width to an equal share of totalPx, respecting the floorPx minimum. Remainder pixels are distributed one each to the leading zones so the total always equals totalPx exactly. Returns an error if the zones cannot fit within totalPx at floorPx each.

func (*Page) Validate

func (p *Page) Validate() error

Validate checks if a page configuration is valid

type PageInfo

type PageInfo struct {
	Name  string     `json:"name"`
	Zones []ZoneInfo `json:"zones"`
}

PageInfo is a lightweight page descriptor sent to the Flutter preview UI.

type PluginLookup

type PluginLookup interface {
	GetPlugin(zoneID string) (plugin.Plugin, bool)
}

PluginLookup is satisfied by Sampler. Manager uses it to resolve a zone's live plugin instance without importing the sampler package directly.

type Renderer

type Renderer struct {
	// contains filtered or unexported fields
}

Renderer renders a single zone from a Payload using fogleman/gg.

func NewRenderer

func NewRenderer(logger *slog.Logger, theme Theme, width, height int, align Alignment) *Renderer

NewRenderer creates a new zone renderer.

func (*Renderer) IsAnimating added in v0.3.0

func (r *Renderer) IsAnimating() bool

IsAnimating returns true if any text slot is actively scrolling or in its end pause. The start pause (showing static ellipsis) does not require continuous re-renders — the frame is static until scrolling begins.

func (*Renderer) Render

func (r *Renderer) Render(payload plugin.Payload) (*image.RGBA, error)

Render renders a payload into a zone-sized RGBA image.

func (*Renderer) UpdateTheme

func (r *Renderer) UpdateTheme(theme Theme)

UpdateTheme replaces the renderer's theme for all subsequent Render calls.

type Sampler

type Sampler struct {
	// contains filtered or unexported fields
}

Sampler manages periodic sampling of modules and updating zone payloads

func NewSampler

func NewSampler(ctx context.Context, logger *slog.Logger, manager *Manager, zoneCfg *ConfigManager, pluginsDir string) *Sampler

NewSampler creates a new plugin sampler. pluginsDir is the absolute path to the directory containing exec: plugin binaries. Pass "" to use the default (sibling plugins/ directory next to the running executable).

func (*Sampler) AllZoneStatuses

func (s *Sampler) AllZoneStatuses() map[string]ZoneStatus

AllZoneStatuses returns a snapshot of all zone statuses.

func (*Sampler) BroadcastConfigChange

func (s *Sampler) BroadcastConfigChange(config map[string]any)

BroadcastConfigChange delivers a global config update to all loaded plugins. Kept for the settings-level config path; zone-specific config goes through BroadcastZoneConfigChange.

func (*Sampler) BroadcastZoneConfigChange

func (s *Sampler) BroadcastZoneConfigChange(zoneID string, config map[string]any) error

BroadcastZoneConfigChange delivers a config update to a specific zone's plugin.

func (*Sampler) GetCatalog

func (s *Sampler) GetCatalog() []CatalogEntry

GetCatalog returns metadata for all available plugins: running builtins (from the loaded modules map) plus every executable found in pluginsDir. Exec plugins not currently loaded are launched briefly to retrieve their Descriptor.

func (*Sampler) GetPlugin

func (s *Sampler) GetPlugin(zoneID string) (plugin.Plugin, bool)

GetPlugin returns the live plugin instance for zoneID, if one is loaded.

func (*Sampler) GetZoneStatus

func (s *Sampler) GetZoneStatus(zoneID string) ZoneStatus

ZoneStatus returns the last known health status for a zone. Returns {Status: "loading"} if no sample has completed yet.

func (*Sampler) RestartForPage

func (s *Sampler) RestartForPage(pageIndex int) error

RestartForPage restarts sampling for a new page. Old zone goroutines are cancelled and new ones start immediately — we don't wait for old goroutines to exit so there's no blocking delay.

func (*Sampler) RestartZone

func (s *Sampler) RestartZone(zoneConfig ZoneConfig) error

RestartZone stops and restarts sampling for a single zone with a new plugin spec. Used when a tap action cycles the zone to its next plugin choice.

func (*Sampler) Start

func (s *Sampler) Start() error

Start begins sampling all zones across all pages. Keeping every plugin running at all times means page switches are instant — no subprocess teardown/restart on swipe, so payloads are always current when a page becomes visible.

func (*Sampler) Stop

func (s *Sampler) Stop()

Stop stops all sampling

type TapAction

type TapAction string

TapAction defines what happens when a zone is tapped

const (
	TapActionNone   TapAction = "none"
	TapActionCycle  TapAction = "cycle"  // Cycle through plugin choices
	TapActionDetail TapAction = "detail" // Show plugin detail overlay
)

type TapRipple added in v0.2.0

type TapRipple struct {
	// contains filtered or unexported fields
}

TapRipple tracks a single in-flight tap ripple animation.

type Theme

type Theme struct {
	Bg                string `yaml:"bg" json:"bg"`                                                       // Background color (hex)
	Fg                string `yaml:"fg" json:"fg"`                                                       // Foreground color (hex)
	Muted             string `yaml:"muted" json:"muted"`                                                 // Muted text color (hex)
	Accent            string `yaml:"accent" json:"accent"`                                               // Accent color (hex)
	ZoneBg            string `yaml:"zone_bg,omitempty" json:"zone_bg,omitempty"`                         // Zone background color (hex)
	GutterPx          int    `yaml:"gutter_px,omitempty" json:"gutter_px,omitempty"`                     // Gutter width
	FontSizePrimary   int    `yaml:"font_size_primary,omitempty" json:"font_size_primary,omitempty"`     // Primary text size
	FontSizeSecondary int    `yaml:"font_size_secondary,omitempty" json:"font_size_secondary,omitempty"` // Secondary text size
	GraphBgOpacity    int    `yaml:"graph_bg_opacity,omitempty" json:"graph_bg_opacity,omitempty"`       // Graph background opacity (0-100)
	GraphLineOpacity  int    `yaml:"graph_line_opacity,omitempty" json:"graph_line_opacity,omitempty"`   // Graph line opacity (0-100)
}

Theme represents visual styling

func DefaultTheme

func DefaultTheme() Theme

DefaultTheme returns the default dark theme

func (*Theme) GetAccentColor

func (t *Theme) GetAccentColor() color.RGBA

GetAccentColor returns the accent color as color.RGBA

func (*Theme) GetBgColor

func (t *Theme) GetBgColor() color.RGBA

GetBgColor returns the background color as color.RGBA

func (*Theme) GetFgColor

func (t *Theme) GetFgColor() color.RGBA

GetFgColor returns the foreground color as color.RGBA

func (*Theme) GetMutedColor

func (t *Theme) GetMutedColor() color.RGBA

GetMutedColor returns the muted color as color.RGBA

func (*Theme) GetZoneBgColor

func (t *Theme) GetZoneBgColor() color.RGBA

GetZoneBgColor returns the zone background color as color.RGBA

func (*Theme) ParseColor

func (t *Theme) ParseColor(hex string) (color.RGBA, error)

ParseColor converts hex color string to color.RGBA

type TransitionState

type TransitionState struct {
	Active    bool
	Type      TransitionType
	StartTime time.Time
	Duration  time.Duration
	OldFrame  *image.RGBA // Previous page frame
	NewFrame  *image.RGBA // New page frame
	Direction int         // 1 for forward, -1 for backward
	// contains filtered or unexported fields
}

TransitionState tracks the current state of a page transition.

func NewTransitionState

func NewTransitionState() *TransitionState

NewTransitionState creates a new transition state.

func (*TransitionState) AnimateManualTo

func (ts *TransitionState) AnimateManualTo(target float64, _ time.Duration)

AnimateManualTo starts a spring snap toward target (0 = cancel, 1 = commit) with zero initial velocity. Used for cancel snaps where we don't have a meaningful release velocity.

func (*TransitionState) FinalizeManual

func (ts *TransitionState) FinalizeManual(releaseVelocityPxS float32)

FinalizeManual starts a spring snap toward 1 (commit), seeded with the finger's release velocity converted to progress-units/second. releaseVelocityPxS is the finger speed in pixels/second from the touch reader.

func (*TransitionState) GetProgress

func (ts *TransitionState) GetProgress() float64

GetProgress returns the transition progress (0.0 to 1.0) and advances the spring simulation if active.

func (*TransitionState) IsComplete

func (ts *TransitionState) IsComplete() bool

IsComplete returns whether the transition is finished.

func (*TransitionState) IsManual

func (ts *TransitionState) IsManual() bool

IsManual returns true if the transition is currently under manual control.

func (*TransitionState) ManualProgress

func (ts *TransitionState) ManualProgress() float64

ManualProgress returns the current manual progress (0-1).

func (*TransitionState) Render

func (ts *TransitionState) Render() *image.RGBA

Render renders the current transition frame.

func (*TransitionState) SetManualProgress

func (ts *TransitionState) SetManualProgress(progress float64)

SetManualProgress updates the progress for a finger-driven transition.

func (*TransitionState) Start

func (ts *TransitionState) Start(transType TransitionType, oldFrame, newFrame *image.RGBA, direction int)

Start begins a transition from oldFrame to newFrame.

func (*TransitionState) StartManual

func (ts *TransitionState) StartManual(transType TransitionType, oldFrame, newFrame *image.RGBA, direction int)

StartManual begins a transition driven by explicit progress updates.

type TransitionType

type TransitionType int

TransitionType defines the type of page transition effect.

const (
	TransitionNone TransitionType = iota
	TransitionFade
	TransitionSlideLeft
	TransitionSlideRight
	TransitionSlideUp
	TransitionSlideDown
)

type Zone

type Zone struct {
	Config   ZoneConfig
	Renderer *Renderer
	Plugin   string
	// contains filtered or unexported fields
}

Zone represents a single zone instance.

type ZoneConfig

type ZoneConfig struct {
	ID            string         `yaml:"id" json:"id"`                                             // Unique zone identifier
	Width         int            `yaml:"width" json:"width"`                                       // Zone width in pixels
	X             int            `yaml:"x,omitempty" json:"x,omitempty"`                           // X offset (auto-computed if 0)
	Plugin        string         `yaml:"plugin" json:"plugin"`                                     // Plugin endpoint (builtin:name or exec:path)
	RefreshMs     int            `yaml:"refresh_ms" json:"refresh_ms"`                             // Sampling interval
	Align         Alignment      `yaml:"align,omitempty" json:"align,omitempty"`                   // Text alignment
	ThemeOverride *Theme         `yaml:"theme_override,omitempty" json:"theme_override,omitempty"` // Per-zone theme
	PluginConfig  map[string]any `yaml:"plugin_config,omitempty" json:"plugin_config,omitempty"`   // Per-zone plugin configuration
	Choices       []string       `yaml:"choices,omitempty" json:"choices,omitempty"`               // Plugin choices for cycling
	OnTap         TapAction      `yaml:"on_tap,omitempty" json:"on_tap,omitempty"`                 // Tap action
}

ZoneConfig represents configuration for a single zone

func (*ZoneConfig) Validate

func (z *ZoneConfig) Validate() error

Validate checks if a zone configuration is valid

type ZoneInfo

type ZoneInfo struct {
	ID    string `json:"id"`
	Width int    `json:"width"`
	OnTap string `json:"on_tap,omitempty"`
}

ZoneInfo is a lightweight zone descriptor sent to the Flutter preview UI.

type ZoneStatus

type ZoneStatus struct {
	Status string // "ok" | "error" | "timeout" | "loading"
	Error  string // non-empty when Status is "error" or "timeout"
}

ZoneStatus represents the current health of a single zone's plugin.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL