Examples
July 12, 2026 · View on GitHub
Complete programs you can copy, paste, and run. Every one of these compiles and works as-is.
Hello World
The absolute minimum. Open a window, show some text.
package main
import "github.com/CzaxStudio/proton"
func main() {
a := proton.New("hello")
a.Window("Hello", 400, 200, func(ctx proton.Context) {
proton.H3(ctx, "Hello from Proton!")
})
a.Run()
}
Counter
A number that goes up and down when you click buttons. Demonstrates the fundamental pattern: state in a struct, buttons inside layout wrappers.
package main
import (
"fmt"
"github.com/CzaxStudio/proton"
)
type UI struct {
count int
inc proton.Clickable
dec proton.Clickable
reset proton.Clickable
}
func main() {
u := &UI{}
a := proton.New("counter")
a.ApplyPalette(proton.NordPalette)
a.Window("Counter", 320, 240, func(ctx proton.Context) {
proton.Center(ctx, func(ctx proton.Context) {
proton.H1(ctx, fmt.Sprintf("%d", u.count))
proton.Gap(ctx, 20)
proton.Row(ctx,
func(ctx proton.Context) {
proton.Pad(ctx, 4, func(ctx proton.Context) {
if proton.OutlineButton(ctx, &u.dec, "−") {
u.count--
}
})
},
func(ctx proton.Context) { proton.Gap(ctx, 8) },
func(ctx proton.Context) {
proton.Pad(ctx, 4, func(ctx proton.Context) {
if proton.Button(ctx, &u.inc, "+") {
u.count++
}
})
},
func(ctx proton.Context) { proton.Gap(ctx, 8) },
func(ctx proton.Context) {
proton.Pad(ctx, 4, func(ctx proton.Context) {
if proton.OutlineButton(ctx, &u.reset, "Reset") {
u.count = 0
}
})
},
)
})
})
a.Run()
}
Todo List
The demo that every UI framework is required to have by law.
package main
import "github.com/CzaxStudio/proton"
type item struct {
text string
done proton.Bool
}
type UI struct {
input proton.Editor
addBtn proton.Clickable
items []item
scroll proton.Scrollable
}
func main() {
u := &UI{}
a := proton.New("todo")
a.ApplyPalette(proton.CatppuccinPalette)
a.Window("Todo", 420, 560, func(ctx proton.Context) {
proton.H4(ctx, "Todo")
proton.Gap(ctx, 12)
// add row
proton.GrowRow(ctx,
proton.GrowItem(ctx, func(ctx proton.Context) {
proton.Input(ctx, &u.input, "What needs doing?")
}),
proton.FixedItem(ctx, func(ctx proton.Context) { proton.Gap(ctx, 8) }),
proton.FixedItem(ctx, func(ctx proton.Context) {
proton.Pad(ctx, 4, func(ctx proton.Context) {
if proton.Button(ctx, &u.addBtn, "Add") {
if t := u.input.Text(); t != "" {
u.items = append(u.items, item{text: t})
u.input.SetText("")
}
}
})
}),
)
proton.Gap(ctx, 8)
proton.Divider(ctx)
proton.Gap(ctx, 8)
if len(u.items) == 0 {
proton.Center(ctx, func(ctx proton.Context) {
proton.Muted(ctx, "Nothing here. Add something above.")
})
return
}
proton.List(ctx, &u.scroll, len(u.items), func(ctx proton.Context, i int) {
proton.PadV(ctx, 6, func(ctx proton.Context) {
proton.Checkbox(ctx, &u.items[i].done, u.items[i].text)
})
})
})
a.Run()
}
Login Form
A form with email/password fields and inline validation.
package main
import (
"strings"
"github.com/CzaxStudio/proton"
)
type UI struct {
email proton.Editor
password proton.Editor
submit proton.Clickable
errMsg string
success bool
}
func main() {
u := &UI{}
a := proton.New("login")
a.ApplyPalette(proton.MidnightPalette)
a.Window("Sign In", 400, 360, func(ctx proton.Context) {
proton.Center(ctx, func(ctx proton.Context) {
proton.MaxWidth(ctx, 300, func(ctx proton.Context) {
proton.H4(ctx, "Sign In")
proton.Gap(ctx, 24)
proton.Label(ctx, "Email")
proton.Gap(ctx, 4)
proton.Input(ctx, &u.email, "you@example.com")
proton.Gap(ctx, 12)
proton.Label(ctx, "Password")
proton.Gap(ctx, 4)
proton.Input(ctx, &u.password, "password")
proton.Gap(ctx, 8)
proton.ErrorText(ctx, u.errMsg)
if u.errMsg != "" {
proton.Gap(ctx, 6)
}
if u.success {
proton.SuccessText(ctx, "Signed in successfully!")
return
}
proton.Pad(ctx, 4, func(ctx proton.Context) {
if proton.Button(ctx, &u.submit, "Sign In") {
u.errMsg = validate(u.email.Text(), u.password.Text())
if u.errMsg == "" {
u.success = true
}
}
})
})
})
})
a.Run()
}
func validate(email, password string) string {
if !strings.Contains(email, "@") {
return "Enter a valid email address."
}
if len(password) < 8 {
return "Password must be at least 8 characters."
}
return ""
}
Settings Panel
Toggles, radio buttons, a slider, and a save button. The kind of panel that lives in every app.
package main
import (
"fmt"
"github.com/CzaxStudio/proton"
)
type Settings struct {
notifications proton.Bool
darkMode proton.Bool
language proton.Enum
fontSize proton.Float
saveBtn proton.Clickable
toast proton.ToastState
}
import "time"
func main() {
s := &Settings{}
s.fontSize.Value = 0.5
a := proton.New("settings")
a.ApplyPalette(proton.DraculaPalette)
a.Window("Settings", 480, 520, func(ctx proton.Context) {
proton.H4(ctx, "Settings")
proton.Gap(ctx, 24)
proton.H6(ctx, "Appearance")
proton.Gap(ctx, 10)
proton.Toggle(ctx, &s.darkMode, "Dark mode")
proton.Gap(ctx, 8)
proton.Label(ctx, fmt.Sprintf("Font size: %.0f%%", 80+s.fontSize.Value*40))
proton.Gap(ctx, 4)
proton.Slider(ctx, &s.fontSize)
proton.Gap(ctx, 24)
proton.H6(ctx, "Notifications")
proton.Gap(ctx, 10)
proton.Checkbox(ctx, &s.notifications, "Email notifications")
proton.Gap(ctx, 24)
proton.H6(ctx, "Language")
proton.Gap(ctx, 10)
proton.RadioButton(ctx, &s.language, "en", "English")
proton.Gap(ctx, 6)
proton.RadioButton(ctx, &s.language, "es", "Español")
proton.Gap(ctx, 6)
proton.RadioButton(ctx, &s.language, "fr", "Français")
proton.Gap(ctx, 28)
proton.RowEnd(ctx,
func(ctx proton.Context) {
proton.Pad(ctx, 4, func(ctx proton.Context) {
if proton.Button(ctx, &s.saveBtn, "Save Settings") {
s.toast.Show("Settings saved.", 2*time.Second)
}
})
},
)
proton.Toast(ctx, &s.toast)
})
a.Run()
}
App With Logo
Load a logo from an embedded file and display it in the header.
package main
import (
_ "embed"
"fmt"
"time"
"github.com/CzaxStudio/proton"
)
//go:embed logo.png
var logoBytes []byte
type UI struct {
count int
btn proton.Clickable
toast proton.ToastState
}
func main() {
u := &UI{}
a := proton.New("logoapp")
a.ApplyPalette(proton.NordPalette)
a.SetLogoBytes(logoBytes)
a.Window("My App", 420, 300, func(ctx proton.Context) {
// header with logo
proton.Row(ctx,
func(ctx proton.Context) { proton.Logo(ctx, 36, 36) },
func(ctx proton.Context) { proton.Gap(ctx, 10) },
func(ctx proton.Context) { proton.H5(ctx, "My App") },
)
proton.Gap(ctx, 16)
proton.Divider(ctx)
proton.Gap(ctx, 16)
proton.Label(ctx, fmt.Sprintf("Button clicked %d times", u.count))
proton.Gap(ctx, 10)
proton.Pad(ctx, 4, func(ctx proton.Context) {
if proton.Button(ctx, &u.btn, "Click me") {
u.count++
if u.count%5 == 0 {
u.toast.Show(fmt.Sprintf("%d clicks!", u.count), 2*time.Second)
}
}
})
proton.Toast(ctx, &u.toast)
})
a.Run()
}
Place logo.png in the same directory as main.go before running.
Two-Pane App
A resizable sidebar/content split — the layout pattern behind most desktop apps.
package main
import "github.com/CzaxStudio/proton"
type UI struct {
split proton.ResizeSplitState
scroll proton.Scrollable
rowBtns [10]proton.Clickable
selected int
saveBtn proton.Clickable
editor proton.Editor
toast proton.ToastState
}
var items = []string{
"Project Alpha", "Project Beta", "Project Gamma",
"Meeting Notes", "Ideas", "Backlog",
}
import "time"
func main() {
u := &UI{selected: 0}
u.editor.SetText("Select an item on the left to edit it.")
a := proton.New("twopane")
a.ApplyPalette(proton.TokyoNightPalette)
a.Window("Two-Pane App", 700, 500, func(ctx proton.Context) {
proton.ResizeSplit(ctx, &u.split, 0.30,
func(ctx proton.Context) {
proton.H6(ctx, "Items")
proton.Gap(ctx, 8)
proton.List(ctx, &u.scroll, len(items), func(ctx proton.Context, i int) {
bg := proton.RGB(0x1a1b26)
hov := proton.RGB(0x24283b)
if u.selected == i {
bg = proton.RGB(0x364a82)
hov = bg
}
proton.PadV(ctx, 2, func(ctx proton.Context) {
if proton.HoverCard(ctx, &u.rowBtns[i], bg, hov, 5, func(ctx proton.Context) {
proton.PadV(ctx, 8, func(ctx proton.Context) {
proton.PadH(ctx, 10, func(ctx proton.Context) {
proton.Label(ctx, items[i])
})
})
}) {
u.selected = i
}
})
})
},
func(ctx proton.Context) {
proton.PadH(ctx, 14, func(ctx proton.Context) {
proton.RowSpread(ctx,
func(ctx proton.Context) { proton.H6(ctx, items[u.selected]) },
func(ctx proton.Context) {
proton.Pad(ctx, 4, func(ctx proton.Context) {
if proton.Button(ctx, &u.saveBtn, "Save") {
u.toast.Show("Saved.", 2*time.Second)
}
})
},
)
proton.Gap(ctx, 12)
proton.GrowColumn(ctx,
proton.GrowItem(ctx, func(ctx proton.Context) {
proton.TextArea(ctx, &u.editor, "Write something...")
}),
)
})
},
)
proton.Toast(ctx, &u.toast)
})
a.Run()
}
Running the Built-in Examples
The repo ships with 9 complete example apps:
go run ./examples/hello # one window, one label
go run ./examples/todo # todo list
go run ./examples/calculator # grid of buttons, math
go run ./examples/notes # note-taking with search and modal delete
go run ./examples/dashboard # dev dashboard: charts, logs, tables
go run ./examples/showcase # every widget in 5 tabs
go run ./examples/themes # live palette picker + preview
go run ./examples/logoapp # custom logo with go:embed
go run ./examples/kitchen # stress test for all features
Run showcase first — it's the most complete visual demonstration of what
Proton can do.