# Shirei

Shirei is a cross-platform GUI framework for Go (desktop and mobile).

Module: `go.hasen.dev/shirei` — current version `v0.9.0`.
Source repository: [`hasenj/go-shirei`](https://github.com/hasenj/go-shirei).
Extensions are separate modules: `go.hasen.dev/shirei/ext/window`,
`.../ext/darkmode`, `.../ext/camera`.

## What it is

- Pure Go immediate-mode UI. The frame function describes the whole interface
  from your own plain data; there are no retained widget objects and no
  callbacks. Interaction results are return values.
- Native backends: Windows, macOS, Linux (Wayland primary, X11 secondary),
  iOS, Android.
- Content-based layout: containers size from their children, with explicit
  control over remaining space and cross-axis expansion.
- Stock widgets: labels, buttons, checkboxes, sliders, text inputs, segmented
  controls, tabs, tables, virtual lists, menus, modals, popups, toasts, file
  selectors, document editor, icon glyphs.
- Complex text shaping and bidirectional layout, IME for East Asian input,
  system fonts, and furigana annotations.
- Document editing with undo/redo, line numbers, and file load/save helpers.
- Native auxiliary windows, transparent desktop overlays, and background apps.
- Color schemes, dark mode, and per-widget styling.
- GPU compositor by default (Metal, GLES, D3D11, WebGL2); automatic software
  renderer fallback.
- Headless deterministic rendering for snapshots, plus UDP-driven live-window
  tests.

## What it is not

- Not retained-mode, not HTML/CSS, no reactive state system. State is plain Go
  data; frames are explicit.
- Accessibility coverage is basic: static text, buttons, toggles and sliders on
  macOS, Linux Wayland and 64-bit Windows.
- No app-owned GPU surfaces (video playback or custom 3D rendering).
- Wayland overlays and explicit window positioning require layer-shell v4;
  ordinary windows follow compositor placement and focus policy.
- X11 supports auxiliary windows but not background main-window restoration or
  always-on-top overlays.
- Mobile work requires the platform toolchains and the shipped mobile runner.

## Examples

Each example and demo is its own module. The links point at the source in
`hasenj/go-shirei`; the same paths exist in the module tree.

| example | shows |
|---|---|
| [`examples/dir_weight`](https://github.com/hasenj/go-shirei/tree/master/examples/dir_weight) | filesystem scan, background workers, tabs, filtering, large virtual list |
| [`examples/see_pprof`](https://github.com/hasenj/go-shirei/tree/master/examples/see_pprof) | sortable tables, custom canvas, file watching, snapshot tests |
| [`examples/process_monitor`](https://github.com/hasenj/go-shirei/tree/master/examples/process_monitor) | live data collection, table/tree views, charts, stable stores, drive tests |
| [`examples/git_history`](https://github.com/hasenj/go-shirei/tree/master/examples/git_history) | commit list and diffs, tabs, session restore |
| [`examples/haystack`](https://github.com/hasenj/go-shirei/tree/master/examples/haystack) | find-in-files, tabbed editing and saving |
| [`examples/icons`](https://github.com/hasenj/go-shirei/tree/master/examples/icons) | searchable icon/glyph picker |
| [`examples/ferry`](https://github.com/hasenj/go-shirei/tree/master/examples/ferry) | SSH/SFTP two-pane file manager |
| [`examples/piano`](https://github.com/hasenj/go-shirei/tree/master/examples/piano) | audio, custom input, keyboard rendering |
| [`demos/overlay`](https://github.com/hasenj/go-shirei/tree/master/demos/overlay) | transparent desktop overlay |
| [`demos/popup-windows`](https://github.com/hasenj/go-shirei/tree/master/demos/popup-windows) | native auxiliary windows |
| [`demos/window-style`](https://github.com/hasenj/go-shirei/tree/master/demos/window-style) | window styling and controls |
| [`demos/darkmode-probe`](https://github.com/hasenj/go-shirei/tree/master/demos/darkmode-probe) | OS dark-mode detection |
| [`behavior_test`](https://github.com/hasenj/go-shirei/tree/master/behavior_test) | behavior test harness (separate module) |

## Minimal app

```go
package main

import (
	"fmt"

	app "go.hasen.dev/shirei/app"

	. "go.hasen.dev/shirei"
	. "go.hasen.dev/shirei/widgets"
)

var count int

func RootView() {
	Container(Attrs(Viewport, Background(220, 10, 97, 1)), func() {
		Container(Attrs(Row, CrossMid, Pad(20), Gap(10)), func() {
			Label(fmt.Sprintf("Counter: %d", count))
			if Button(SymIPlus, "Increment") {
				count++
			}
		})
	})
}

func main() {
	app.SetupWindow("My App", 300, 100)
	app.Run(RootView)
}
```

## Mental model

- The frame function rebuilds the UI from application state every frame.
  Nothing is retained between frames except your own data and explicit
  identities.
- Frames run on input, on animation continuation, or when `RequestNextFrame()`
  is called. Call it when state changes outside the input loop (goroutines,
  timers). Ordinary interactions already produce frames.
- Cross-goroutine updates go through `WithFrameLock(fn)`, then request a frame.
  Keep the locked section short; never block the frame function.
- Dynamic lists and tables need stable app-owned identity per item (pointer or
  key), not positional identity.
- Animations are on by default; `NoAnimate` opts out for a subtree.
- App entry: `app.SetupWindow(title, w, h)` then `app.Run(frameFn)`. Headless
  rendering does not need a window (see [testing.md](agents/testing.md)).
- Identity and frame-local state have their own rules: see
  [state-and-identity.md](agents/state-and-identity.md).

## Topic files (this site)

| task | file |
|---|---|
| layout, sizing, attributes, spacing | [agents/layout.md](agents/layout.md) |
| interaction: hover, click, drag, touch, scroll, focus, keyboard | [agents/interaction.md](agents/interaction.md) |
| stock widgets, tables | [agents/widgets.md](agents/widgets.md) |
| virtual lists, row heights, `Measure` | [agents/virtual-lists.md](agents/virtual-lists.md) |
| document editing, file load/save | [agents/text-editing.md](agents/text-editing.md) |
| furigana annotations in labels and editable text | [agents/furigana.md](agents/furigana.md) |
| color schemes, dark mode, styling | [agents/appearance.md](agents/appearance.md) |
| window setup, popups, overlays, background apps, Wayland policy | [agents/windows.md](agents/windows.md) |
| application state, identity, hooks, settling, animation | [agents/state-and-identity.md](agents/state-and-identity.md) |
| custom widgets: process/paint, hit-testing, focus | [agents/custom-widgets.md](agents/custom-widgets.md) |
| accessibility: labels, roles, actions, custom controls | [agents/accessibility.md](agents/accessibility.md) |
| drag and drop, ghost preview | [agents/drag-drop.md](agents/drag-drop.md) |
| audio: voices, threading, headless verification | [agents/audio.md](agents/audio.md) |
| mobile: Android/iOS runners, extensions, capabilities | [agents/mobile.md](agents/mobile.md) |
| headless rendering, snapshots, frame driving | [agents/testing.md](agents/testing.md) |
| drive tests: access names, query, UDP driver | [agents/drive-tests.md](agents/drive-tests.md) |
| app patterns: selection, background work, stores, trees, charts | [agents/app-patterns.md](agents/app-patterns.md) |
| platforms, build, resources, tooling | [agents/platforms.md](agents/platforms.md) |
| upgrading from older versions | [agents/migration.md](agents/migration.md) |
