帮助你编写和排查 Guigui 框架的 GUI 组件与交互逻辑。
复制安装指令,让 AI 自动完成配置 · 推荐新手
请帮我安装 askskill 上的 "using-guigui" 技能: 1. 下载 https://raw.githubusercontent.com/guigui-gui/guigui/main/.agents/skills/using-guigui/SKILL.md 2. 保存为 ~/.claude/skills/using-guigui/SKILL.md 3. 装好后重载技能,告诉我可以用了
请用 Guigui 编写一个包含标题、输入框和提交按钮的界面,并说明各组件的布局关系。
输出 Guigui 组件结构、LinearLayout 布局方案和按钮点击处理方式。
我在 Guigui 中把文本字段绑定到共享状态后,修改值没有立刻显示,请分析可能原因并给出修复建议。
解释 state 何时触发 rebuild,以及 Env 注入或事件回调的正确用法。
请用 Guigui 实现一个动态列表,支持新增、删除和点击选中条目,并说明如何处理动态子节点。
输出动态子列表实现思路、事件绑定方式和输入/键盘交互处理。
Guigui is an immediate-mode-inspired GUI framework for Go on top of Ebitengine.
"Inspired" is the key word: widgets are retained Go structs that you own and
keep across ticks, but their child tree and presentation are reconstructed
by re-running Build whenever relevant state changes — the way Compose or
SwiftUI re-run a view function. You hold the state in struct fields; the
framework decides when to rebuild, lay out, and redraw.
Read this whole file before writing widget code; the lifecycle rules below are the part people get wrong.
Freshness. Verified against Guigui at commit
4ebb3fc7(2026-06-25). Guigui is alpha and its API may change — if anything here disagrees with the source, the source wins: trust*.goin the module root and the programs underexample/over this file, and update this skill when you find drift.
guigui.DefaultWidget and overrides the
methods it needs. DefaultWidget supplies no-op defaults for every method, so
override only what matters.&w.child. Do not allocate them in
a constructor; must already be usable.var w FooUpdate,
at the app's TPS — 60×/sec by default, or whatever TPS is configured) settles
the tree: it may run Build (reconstruct the child tree), Layout
(position the children), and the Handle*Input methods an indeterminate
number of times, interleaved, until state stops changing — then calls Tick
exactly once. Rely only on these guarantees: within a pass Build precedes
Layout, and Tick runs once, last. Do not assume a fixed count of Build, Layout,
or input passes per tick, nor that an input handler runs only once before
Tick. Each frame (Ebitengine's Draw, at the display's refresh rate)
does Draw. Ticks and frames are not one-to-one — there may be more or
fewer frames than ticks — so put per-step logic in Tick, never in Draw.Build, Layout,
Tick, Draw, the Handle*Input methods, Env, …) yourself — you set fields
and register handlers, and the framework calls back. The one exception is
Measure: a parent or composite widget calls a child's Measure directly
to size it (it is what LinearLayout and the shared layout() helper do).package main
import (
"image"
"log"
"github.com/guigui-gui/guigui"
"github.com/guigui-gui/guigui/basicwidget"
)
type Root struct {
guigui.DefaultWidget
background basicwidget.Background
hello basicwidget.Text
}
func (r *Root) Build(context *guigui.Context, adder *guigui.ChildAdder) error {
adder.AddWidget(&r.background)
adder.AddWidget(&r.hello)
r.hello.SetValue("Hello, Guigui")
return nil
}
func (r *Root) Layout(context *guigui.Context, widgetBounds *guigui.WidgetBounds, layouter *guigui.ChildLayouter) {
layouter.LayoutWidget(&r.background, widgetBounds.Bounds())
layouter.LayoutWidget(&r.hello, widgetBounds.Bounds())
}
func main() {
if err := guigui.Run(&Root{}, &guigui.RunOptions{
Title: "Example",
WindowMinSize: image.Pt(480, 320),
}); err != nil {
log.Fatal(err)
}
}
guigui.Run(root, *RunOptions) starts the app. RunOptions carries Title,
WindowSize / WindowMinSize / WindowMaxSize, AppScale, and an optional
RunGameOptions passed through to Ebitengine.
Embed guigui.DefaultWidget, then override as needed:
| Method | Signature | Override when |
|---|---|---|
Build | Build(*Context, *ChildAdder) error | Almost always — declare and configure children. |
Layout | Layout(*Context, *WidgetBounds, *ChildLayouter) | You have children to position (i.e. almost always). |
…
通过无障碍树与输入注入,自动操控和观测任意 X11 图形应用。