docs(gui): clarify facade methods and profiling measurements
- commit
- f8b8aaa81ec99f8c0d1869325bf8d7640f8bd16c
- author
- brice · · 2026-09-30 03:56 UTC
- parent
- 84c1f24
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
3 files · +20 -9
M docs/controls.md +4 -0
| @@ -1,5 +1,9 @@ | |||
| 1 | 1 | # Controls | |
| 2 | 2 | ||
| 3 | + | Import `github.com/bnema/nefergui`. Public `Frame`, `Node` and event types alias their implementation types, so `go doc` does not list their methods at the root. Inspect signatures with `go doc github.com/bnema/nefergui/internal/ui.Node` (or `.Frame`, `.ButtonEvent`, `.EditEvent`, `.ChangeEvent`). Applications still use the public package; do not import `internal/ui`. | |
| 4 | + | ||
| 5 | + | `ButtonEvent.Activated()` reports activation; `EditEvent.Changed()` and `.Submitted()` report edits and submission; `ChangeEvent.Changed()` reports value changes. These snapshots can be queried repeatedly without consuming an event. | |
| 6 | + | ||
| 3 | 7 | `Text`, `Heading`, `Image`, `Icon`, `Separator`, `Spacer`, `Button`, `Checkbox`, `Radio`, `Slider`, `Input` and `Textarea` build semantic nodes in the immediate frame. `Key` identifies reorderable controls; `ID` and `Class` are CSS metadata. `Image` accepts an existing `image.Image` with bounded intrinsic dimensions. Style is computed via the existing CSS cascade; the caller owns images. CSS types and default accessibility roles are assigned even though a platform accessibility adapter is not yet connected. | |
| 4 | 8 | ||
| 5 | 9 | `Button`, `Checkbox`, `Radio` and `Slider` paint their label as text in the control's content box, using its font, `color` and `text-align` (buttons center by default). | |
| @@ -1,5 +1,9 @@ | |||||
| 1 | # Controls | 1 | # Controls | ||
| 2 | 2 | ||||
| 3 | + | Import `github.com/bnema/nefergui`. Public `Frame`, `Node` and event types alias their implementation types, so `go doc` does not list their methods at the root. Inspect signatures with `go doc github.com/bnema/nefergui/internal/ui.Node` (or `.Frame`, `.ButtonEvent`, `.EditEvent`, `.ChangeEvent`). Applications still use the public package; do not import `internal/ui`. | |||
| 4 | + | ||||
| 5 | + | `ButtonEvent.Activated()` reports activation; `EditEvent.Changed()` and `.Submitted()` report edits and submission; `ChangeEvent.Changed()` reports value changes. These snapshots can be queried repeatedly without consuming an event. | |||
| 6 | + | ||||
| 3 | `Text`, `Heading`, `Image`, `Icon`, `Separator`, `Spacer`, `Button`, `Checkbox`, `Radio`, `Slider`, `Input` and `Textarea` build semantic nodes in the immediate frame. `Key` identifies reorderable controls; `ID` and `Class` are CSS metadata. `Image` accepts an existing `image.Image` with bounded intrinsic dimensions. Style is computed via the existing CSS cascade; the caller owns images. CSS types and default accessibility roles are assigned even though a platform accessibility adapter is not yet connected. | 7 | `Text`, `Heading`, `Image`, `Icon`, `Separator`, `Spacer`, `Button`, `Checkbox`, `Radio`, `Slider`, `Input` and `Textarea` build semantic nodes in the immediate frame. `Key` identifies reorderable controls; `ID` and `Class` are CSS metadata. `Image` accepts an existing `image.Image` with bounded intrinsic dimensions. Style is computed via the existing CSS cascade; the caller owns images. CSS types and default accessibility roles are assigned even though a platform accessibility adapter is not yet connected. | ||
| 4 | 8 | ||||
| 5 | `Button`, `Checkbox`, `Radio` and `Slider` paint their label as text in the control's content box, using its font, `color` and `text-align` (buttons center by default). | 9 | `Button`, `Checkbox`, `Radio` and `Slider` paint their label as text in the control's content box, using its font, `color` and `text-align` (buttons center by default). | ||
M docs/performance.md +3 -3
| @@ -6,7 +6,7 @@ AMD Ryzen 9 7900X3D 12-Core Processor; `CGO_ENABLED=0 GOWORK=off go test -run '^ | |||
| 6 | 6 | ||
| 7 | 7 | | Package / benchmark | Median ns/op | Median B/op | Median allocs/op | Budget ns/op | Budget B/op | Budget allocs/op | | |
| 8 | 8 | |---|---:|---:|---:|---:|---:|---:| | |
| 9 | - | | root / DemoFrame | 21,238 | 32,816 | 220 | 45,000 | 66,000 | 500 | | |
| 9 | + | | internal/ui / DemoFrame | 21,238 | 32,816 | 220 | 45,000 | 66,000 | 500 | | |
| 10 | 10 | | render / Prepare | 59,024 | 158,720 | 386 | 125,000 | 320,000 | 800 | | |
| 11 | 11 | | text / AtlasWarmLookup | 29.07 | 0 | 0 | 60 | 0 | 0 | | |
| 12 | 12 | | text / RasterDistinct1000 | 4,139,638 | 8,566,137 | 16,784 | 8,300,000 | 17,200,000 | 34,000 | | |
| @@ -37,13 +37,13 @@ A 400-frame demo harness run (960×640, scale 1, input: name Ada then continue) | |||
| 37 | 37 | ||
| 38 | 38 | ## Memory as a dependency | |
| 39 | 39 | ||
| 40 | - | An external Go module with a minimal counter view, a 960×640 window, and a private headless NeferWL compositor was profiled on AMD/RADV. Debug readbacks were disabled. Live Go heap was sampled after forced GC; RSS includes shared driver libraries, while PSS apportions shared pages. | |
| 40 | + | An external Go module with a minimal counter view, a 960×640 window, and a private headless NeferWL compositor was profiled on AMD/RADV. Baseline: NeferGUI `068ba85`, Go 1.27.1, Mesa/RADV 26.2.3, and NeferWL `1d16b83bf90f9e8189ad21b27772382c96b9f9a8`. A minimal-consumer repeat at `84c1f24` matched retained heap within 0.02 MiB and used identical GPU allocations. Debug readbacks were disabled. Live Go heap was sampled after forced GC; RSS includes shared driver libraries, while PSS apportions shared pages. | |
| 41 | 41 | ||
| 42 | 42 | | Measurement | Minimal view | Demo view | | |
| 43 | 43 | |---|---:|---:| | |
| 44 | 44 | | Live Go heap after 1,000 frames | 5.3 MiB | 5.4 MiB | | |
| 45 | 45 | | Process RSS / PSS after 1,000 frames | 60 / 43 MiB | 64 / 47 MiB | | |
| 46 | - | | Estimated temporary allocations per rendered frame, sampler excluded | about 65 KiB | about 230 KiB | | |
| 46 | + | | Estimated temporary allocations per rendered frame, measurement sampler's own allocations excluded | about 65 KiB | about 230 KiB | | |
| 47 | 47 | ||
| 48 | 48 | The minimal view starts at about 0.75 MiB live Go heap, reaches 5.2 MiB after the first frame, and returns to about 0.9 MiB after closing. No sustained live-heap growth was observed over 1,000–3,000 frames. Driver mappings and Go heap capacity can remain resident after closing; RSS is not a leak measurement on its own. | |
| 49 | 49 | ||
| @@ -6,7 +6,7 @@ AMD Ryzen 9 7900X3D 12-Core Processor; `CGO_ENABLED=0 GOWORK=off go test -run '^ | |||||
| 6 | 6 | ||||
| 7 | | Package / benchmark | Median ns/op | Median B/op | Median allocs/op | Budget ns/op | Budget B/op | Budget allocs/op | | 7 | | Package / benchmark | Median ns/op | Median B/op | Median allocs/op | Budget ns/op | Budget B/op | Budget allocs/op | | ||
| 8 | |---|---:|---:|---:|---:|---:|---:| | 8 | |---|---:|---:|---:|---:|---:|---:| | ||
| 9 | - | | root / DemoFrame | 21,238 | 32,816 | 220 | 45,000 | 66,000 | 500 | | 9 | + | | internal/ui / DemoFrame | 21,238 | 32,816 | 220 | 45,000 | 66,000 | 500 | |
| 10 | | render / Prepare | 59,024 | 158,720 | 386 | 125,000 | 320,000 | 800 | | 10 | | render / Prepare | 59,024 | 158,720 | 386 | 125,000 | 320,000 | 800 | | ||
| 11 | | text / AtlasWarmLookup | 29.07 | 0 | 0 | 60 | 0 | 0 | | 11 | | text / AtlasWarmLookup | 29.07 | 0 | 0 | 60 | 0 | 0 | | ||
| 12 | | text / RasterDistinct1000 | 4,139,638 | 8,566,137 | 16,784 | 8,300,000 | 17,200,000 | 34,000 | | 12 | | text / RasterDistinct1000 | 4,139,638 | 8,566,137 | 16,784 | 8,300,000 | 17,200,000 | 34,000 | | ||
| @@ -37,13 +37,13 @@ A 400-frame demo harness run (960×640, scale 1, input: name Ada then continue) | |||||
| 37 | 37 | ||||
| 38 | ## Memory as a dependency | 38 | ## Memory as a dependency | ||
| 39 | 39 | ||||
| 40 | - | An external Go module with a minimal counter view, a 960×640 window, and a private headless NeferWL compositor was profiled on AMD/RADV. Debug readbacks were disabled. Live Go heap was sampled after forced GC; RSS includes shared driver libraries, while PSS apportions shared pages. | 40 | + | An external Go module with a minimal counter view, a 960×640 window, and a private headless NeferWL compositor was profiled on AMD/RADV. Baseline: NeferGUI `068ba85`, Go 1.27.1, Mesa/RADV 26.2.3, and NeferWL `1d16b83bf90f9e8189ad21b27772382c96b9f9a8`. A minimal-consumer repeat at `84c1f24` matched retained heap within 0.02 MiB and used identical GPU allocations. Debug readbacks were disabled. Live Go heap was sampled after forced GC; RSS includes shared driver libraries, while PSS apportions shared pages. |
| 41 | 41 | ||||
| 42 | | Measurement | Minimal view | Demo view | | 42 | | Measurement | Minimal view | Demo view | | ||
| 43 | |---|---:|---:| | 43 | |---|---:|---:| | ||
| 44 | | Live Go heap after 1,000 frames | 5.3 MiB | 5.4 MiB | | 44 | | Live Go heap after 1,000 frames | 5.3 MiB | 5.4 MiB | | ||
| 45 | | Process RSS / PSS after 1,000 frames | 60 / 43 MiB | 64 / 47 MiB | | 45 | | Process RSS / PSS after 1,000 frames | 60 / 43 MiB | 64 / 47 MiB | | ||
| 46 | - | | Estimated temporary allocations per rendered frame, sampler excluded | about 65 KiB | about 230 KiB | | 46 | + | | Estimated temporary allocations per rendered frame, measurement sampler's own allocations excluded | about 65 KiB | about 230 KiB | |
| 47 | 47 | ||||
| 48 | The minimal view starts at about 0.75 MiB live Go heap, reaches 5.2 MiB after the first frame, and returns to about 0.9 MiB after closing. No sustained live-heap growth was observed over 1,000–3,000 frames. Driver mappings and Go heap capacity can remain resident after closing; RSS is not a leak measurement on its own. | 48 | The minimal view starts at about 0.75 MiB live Go heap, reaches 5.2 MiB after the first frame, and returns to about 0.9 MiB after closing. No sustained live-heap growth was observed over 1,000–3,000 frames. Driver mappings and Go heap capacity can remain resident after closing; RSS is not a leak measurement on its own. | ||
| 49 | 49 | ||||
M nefergui.go +13 -6
| @@ -23,6 +23,7 @@ import ( | |||
| 23 | 23 | ||
| 24 | 24 | // Frame is valid only during one call to the view function. Root builds the | |
| 25 | 25 | // application element; Diagnostics reports identity problems in debug builds. | |
| 26 | + | // Alias methods are listed by go doc github.com/bnema/nefergui/internal/ui.Frame. | |
| 26 | 27 | type Frame = ui.Frame | |
| 27 | 28 | ||
| 28 | 29 | // Node is an ephemeral handle into the current frame. Do not retain it between | |
| @@ -31,14 +32,20 @@ type Frame = ui.Frame | |||
| 31 | 32 | // (Button, Checkbox, Radio, Slider, Input, Textarea, Text, Heading, Image, | |
| 32 | 33 | // Icon, Separator, Spacer) declare controls. Interactive controls return event | |
| 33 | 34 | // snapshots. | |
| 35 | + | // Alias methods are listed by go doc github.com/bnema/nefergui/internal/ui.Node. | |
| 34 | 36 | type Node = ui.Node | |
| 35 | 37 | ||
| 36 | - | // Control event values are immutable snapshots; querying them never consumes events. | |
| 37 | - | type ( | |
| 38 | - | ButtonEvent = ui.ButtonEvent | |
| 39 | - | EditEvent = ui.EditEvent | |
| 40 | - | ChangeEvent = ui.ChangeEvent | |
| 41 | - | ) | |
| 38 | + | // ButtonEvent is an immutable snapshot queried with Activated. | |
| 39 | + | // Alias methods are listed by go doc github.com/bnema/nefergui/internal/ui.ButtonEvent. | |
| 40 | + | type ButtonEvent = ui.ButtonEvent | |
| 41 | + | ||
| 42 | + | // EditEvent is an immutable snapshot queried with Changed and Submitted. | |
| 43 | + | // Alias methods are listed by go doc github.com/bnema/nefergui/internal/ui.EditEvent. | |
| 44 | + | type EditEvent = ui.EditEvent | |
| 45 | + | ||
| 46 | + | // ChangeEvent is an immutable snapshot queried with Changed. | |
| 47 | + | // Alias methods are listed by go doc github.com/bnema/nefergui/internal/ui.ChangeEvent. | |
| 48 | + | type ChangeEvent = ui.ChangeEvent | |
| 42 | 49 | ||
| 43 | 50 | // Option families are sealed: ContainerOption, ButtonOption, EditOption, | |
| 44 | 51 | // ValueOption and HeadingOption accept the common CSS options (Key, ID, | |
| @@ -23,6 +23,7 @@ import ( | |||||
| 23 | 23 | ||||
| 24 | // Frame is valid only during one call to the view function. Root builds the | 24 | // Frame is valid only during one call to the view function. Root builds the | ||
| 25 | // application element; Diagnostics reports identity problems in debug builds. | 25 | // application element; Diagnostics reports identity problems in debug builds. | ||
| 26 | + | // Alias methods are listed by go doc github.com/bnema/nefergui/internal/ui.Frame. | |||
| 26 | type Frame = ui.Frame | 27 | type Frame = ui.Frame | ||
| 27 | 28 | ||||
| 28 | // Node is an ephemeral handle into the current frame. Do not retain it between | 29 | // Node is an ephemeral handle into the current frame. Do not retain it between | ||
| @@ -31,14 +32,20 @@ type Frame = ui.Frame | |||||
| 31 | // (Button, Checkbox, Radio, Slider, Input, Textarea, Text, Heading, Image, | 32 | // (Button, Checkbox, Radio, Slider, Input, Textarea, Text, Heading, Image, | ||
| 32 | // Icon, Separator, Spacer) declare controls. Interactive controls return event | 33 | // Icon, Separator, Spacer) declare controls. Interactive controls return event | ||
| 33 | // snapshots. | 34 | // snapshots. | ||
| 35 | + | // Alias methods are listed by go doc github.com/bnema/nefergui/internal/ui.Node. | |||
| 34 | type Node = ui.Node | 36 | type Node = ui.Node | ||
| 35 | 37 | ||||
| 36 | - | // Control event values are immutable snapshots; querying them never consumes events. | 38 | + | // ButtonEvent is an immutable snapshot queried with Activated. |
| 37 | - | type ( | 39 | + | // Alias methods are listed by go doc github.com/bnema/nefergui/internal/ui.ButtonEvent. |
| 38 | - | ButtonEvent = ui.ButtonEvent | 40 | + | type ButtonEvent = ui.ButtonEvent |
| 39 | - | EditEvent = ui.EditEvent | 41 | + | |
| 40 | - | ChangeEvent = ui.ChangeEvent | 42 | + | // EditEvent is an immutable snapshot queried with Changed and Submitted. |
| 41 | - | ) | 43 | + | // Alias methods are listed by go doc github.com/bnema/nefergui/internal/ui.EditEvent. |
| 44 | + | type EditEvent = ui.EditEvent | |||
| 45 | + | ||||
| 46 | + | // ChangeEvent is an immutable snapshot queried with Changed. | |||
| 47 | + | // Alias methods are listed by go doc github.com/bnema/nefergui/internal/ui.ChangeEvent. | |||
| 48 | + | type ChangeEvent = ui.ChangeEvent | |||
| 42 | 49 | ||||
| 43 | // Option families are sealed: ContainerOption, ButtonOption, EditOption, | 50 | // Option families are sealed: ContainerOption, ButtonOption, EditOption, | ||
| 44 | // ValueOption and HeadingOption accept the common CSS options (Key, ID, | 51 | // ValueOption and HeadingOption accept the common CSS options (Key, ID, | ||