An immediate-mode UI framework for V that stays out of your way.
Most UI frameworks want you to think about data binding, observables, and UI thread synchronization. v-gui doesn't. Your view is just a function of your state—change the state anywhere and the UI updates. No wiring. No callbacks to remember. No threading headaches.
The layout engine is inspired by Clay, a fast layout algorithm that makes flex-box style layouts simple to reason about.
V is a simple language. It deserves a simple UI framework.
Good fit if you want:
- State as plain structs, no observables
- Thread-safe UI updates from anywhere
- Code-defined layouts (no XML, no designers)
- Desktop apps, tools, data viewers, games
Maybe not if you need:
- Mature accessibility support (work in progress)
- Production mobile apps
- Native platform widgets
- Drag-and-drop UI designers
Layout
- Flex-box rows and columns
- Fit/fill/fixed sizing per axis
- Scroll containers with momentum
- Nested layouts to any depth
Widgets (30+)
- Text, inputs, textareas
- Buttons, toggles, switches, checkboxes, radio buttons
- Dropdowns, listboxes, tables, trees
- Menus, menubars, tabs, dialogs
- Progress bars, tooltips, date pickers
Rendering
- SDF-based drop shadows
- Gradient borders
- Blur effects
- Full SVG support (paths, transforms, groups, strokes)
Animation
- Tweens with easing curves
- Physics-based springs
- Automatic layout transitions
- Hero morphs between views
Text (via vglyph/Pango)
- Subpixel positioning and hinting
- Rich text with mixed styles in a single widget
- Bidirectional text, ligatures, emoji
- Full Unicode and OpenType support
Architecture
- Thread-safe state updates
- 60 FPS with 1000+ widgets
- Pure V, no C bindings in user code
import gui
@[heap]
struct App {
pub mut:
clicks int
}
fn main() {
mut window := gui.window(
state: &App{}
on_init: fn (mut w gui.Window) { w.update_view(main_view) }
)
window.run()
}
fn main_view(window &gui.Window) gui.View {
app := window.state[App]()
return gui.column(
h_align: .center
v_align: .middle
content: [
gui.text(text: '${app.clicks} clicks'),
gui.button(
content: [gui.text(text: 'Click me')]
on_click: fn (_, _, mut w gui.Window) {
w.state[App]().clicks += 1
}
),
]
)
}See GET_STARTED.md for a detailed walkthrough.
v install gui| Package | Purpose | Source |
|---|---|---|
vglyph |
Text rendering | Auto-installed with v-gui |
gg |
2D graphics | V standard library |
sokol.sapp |
Windowing and events | V standard library |
| Document | Description |
|---|---|
| GET_STARTED.md | Tutorial: first app to working knowledge |
| ARCHITECTURE.md | How v-gui works under the hood |
| LAYOUT_ALGORITHM.md | Sizing, alignment, and positioning |
| ANIMATIONS.md | Tweens, springs, and transitions |
| SVG.md | Vector graphics and icon rendering |
Generate API docs with:
v run _doc.vshThe examples/ folder contains working apps for every feature:
v run examples/get_started.v # Start here
v run examples/buttons.v # Button variants
v run examples/animations.v # Tweens and springs
v run examples/theme_designer.v # Build custom themes
v run examples/tiger.v # SVG rendering demo
v run examples/snake.v # A complete gamev-gui is in active development. Join the discussion on Discord.
Contributions welcome:
- Report bugs and request features via GitHub issues
- Submit pull requests
- Improve documentation
MIT
