Getting Started

July 18, 2026 · View on GitHub

You want to build a desktop app in Go. You've come to the right place


Prerequisites

Go 1.22 or newer. Check with:

go version

If you're on Linux, you also need three system packages. macOS and Windows users can skip this and feel smug:

sudo apt install libwayland-dev libxkbcommon-dev libvulkan-dev

Install

In your project directory:

go get github.com/CzaxStudio/proton
go mod tidy

The go mod tidy step is important — it pulls Gio's transitive dependencies and writes them to go.sum. Skip it and you'll see red squiggles everywhere.


Your First Window

package main

import "github.com/CzaxStudio/proton"

func main() {
    a := proton.New("hello")
    a.Window("Hello", 480, 320, func(ctx proton.Context) {
        proton.H3(ctx, "Hello from Proton!") // ⓘ You can change proton.H3 to any size you want
    })
    a.Run()
}
go run .

A window appears. That's a complete, working GUI app in 9 lines. No XML, no implements Runnable, no dependency injection framework, no webpack.


Adding State

Widgets that do something — buttons, text inputs, checkboxes — need a state field in your own struct. Declare them once, pass pointers to the widgets.

package main

import (
    "fmt"
    "github.com/CzaxStudio/proton"
)

type UI struct {
    name proton.Editor
    btn  proton.Clickable
}

func main() {
    u := &UI{}

    a := proton.New("greeter")
    a.Window("Greeter", 400, 240, func(ctx proton.Context) {
        proton.Input(ctx, &u.name, "Your name")
        proton.Gap(ctx, 8)
        proton.Pad(ctx, 4, func(ctx proton.Context) {
            if proton.Button(ctx, &u.btn, "Say hello") {
                fmt.Println("Hello,", u.name.Text())
            }
        })
    })
    a.Run()
}

The draw function runs every frame. Button returns true on the frame it gets clicked. The if block runs, prints the name, and that's it.


The State Types

Declare these in your UI struct. They're all zero-value ready — no constructors.

type UI struct {
    btn     proton.Clickable    // Button, OutlineButton, Tappable, Link
    name    proton.Editor       // Input, TextArea
    checked proton.Bool         // Checkbox, Toggle
    choice  proton.Enum         // RadioButton group
    vol     proton.Float        // Slider
    scroll  proton.Scrollable   // List, HList, Scroll, TextView, LogView
}

One field per widget. Don't share a Clickable between two buttons — they'll both fire on the same click, which is almost never what you want.


How the Layout Works

Without any layout wrappers, widgets stack vertically top to bottom. Gap adds space between them.

proton.H4(ctx, "Settings")
proton.Gap(ctx, 12)
proton.Label(ctx, "Adjust your preferences below.")
proton.Gap(ctx, 16)
proton.Divider(ctx)
proton.Gap(ctx, 16)
proton.Toggle(ctx, &u.darkMode, "Dark mode")

For side-by-side layout, use Row. For more control, see 04-layout.md.


Buttons Need a Layout Wrapper

Buttons (and other interactive widgets) must be inside a layout helper for clicks to register correctly. This is a Gio thing — the layout pass is what establishes hit areas on screen.

// correct — button is inside Pad
proton.Pad(ctx, 8, func(ctx proton.Context) {
    if proton.Button(ctx, &u.btn, "Save") {
        save()
    }
})

// also correct — button is inside Row
proton.Row(ctx,
    func(ctx proton.Context) {
        if proton.Button(ctx, &u.btn, "Save") {
            save()
        }
    },
)

If you put a button at the very top level of the draw function without any wrapper, it'll draw but won't respond to clicks. Pad(ctx, 0, ...) is the minimum wrapper if you want zero visual padding.


Theming

a := proton.New("myapp")
a.ApplyPalette(proton.NordPalette)
a.Window("App", 800, 600, draw)
a.Run()

46 palettes are built in. See 07-theming.md for all of them and for building your own with hex color codes.


Multiple Windows

a := proton.New("app")
a.Window("Main", 800, 600, drawMain)
a.Window("Settings", 400, 300, drawSettings)
a.Run() // opens both

All windows share the same *App. The process stays alive until all windows are closed.


Next Steps