docs(readme): introduce the library with a minimal counter
- commit
- 068ba85462f9eef7712fe672e5d6d37af55390de
- author
- brice · · 2026-09-30 03:34 UTC
- parent
- d438c5c
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +69 -28
M README.md +43 -28
| @@ -1,49 +1,64 @@ | |||
| 1 | 1 | # NeferGUI | |
| 2 | 2 | ||
| 3 | - | Native immediate-mode GUI library for Go, built for Wayland with Vulkan rendering and CSS styling. | |
| 3 | + | A native Go GUI library for Linux: Wayland windows, Vulkan rendering, and CSS styling. Build your view from the current model; controls return events during that call. No cgo required. | |
| 4 | 4 | ||
| 5 | - | ## Status | |
| 5 | + | > [!WARNING] | |
| 6 | + | > **Early development.** No release yet. Expect bugs and breaking changes. Platform accessibility is not connected. | |
| 6 | 7 | ||
| 7 | - | NeferGUI is under active development and has no release yet. | |
| 8 | - | ||
| 9 | - | ## Usage | |
| 8 | + | ## A small example | |
| 10 | 9 | ||
| 11 | 10 | ```go | |
| 12 | - | type Model struct{ Name, Status string } | |
| 11 | + | package main | |
| 13 | 12 | ||
| 14 | - | func view(f *nefergui.Frame, m *Model) { | |
| 15 | - | root := f.Root(nefergui.Class("app")) | |
| 16 | - | root.Input("Name", &m.Name, nefergui.Key("name")) | |
| 17 | - | if root.Button("Greet", nefergui.Key("greet")).Activated() { | |
| 18 | - | m.Status = "Hello " + m.Name | |
| 19 | - | } | |
| 20 | - | root.Text(m.Status) | |
| 21 | - | } | |
| 13 | + | import ( | |
| 14 | + | "context" | |
| 15 | + | "fmt" | |
| 16 | + | "log" | |
| 17 | + | ||
| 18 | + | "github.com/bnema/nefergui" | |
| 19 | + | ) | |
| 22 | 20 | ||
| 23 | 21 | func main() { | |
| 24 | - | var m Model | |
| 25 | - | if err := nefergui.Run(context.Background(), &m, view, nefergui.Title("Hello"), nefergui.Size(640, 480), nefergui.Styles("app.css")); err != nil { | |
| 22 | + | count := 0 | |
| 23 | + | view := func(f *nefergui.Frame, count *int) { | |
| 24 | + | root := f.Root().Column() | |
| 25 | + | root.Text("Hello, Wayland!") | |
| 26 | + | if root.Button("Count", nefergui.Key("count")).Activated() { | |
| 27 | + | *count++ | |
| 28 | + | } | |
| 29 | + | root.Text(fmt.Sprintf("Clicked %d times", *count)) | |
| 30 | + | } | |
| 31 | + | if err := nefergui.Run(context.Background(), &count, view, | |
| 32 | + | nefergui.Title("Hello"), nefergui.Size(320, 200)); err != nil { | |
| 26 | 33 | log.Fatal(err) | |
| 27 | 34 | } | |
| 28 | 35 | } | |
| 29 | 36 | ``` | |
| 30 | 37 | ||
| 31 | - | Runtime requirements: a Wayland compositor with linux-dmabuf and linux-drm-syncobj, `libvulkan.so.1` and `libxkbcommon.so.0`. Builds with `CGO_ENABLED=0`. See [docs/runtime.md](docs/runtime.md) and `examples/demo`. | |
| 38 | + | Default styles work without a stylesheet; `nefergui.Styles("app.css")` loads your own CSS. | |
| 32 | 39 | ||
| 33 | - | ## Documentation | |
| 40 | + | ## Try it | |
| 34 | 41 | ||
| 35 | - | - [CSS properties and limitations](docs/css.md) | |
| 36 | - | - [Layout](docs/layout.md) · [Controls](docs/controls.md) · [Runtime](docs/runtime.md) | |
| 37 | - | - [Troubleshooting](docs/troubleshooting.md) · [Harness](docs/harness.md) · [Performance](docs/performance.md) | |
| 42 | + | Requires Go 1.27, `libvulkan.so.1`, `libxkbcommon.so.0`, usable fonts, and a Wayland compositor supporting linux-dmabuf and linux-drm-syncobj. Fractional scaling also requires viewporter. No X11 or software-rendering fallback. | |
| 38 | 43 | ||
| 39 | - | ## Design records | |
| 44 | + | ```sh | |
| 45 | + | go get github.com/bnema/nefergui | |
| 46 | + | ``` | |
| 47 | + | ||
| 48 | + | From a checkout, run the [demo](examples/demo): | |
| 49 | + | ||
| 50 | + | ```sh | |
| 51 | + | CGO_ENABLED=0 go run ./examples/demo | |
| 52 | + | ``` | |
| 40 | 53 | ||
| 41 | - | - [0002 Wayland bindings and FD ownership](docs/adr/0002-wayland-bindings-and-fd-ownership.md) | |
| 42 | - | - [0003 Vulkan presentation through DMA-BUF](docs/adr/0003-vulkan-dmabuf-presentation.md) | |
| 43 | - | - [0004 Keyboard interpretation](docs/adr/0004-keyboard.md) | |
| 44 | - | - [0005 Immediate-mode identity and events](docs/adr/0005-identity-and-events.md) | |
| 45 | - | - [0006 CSS and text scope](docs/adr/0006-css-and-text-scope.md) | |
| 54 | + | ## Documentation | |
| 55 | + | ||
| 56 | + | - [Controls](docs/controls.md) and [layout](docs/layout.md) | |
| 57 | + | - [CSS properties and limitations](docs/css.md) | |
| 58 | + | - [Runtime requirements and behavior](docs/runtime.md) and [troubleshooting](docs/troubleshooting.md) | |
| 59 | + | - [Visual test harness](docs/harness.md) and [performance](docs/performance.md) | |
| 60 | + | - [Architecture decisions](docs/adr) | |
| 46 | 61 | ||
| 47 | 62 | ## License | |
| 48 | 63 | ||
| 49 | - | NeferGUI is licensed under [GNU GPL v3](LICENSE). Third-party code and test fonts retain their licenses and attribution notices in their respective directories. | |
| 64 | + | [GNU GPL v3](LICENSE). Third-party code and test fonts retain their own licenses and attribution. | |
| @@ -1,49 +1,64 @@ | |||||
| 1 | # NeferGUI | 1 | # NeferGUI | ||
| 2 | 2 | ||||
| 3 | - | Native immediate-mode GUI library for Go, built for Wayland with Vulkan rendering and CSS styling. | 3 | + | A native Go GUI library for Linux: Wayland windows, Vulkan rendering, and CSS styling. Build your view from the current model; controls return events during that call. No cgo required. |
| 4 | 4 | ||||
| 5 | - | ## Status | 5 | + | > [!WARNING] |
| 6 | + | > **Early development.** No release yet. Expect bugs and breaking changes. Platform accessibility is not connected. | |||
| 6 | 7 | ||||
| 7 | - | NeferGUI is under active development and has no release yet. | 8 | + | ## A small example |
| 8 | - | ||||
| 9 | - | ## Usage | |||
| 10 | 9 | ||||
| 11 | ```go | 10 | ```go | ||
| 12 | - | type Model struct{ Name, Status string } | 11 | + | package main |
| 13 | 12 | ||||
| 14 | - | func view(f *nefergui.Frame, m *Model) { | 13 | + | import ( |
| 15 | - | root := f.Root(nefergui.Class("app")) | 14 | + | "context" |
| 16 | - | root.Input("Name", &m.Name, nefergui.Key("name")) | 15 | + | "fmt" |
| 17 | - | if root.Button("Greet", nefergui.Key("greet")).Activated() { | 16 | + | "log" |
| 18 | - | m.Status = "Hello " + m.Name | 17 | + | |
| 19 | - | } | 18 | + | "github.com/bnema/nefergui" |
| 20 | - | root.Text(m.Status) | 19 | + | ) |
| 21 | - | } | |||
| 22 | 20 | ||||
| 23 | func main() { | 21 | func main() { | ||
| 24 | - | var m Model | 22 | + | count := 0 |
| 25 | - | if err := nefergui.Run(context.Background(), &m, view, nefergui.Title("Hello"), nefergui.Size(640, 480), nefergui.Styles("app.css")); err != nil { | 23 | + | view := func(f *nefergui.Frame, count *int) { |
| 24 | + | root := f.Root().Column() | |||
| 25 | + | root.Text("Hello, Wayland!") | |||
| 26 | + | if root.Button("Count", nefergui.Key("count")).Activated() { | |||
| 27 | + | *count++ | |||
| 28 | + | } | |||
| 29 | + | root.Text(fmt.Sprintf("Clicked %d times", *count)) | |||
| 30 | + | } | |||
| 31 | + | if err := nefergui.Run(context.Background(), &count, view, | |||
| 32 | + | nefergui.Title("Hello"), nefergui.Size(320, 200)); err != nil { | |||
| 26 | log.Fatal(err) | 33 | log.Fatal(err) | ||
| 27 | } | 34 | } | ||
| 28 | } | 35 | } | ||
| 29 | ``` | 36 | ``` | ||
| 30 | 37 | ||||
| 31 | - | Runtime requirements: a Wayland compositor with linux-dmabuf and linux-drm-syncobj, `libvulkan.so.1` and `libxkbcommon.so.0`. Builds with `CGO_ENABLED=0`. See [docs/runtime.md](docs/runtime.md) and `examples/demo`. | 38 | + | Default styles work without a stylesheet; `nefergui.Styles("app.css")` loads your own CSS. |
| 32 | 39 | ||||
| 33 | - | ## Documentation | 40 | + | ## Try it |
| 34 | 41 | ||||
| 35 | - | - [CSS properties and limitations](docs/css.md) | 42 | + | Requires Go 1.27, `libvulkan.so.1`, `libxkbcommon.so.0`, usable fonts, and a Wayland compositor supporting linux-dmabuf and linux-drm-syncobj. Fractional scaling also requires viewporter. No X11 or software-rendering fallback. |
| 36 | - | - [Layout](docs/layout.md) · [Controls](docs/controls.md) · [Runtime](docs/runtime.md) | |||
| 37 | - | - [Troubleshooting](docs/troubleshooting.md) · [Harness](docs/harness.md) · [Performance](docs/performance.md) | |||
| 38 | 43 | ||||
| 39 | - | ## Design records | 44 | + | ```sh |
| 45 | + | go get github.com/bnema/nefergui | |||
| 46 | + | ``` | |||
| 47 | + | ||||
| 48 | + | From a checkout, run the [demo](examples/demo): | |||
| 49 | + | ||||
| 50 | + | ```sh | |||
| 51 | + | CGO_ENABLED=0 go run ./examples/demo | |||
| 52 | + | ``` | |||
| 40 | 53 | ||||
| 41 | - | - [0002 Wayland bindings and FD ownership](docs/adr/0002-wayland-bindings-and-fd-ownership.md) | 54 | + | ## Documentation |
| 42 | - | - [0003 Vulkan presentation through DMA-BUF](docs/adr/0003-vulkan-dmabuf-presentation.md) | 55 | + | |
| 43 | - | - [0004 Keyboard interpretation](docs/adr/0004-keyboard.md) | 56 | + | - [Controls](docs/controls.md) and [layout](docs/layout.md) |
| 44 | - | - [0005 Immediate-mode identity and events](docs/adr/0005-identity-and-events.md) | 57 | + | - [CSS properties and limitations](docs/css.md) |
| 45 | - | - [0006 CSS and text scope](docs/adr/0006-css-and-text-scope.md) | 58 | + | - [Runtime requirements and behavior](docs/runtime.md) and [troubleshooting](docs/troubleshooting.md) |
| 59 | + | - [Visual test harness](docs/harness.md) and [performance](docs/performance.md) | |||
| 60 | + | - [Architecture decisions](docs/adr) | |||
| 46 | 61 | ||||
| 47 | ## License | 62 | ## License | ||
| 48 | 63 | ||||
| 49 | - | NeferGUI is licensed under [GNU GPL v3](LICENSE). Third-party code and test fonts retain their licenses and attribution notices in their respective directories. | 64 | + | [GNU GPL v3](LICENSE). Third-party code and test fonts retain their own licenses and attribution. |
A readme_example_test.go +26 -0
| @@ -0,0 +1,26 @@ | |||
| 1 | + | package nefergui_test | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "context" | |
| 5 | + | "fmt" | |
| 6 | + | "log" | |
| 7 | + | ||
| 8 | + | "github.com/bnema/nefergui" | |
| 9 | + | ) | |
| 10 | + | ||
| 11 | + | // Compile the README example without opening a window during tests. | |
| 12 | + | func Example_counter() { | |
| 13 | + | count := 0 | |
| 14 | + | view := func(f *nefergui.Frame, count *int) { | |
| 15 | + | root := f.Root().Column() | |
| 16 | + | root.Text("Hello, Wayland!") | |
| 17 | + | if root.Button("Count", nefergui.Key("count")).Activated() { | |
| 18 | + | *count++ | |
| 19 | + | } | |
| 20 | + | root.Text(fmt.Sprintf("Clicked %d times", *count)) | |
| 21 | + | } | |
| 22 | + | if err := nefergui.Run(context.Background(), &count, view, | |
| 23 | + | nefergui.Title("Hello"), nefergui.Size(320, 200)); err != nil { | |
| 24 | + | log.Fatal(err) | |
| 25 | + | } | |
| 26 | + | } | |
| @@ -0,0 +1,26 @@ | |||||
| 1 | + | package nefergui_test | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "context" | |||
| 5 | + | "fmt" | |||
| 6 | + | "log" | |||
| 7 | + | ||||
| 8 | + | "github.com/bnema/nefergui" | |||
| 9 | + | ) | |||
| 10 | + | ||||
| 11 | + | // Compile the README example without opening a window during tests. | |||
| 12 | + | func Example_counter() { | |||
| 13 | + | count := 0 | |||
| 14 | + | view := func(f *nefergui.Frame, count *int) { | |||
| 15 | + | root := f.Root().Column() | |||
| 16 | + | root.Text("Hello, Wayland!") | |||
| 17 | + | if root.Button("Count", nefergui.Key("count")).Activated() { | |||
| 18 | + | *count++ | |||
| 19 | + | } | |||
| 20 | + | root.Text(fmt.Sprintf("Clicked %d times", *count)) | |||
| 21 | + | } | |||
| 22 | + | if err := nefergui.Run(context.Background(), &count, view, | |||
| 23 | + | nefergui.Title("Hello"), nefergui.Size(320, 200)); err != nil { | |||
| 24 | + | log.Fatal(err) | |||
| 25 | + | } | |||
| 26 | + | } | |||