shirei

package module
v0.6.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 17, 2026 License: Zlib Imports: 42 Imported by: 0

README

Shirei

Shirei is a cross-platform GUI framework for Go, designed as a lightweight alternative to web-based approaches, with a focus on development ergonomics.

  • Build the UI in pure Go, instead of HTML and Javascript
  • Describe the UI as a function of state, instead of creating and maintaining widget objects
  • Use the good parts from the web: uniform container tree, flexbox-like layout
  • Custom components can retain internal state that the caller does not have to care about
func ProfileForm(profile *Profile) {
    Container(Attrs(Expand, Pad(18), Gap(8)), func() {
        Label("Profile", FontSize(22),
            FontWeight(WeightBold))

        Label("Name")
        TextInput(&profile.Name)

        Label("Email")
        TextInput(&profile.Email)

        Container(Attrs(Row, CrossMid, Gap(10)), func() {
            if Button(SymITick, "Save") {
                profile.Saved = true
            }
            if profile.Saved {
                Label("All changes saved",
                    FontSize(12),
                    TextColor(145, 55, 34, 1))
            }
        })
    })
}

Suitable for a wide range of utility applications.

If you find yourself resorting to TUI frameworks because you dread using Electron, give Shirei a try.

※ "Shirei" is derived from the Japanese pronunciation of "Simple Layout": シンプル・レイアウト → シレイ

Shirei supports all major platforms:

  • Windows
  • macOS
  • Linux (Wayland, X11)
  • iOS (iPhone)
  • Android

We have several example programs in this repo:

Git History: quickly verify commit history (linearly)

git_history

Haystack: very fast "find in files"

haystack

Piano: simple keyboard piano

piano

Process Monitor: quickly check how running processes are using CPU/RAM

process monitor

Running a program is as easy as go run . or go run ./pkg.

We ship shirei_mobilerun to quickly run apps on Mobile phones.

We also ship shirei_bundle to manage creating release bundles for all supported target platforms.

Cross compilation works for most platforms without CGO. The exception is macOS and iOS.

Motivation

There are several approaches to creating UIs, and it has been this author's consistent experience that the declarative (immediate mode) provides the most flexibility and power for the least effort, compared to other approaches.

When we say "immediate mode", we're not talking about the rendering mechanism, rather we are talking about the API: do you "retain" widgets in your application code, or do you just say what the UI should look like right now, given application state?

Existing GUI frameworks in Go all seem to require you to retain widgets yourself, even ones that say they are immediate mode.

Shirei combines two powerful ideas:

  • Build the UI using regular code constructs, and respond to input without callbacks
  • Automatically size and layout elements based on a flexbox-like system

Why use Shirei:

  • Produce small native binaries, ≈10MB is typical for binary size.

  • Performance and resource usage is a first class design consideration.

  • Easy to learn API & fast iteration cycle for both humans and AI.

  • Simpler UI code, focus on program data, not widget objects.

  • Flexbox layout model means you have full freedom in arranging styled container trees to build custom UIs and components.

  • Batteries included: default widgets, robust text editing, virtual lists, tables, modals.

  • International text support: unlike what you might expect from imgui libraries from C/C++, Shirei supports complex text shaping and bidirectional layout, input method editor (IME) for East Asian languages, and ability to use all system fonts.

  • Snapshot testing: render the normal application frame to an image without opening a native window or requiring a GPU.

Limitations

  • Shirei apps only have one window with standard decorations
  • Accessibility support not available yet, but planned before v1.0
  • No GPU surfaces at this time; under consideration

Getting started

Copy this into main.go in a new folder:

package main

import (
	"fmt"

	app "go.hasen.dev/shirei/app"

	. "go.hasen.dev/shirei"
	. "go.hasen.dev/shirei/widgets"
)

func main() {
	app.SetupWindow("My App", 300, 100)
	app.Run(RootView)
}

var count int

func RootView() {
	Container(Attrs(Viewport, Background(220, 10, 97, 1)), func() {
		Container(Attrs(Row, CrossMid, Pad(20), Gap(10)), func() {
			Label(fmt.Sprintf("Counter: %d", count))
			if Button(SymIPlus, "Increment") {
				count++
			}
		})
	})
}

Then type:

$ go mod init main
$ go mod tidy
$ go run .

You should see a window like this:

Tools

Install the companion CLIs (puts binaries on $(go env GOPATH)/bin — keep that on your PATH):

go install go.hasen.dev/shirei/cmd/shirei_mobilerun@latest
go install go.hasen.dev/shirei/cmd/shirei_bundle@latest
Command Role
shirei_mobilerun Dev installs on iOS / Android (debug signing, fast iteration)
shirei_bundle Release packaging (IPA, release APK, macOS zip/pkg, desktop archives)

Learn

Documentation

Index

Constants

View Source
const (
	KeyCodeNone KeyCode = iota

	KeyLeft = 128 + iota
	KeyRight
	KeyUp
	KeyDown
	KeyEnter
	KeyEscape
	KeyHome
	KeyEnd
	KeyDeleteBackward
	KeyDeleteForward
	KeyPageUp
	KeyPageDown
	KeyTab
	KeySpace
	KeyCtrl
	KeyShift
	KeyAlt
	KeySuper
	KeyCommand

	KeyF1
	KeyF2
	KeyF3
	KeyF4
	KeyF5
	KeyF6
	KeyF7
	KeyF8
	KeyF9
	KeyF10
	KeyF11
	KeyF12
	KeyBack
	KeyInsert
)
View Source
const (
	HUE        = 0
	SATURATION = 1
	LIGHT      = 2
	ALPHA      = 3
)
View Source
const (
	SnapMatch    = "match"
	SnapMismatch = "mismatch"
	SnapCreated  = "created"
	SnapUpdated  = "updated"
	SnapSkip     = "skip"
)

SnapResult statuses (also SnapEvent.Status).

View Source
const DefaultTextSize = 12
View Source
const EnvSnapReport = "SHIREI_SNAP_REPORT"

EnvSnapReport is the path to an append-only JSONL file of SnapEvent lines.

View Source
const HeadlessScale float32 = 2

HeadlessScale is the device-pixel ratio used by RenderToImage / RenderToPNG (2 = retina). Layout sizes stay in logical points; output bitmaps are scale times larger so text and edges stay sharp when viewed on HiDPI displays or scaled down in docs.

View Source
const LOG_FONTS = false
View Source
const MaxTouches = 10

MaxTouches is the fixed capacity of ui.Host.Input.Touches and ui.Host.FrameInput began/ended id lists. Enough for phone and typical iPad multi-touch; backends drop contacts beyond this.

View Source
const PAD_BOTTOM = 2
View Source
const PAD_LEFT = 3
View Source
const PAD_RIGHT = 1
View Source
const PAD_TOP = 0
View Source
const StretchCondensed = font.StretchCondensed
View Source
const StretchExpanded = font.StretchExpanded
View Source
const StretchExtraCondensed = font.StretchExtraCondensed
View Source
const StretchExtraExpanded = font.StretchExtraExpanded
View Source
const StretchNormal = font.StretchNormal
View Source
const StretchSemiCondensed = font.StretchSemiCondensed
View Source
const StretchSemiExpanded = font.StretchSemiExpanded
View Source
const StretchUltraCondensed = font.StretchUltraCondensed
View Source
const StretchUltraExpanded = font.StretchUltraExpanded
View Source
const StyleItalic = font.StyleItalic
View Source
const StyleNormal = font.StyleNormal
View Source
const WeightBlack = font.WeightBlack
View Source
const WeightBold = font.WeightBold
View Source
const WeightExtraBold = font.WeightExtraBold
View Source
const WeightExtraLight = font.WeightExtraLight
View Source
const WeightLight = font.WeightLight
View Source
const WeightMedium = font.WeightMedium
View Source
const WeightNormal = font.WeightNormal
View Source
const WeightSemibold = font.WeightSemibold
View Source
const WeightThin = font.WeightThin

Variables

View Source
var (
	PixelOrderBGRA = [4]uint8{2, 1, 0, 3}
	PixelOrderRGBA = [4]uint8{0, 1, 2, 3}
)

Soft-renderer framebuffer channel layouts (see Host.PixelOrder).

View Source
var (
	// ScaleMotionIdle is how long the requested device size must stay unchanged
	// before ScaleIdleFilter is used. While size is moving (or just moved),
	// ScaleMotionFilter is used instead.
	ScaleMotionIdle = 120 * time.Millisecond

	// ScaleMotionQuantize rounds dw/dh to this step during motion (0 = off).
	// Idle frames always use the exact size.
	ScaleMotionQuantize = 0

	// ScaleIdleFilter is the resampler when size is stable (exact dw/dh).
	ScaleIdleFilter = transform.Linear

	// ScaleMotionFilter is the resampler while size is moving.
	ScaleMotionFilter = transform.NearestNeighbor
)

Tunables for interactive resize. Flip these while profiling:

ScaleMotionIdle = 0            → always ScaleIdleFilter
ScaleMotionQuantize = 0        → no size rounding during motion
ScaleMotionQuantize = 8        → round dw/dh to 8px while moving
View Source
var (
	DoubleClickInterval         = 400 * time.Millisecond
	DoubleClickSlop     float32 = 6
)

Double-click detection tunables (package-level process knobs, not per-UI).

View Source
var DEBUG_ENV = envTruthy("DEBUG")
View Source
var Monospace = []string{"Noto Sans Mono", "SF Mono", "Menlo", "Monaco", "Terminus", "Consolas", "Lucida Console"}
View Source
var SelectionColor = Vec4{220, 50, 70, 0.5}

the background color of selected text

View Source
var ShapeStats struct {
	Calls int64
	Hits  int64
}

ShapeStats counts ShapeText invocations vs cache hits — the diagnostic for shape-cache effectiveness. In steady state (no text changing between frames) hits should track calls; a persistent gap means the UI is paying harfbuzz every frame. Pinned by see_pprof's TestShapeCacheSteadyState.

Functions

func Absf32

func Absf32(x float32) float32

Absf32 returns the absolute value of x.

func AutoFocus

func AutoFocus()

grab focus if this is our first render and nothing else is focused

func Behind

func Behind(a *AttrSet)

Behind draws this container behind its siblings (z = -1).

func Blur

func Blur()

Blur gives up the current container's pending focus, unless another container has already requested focus this frame.

func CapAbove

func CapAbove[T cmp.Ordered](v *T, f T)

CapAbove raises *v to f when it is below f, so *v ends up no less than f.

func CapBelow

func CapBelow[T cmp.Ordered](v *T, c T)

CapBelow lowers *v to c when it exceeds c, so *v ends up no greater than c.

func CaretHeightForStyle added in v0.6.7

func CaretHeightForStyle(style TextStyleAttrs) f32

CaretHeightForStyle is the caret bar height for a uniform run of style: pen baseline (glyphBaselineFrac × em) plus the face's descender depth. Falls back to the em when the face has no descender metrics.

func Center

func Center(a *AttrSet)

Center centers children on both the main and cross axes.

func ClampColorVec

func ClampColorVec(v *Vec4)

func ClearFocus

func ClearFocus()

ClearFocus drops keyboard focus immediately (this frame). Use when a parent wants to dismiss child focus (e.g. Escape blurring a field).

func ClickThrough

func ClickThrough(a *AttrSet)

ClickThrough lets pointer events pass through this container to whatever is beneath it. Cascades to unset descendants; use NoClickThrough on a child to opt back into hit-testing (e.g. a toast card inside a ClickThrough overlay).

func Clip

func Clip(a *AttrSet)

Clip constrains children — both their drawing and their pointer events — to this container's bounds. Attrs() enables this by default; Clip is kept as an explicit no-op setter for call sites and for Viewport.

func ComfortScale added in v0.6.0

func ComfortScale() float32

ComfortScale returns Host.ComfortScale for the active UI. Widget defaults multiply design-unit sizes by this (see Host.ComfortScale). Always a real multiplier — backends and defaultHost set it to 1; do not treat 0 as 1.

func CrossMid

func CrossMid(a *AttrSet)

CrossMid centers children on the cross axis — shorthand for CrossAlign(AlignMiddle).

func CycleFocusOnTab

func CycleFocusOnTab()

CycleFocusOnTab moves focus to the next focusable container (or the previous one, with Shift) when the current container has focus and Tab is pressed. Call it so you don't have to wire up tab navigation yourself.

func DebugMessage added in v0.6.5

func DebugMessage(msg string)

DebugMessage adds a line of text to the debug overlay for this frame. It is a no-op when DebugPanel isn't being called, so messages don't accumulate.

func DebugPanel added in v0.6.5

func DebugPanel()

DebugPanel draws the floating, draggable debug overlay holding the messages collected via DebugMessage and DebugVar this frame (when show is true), then clears them for the next frame. Call it once per frame, typically at the end of your UI.

func DebugVar added in v0.6.5

func DebugVar(name string, value any)

DebugVar adds a "name: value" line to the debug overlay, formatting value as compact JSON.

func DeleteHookedData

func DeleteHookedData(data any, itemKey any)

DeleteHookedData releases the data-hook state that UseData created for the given (data, itemKey) pair.

func DirListing

func DirListing(path string) []os.DirEntry

DirListing returns the entries of a directory. Results are cached and kept fresh by a filesystem watcher, so it's cheap to call every frame. It is an immediate-mode call, meant to run during rendering (under the frame lock).

func Expand

func Expand(a *AttrSet)

Expand stretches this container to fill the parent's cross axis.

func Extrinsic

func Extrinsic(a *AttrSet)

Extrinsic makes the container's size independent of its content, so it takes its size from its constraints rather than growing to fit what's inside.

func FallbackFontFor

func FallbackFontFor(ch rune, aspect FontAspect) (FontId, GlyphId)

FallbackFontFor picks a registered face that covers ch when the caller's family list does not. It walks a script-specific name list (then a short last-resort list), probes cmap before a full parse, and memos the answer including misses. fontLookupEpoch invalidates the memo when new faces appear.

func FirstRender

func FirstRender() bool

FirstRender reports whether the current container is being built for the first time — it has no previous-frame data yet, making this the place for one-time setup.

func FloatHSLToRGB

func FloatHSLToRGB(h f32, s f32, l f32) (f32, f32, f32)

FloatHSLToRGB converts HSL (each component in 0..1) to RGB (each in 0..1). Adapted from https://github.com/alessani/ColorConverter/blob/master/ColorSpaceUtilities.h

func Focus

func Focus()

Focus requests keyboard focus for the current container; the change takes effect as the frame is committed.

func FocusImmediateOn

func FocusImmediateOn(id ContainerId)

FocusImmediateOn moves keyboard focus to the container with the given handle immediately (this frame), if the handle is valid.

func FocusOnClick

func FocusOnClick()

returns true if focus was received now

func FocusTrap

func FocusTrap(a *AttrSet)

func Focusable

func Focusable(a *AttrSet)

Focusable allows this container to receive keyboard focus.

func FontParsed

func FontParsed(id FontId) bool

FontParsed reports whether this face's parsed tables are currently resident. File-backed faces are dropped at the end of each frame (shape and glyph caches keep drawing); a later GetParsedFont re-reads the file.

func FontWarmed added in v0.6.7

func FontWarmed(id FontId) bool

FontWarmed reports whether this face has been parsed at least once. Fontviewer uses this so a card that already shaped does not fall back to a skeleton after the frame-end unload.

func FrameRequested

func FrameRequested() bool

FrameRequested reports whether another frame has been requested; backends check it to decide whether to keep rendering or go idle.

func GetFrameNumber added in v0.6.0

func GetFrameNumber() int64

GetFrameNumber returns the current frame-pass counter (advances on every RunFrameFn pass, including settle). Useful for per-frame caches on hooks.

func GlyphOutline

func GlyphOutline(fontId FontId, glyphId GlyphId) font.GlyphOutline

GlyphData re-parses the glyf/CFF/sbix tables on every call, so we memoize the extracted outline per (font, glyph). The result is immutable vector data, shared by every backend.

func GlyphWidth

func GlyphWidth(fontId FontId, glyphId GlyphId) float32

func HSLAColor

func HSLAColor(c Vec4) color.NRGBA

HSLAColor converts an HSLA color — hue in 0..360, saturation and lightness in 0..100, alpha in 0..1 — to a Go image/color.NRGBA.

func HasFocus

func HasFocus() bool

HasFocus reports whether the current container holds keyboard focus.

func HasFocusWithin

func HasFocusWithin() bool

HasFocusWithin reports whether the current container, or any of its descendants, holds keyboard focus.

func Hash

func Hash[T any](h *xxhash.Digest, v *T)

Hash writes the raw in-memory bytes of *v into the digest. Intended for small plain values; it hashes the memory representation, so results are not portable across architectures.

func HashSlice

func HashSlice[T any](h *xxhash.Digest, v []T)

HashSlice writes the raw in-memory bytes of the slice's elements into the digest.

func HashString

func HashString(h *xxhash.Digest, s string)

HashString writes the bytes of s into the digest.

func HashStringHeader

func HashStringHeader(h *xxhash.Digest, s string)

HashStringHeader writes s's data pointer and length — not its bytes — into the digest. This is an identity hash: two strings sharing backing storage hash equal, but equal content in separate allocations does not.

func IdHasFocus

func IdHasFocus(id ContainerId) bool

IdHasFocus reports whether the container with the given handle holds keyboard focus.

func IdIsClicked

func IdIsClicked(id ContainerId) bool

IdIsClicked reports whether the container with the given handle was clicked this frame.

func IdIsHovered

func IdIsHovered(id ContainerId) bool

IdIsHovered reports whether the pointer is over the container with the given handle (anywhere in its hover stack, not necessarily on top).

func IdReceivedFocusNow

func IdReceivedFocusNow(id ContainerId) bool

IdReceivedFocusNow reports whether the container with the given handle gained focus on this frame.

func Image

func Image(fpath string, maxSize Vec2)

Image renders the image at fpath as a leaf of the current container, scaled to fit within maxSize while preserving its aspect ratio.

func ImageView

func ImageView(id ImageId, maxSize Vec2)

ImageView displays a registered image, scaled down (never up) to fit within maxSize. The zero ImageId renders nothing. Touches the id so a view that still uses a held handle is not reclaimed mid-session; prefer re-UseImage by key each frame when possible.

func ImageViewAt added in v0.6.5

func ImageViewAt(id ImageId, size Vec2)

ImageViewAt draws id in a fixed logical box of size (fills the box; the soft-renderer ImageScale path maps image pixels onto this surface). For a 1:1 device blit (no Kernel.Scale), register pixels at size × Host.WindowScale.

func InFront

func InFront(a *AttrSet)

InFront draws this container in front of its siblings (z = 1).

func InitFontSubsystem

func InitFontSubsystem()

InitFontSubsystem loads a small critical face set synchronously (hard-coded likely paths per GOOS), then walks the rest of the system font dirs on a background goroutine. Package init runs it when shirei is imported. Safe to call explicitly; later calls are no-ops.

func IsActive

func IsActive() bool

IsActive reports whether the current container is the active one — the target that captured the pointer on mouse-down and is holding it until release.

func IsClicked

func IsClicked() bool

IsClicked reports whether the current container was clicked this frame — it is hovered and the mouse went down.

func IsDoubleClicked

func IsDoubleClicked() bool

IsDoubleClicked reports whether this frame's click is the second (or later) click of a streak on the current container. Note the first click of the pair fires IsClicked on its own frame — the standard select-then- escalate pattern (click selects, double-click acts) needs no special handling for that.

func IsHovered

func IsHovered() bool

IsHovered reports whether the pointer is over the current container (including when it is only under a child). Prefer this over IsHoveredDirectly for ordinary hit-testing.

func IsHoveredDirectly

func IsHoveredDirectly() bool

IsHoveredDirectly reports whether the current container is the topmost hovered container — nothing is drawn over it at the pointer. Rare: use when you care about the "whitespace" of this box specifically (e.g. a modal backdrop), not the default for buttons/keys with child chrome.

func IsIdHoveredDirectly

func IsIdHoveredDirectly(id ContainerId) bool

IsIdHoveredDirectly reports whether the container with the given handle is the topmost hovered container — nothing else is drawn over it at the pointer.

func IsTouched added in v0.6.0

func IsTouched() bool

IsTouched reports whether any active touch's hit chain includes the current container (direct hit or ancestor). Same idea as IsHovered: children (labels, chips) do not steal the touch from their parent. Prefer this for almost all multi-touch hit-testing.

func IsTouchedDirectly added in v0.6.0

func IsTouchedDirectly() bool

IsTouchedDirectly reports whether the current container is the frontmost hit for at least one active touch (no child or sibling on top). Rare — same niche as IsHoveredDirectly (e.g. "did they touch the empty backdrop, not a control drawn on it?"). Default to IsTouched.

func Label

func Label(text string, mods ...TextStyleFn)

Label renders text with the current text style plus optional call-local mods — sugar for Text(text, TextStyle(mods...)).

func LoadImageConfig

func LoadImageConfig(fpath string) image.Config

func MainCrossAxes

func MainCrossAxes(row bool) (int, int)

MainCrossAxes returns the Vec component indices of the main and cross axes: (0, 1) for a row layout, (1, 0) for a column.

func ModAttrs

func ModAttrs(fns ...func(*AttrSet))

ModAttrs applies setters to the current container's attributes. It must be called before any child is added; modifying attributes once children exist panics.

func Modal(width f32, dismiss func(), fn func())

Modal renders fn as a centered card over a dimmed scrim that blocks the UI behind it, drawn on top of everything via the popup layer. dismiss wires the universal close gestures: Escape, and a click on the scrim (outside the card). Pass nil for a modal that must be answered through its own buttons (e.g. a conflict that has no neutral outcome). Anything beyond that — Enter-to-submit, multiple choices — belongs in fn, next to the buttons it duplicates.

Modal is immediate: call it every frame while the dialog should stay open (typically `if open { Modal(...) }`).

func Nil

func Nil()

Nil adds an empty container that draws nothing.

func NoAnimate

func NoAnimate(a *AttrSet)

NoAnimate disables all animation channels on this container (Animations = 0). Marks the mask set so open-time cascade does not rewrite it. Unset children still inherit zero via cascade (&= parent).

func NoClickThrough added in v0.6.7

func NoClickThrough(a *AttrSet)

NoClickThrough opts this container into hit-testing under a ClickThrough parent. Marks the flag set so open-time cascade does not rewrite it.

func NoClip added in v0.6.5

func NoClip(a *AttrSet)

NoClip lets children draw and receive pointer events outside this container's bounds. Prefer padding (for shadows) or Popup (for overlays) when possible.

func Popup(fn func())

Popup registers fn to render at the end of the current frame, on top of the rest of the UI. Call it from anywhere while building the frame; it renders where the frame loop drains the queue (ui.popups), not where Popup is called.

A popup is not special: once PopupsHost runs its callback, the containers it builds are ordinary containers. Layout, hover, and the settle/second-pass mechanism all apply without special casing, because the queue is drained inside the frame build and re-populated on every pass.

While a popup callback runs, outermost floating containers with unset Z (0) pick up ui.popupZ so later drains paint above earlier ones. Nested floats under an already-floating ancestor keep Z=0 so decoration fills still paint under labels (menu hover, text selection, …).

func PopupsHost

func PopupsHost()

PopupsHost drains the popup queue until empty. The frame loop calls this automatically after the app's frame function, in the same container scope the frame ran in — applications do not call it.

Frame popup sources run first (they may append to the queue). Then an index loop drains until empty so popups appended during a callback still run. ui.popupZ is that index (1-based) for the duration of each callback.

func PostCommand

func PostCommand(widget string, key any, name string, arg any)

PostCommand queues a command for a widget instance. It does NOT wake the loop eagerly: at post time it can't know whether the consumer builds later this same frame (no follow-up needed) or earlier (needs the next frame). That is decided at frame end by pendingCommandNeedsNextFrame, so a command consumed same-frame — the common case when the poster builds before its consumer — costs no wake. This is what lets an app post a standing query every frame and still go idle.

A command posted OUTSIDE a frame (a background goroutine under the frame lock) can't be caught by the end-of-frame check, so it wakes the loop directly.

func PressAction

func PressAction() bool

PressAction reports a completed click gesture on the current container: it becomes active on mouse-down while hovered and returns true when the button is released while still hovered — the standard button behavior.

func PrewarmFont

func PrewarmFont(id FontId)

PrewarmFont parses one face ahead of time so a later shape/render finds it ready. The file read and parse run OFF the registry lock; only the publish is done under it. A collection (.ttc) sibling is not parsed until asked for.

Call it from a background goroutine. No-op if the font is already parsed or the id is invalid.

func ReadFileContent

func ReadFileContent(fpath string) []byte

ReadFileContent returns the bytes of a file, cached and invalidated when the file changes. A small file is read immediately; a large file is read on a background goroutine, so the first call returns nil and its content appears on a later frame (via RequestNextFrame when the read finishes).

func ReceivedFocusNow

func ReceivedFocusNow() bool

ReceivedFocusNow reports whether the current container gained focus on this frame — it is focused now but was not on the previous frame.

func RectContainsPoint

func RectContainsPoint(r Rect, p Vec2) bool

RectContainsPoint reports whether p lies inside r, with the left and top edges inclusive and the right and bottom edges exclusive.

func RegisterFramePopup added in v0.6.7

func RegisterFramePopup(fn func())

RegisterFramePopup adds fn to run at the start of every PopupsHost drain. Typical use: retain a message or flag in package state, and from fn call Popup while that state is live.

func RenderToImage

func RenderToImage(width, height int, fn FrameFn) *image.RGBA

RenderToImage runs fn headlessly at the given logical size and software-renders the settled frame — the engine behind RenderToPNG, and directly useful for snapshot tests that compare in memory. Not meant to run alongside a live window: it overwrites Host.WindowSize / WindowScale.

Output is HeadlessScale device pixels per logical point (retina by default).

It runs at least two frames, then keeps going (capped) while the frame requests a follow-up: widgets that size themselves from previous-frame data — virtual lists, GetResolvedSize users — need the extra passes to settle. The cap keeps self-rerendering content (e.g. a focused text input's blinking caret) from looping forever; NoAnimate is forced so animations don't count against it.

func RenderToPNG

func RenderToPNG(path string, width, height int, fn FrameFn) error

RenderToPNG runs fn headlessly at the given logical size and writes the software-rendered result to path — the standard way to verify UI changes without opening a window (apps typically expose it as a --png flag; see cocoabackend/example and examples/see_pprof). The PNG is HeadlessScale device pixels per logical point (same as RenderToImage).

func ReportSnap added in v0.6.5

func ReportSnap(testName string, r SnapResult)

ReportSnap appends one SnapEvent when SHIREI_SNAP_REPORT is set. testName is stored in SnapEvent.Test (pass testing.T.Name() from go test).

func RequestNextFrame

func RequestNextFrame()

RequestNextFrame asks the backend to render another frame after this one, even if no input arrives — used by animations and by state that settles over several frames.

func RequestOpenURL added in v0.6.0

func RequestOpenURL(url string)

RequestOpenURL asks the backend to open url in the system browser (or the scheme's handler) after the frame. Empty url is ignored; last write wins. Errors are ignored for now (backends may later report via Host if needed).

func RequestPaste

func RequestPaste()

RequestPaste requests the system clipboard's text, delivered as input on a subsequent frame.

func RequestStabilize added in v0.6.5

func RequestStabilize()

func RequestTextCopy

func RequestTextCopy(text string)

RequestTextCopy places text on the system clipboard at the end of the frame.

func ResetInputSession

func ResetInputSession()

ResetInputSession restores the neutral input/focus state of a freshly launched app: mouse parked offscreen (nothing hovered), no pending input, nothing focused or active. Headless render sessions (RenderToImage, snapshot tests, benchmarks) call it so repeated invocations in one process don't leak the previous invocation's mouse position or focus — e.g. a stale nextFocused pointing at a dead container silently suppresses AutoFocus in the next invocation.

func Roundf32

func Roundf32(x f32) f32

Roundf32 rounds x to the nearest integer, returned as a float32.

func Row

func Row(a *AttrSet)

Row arranges children horizontally (left to right) instead of the default vertical column.

func SafeTruncateUTF8

func SafeTruncateUTF8(s string, limit int) string

Generated by ChatGPT (initially)

func ScaleFactor

func ScaleFactor(fontId FontId) float32

func ScrollOnInput

func ScrollOnInput()

ScrollOnInput scrolls the current container by this frame's wheel input when it is hovered, clamped to the container's scrollable range.

func SetScrollOffset

func SetScrollOffset(offset Vec2)

SetScrollOffset records the desired scroll offset as-is; layout clamps it against THIS frame's content and available size once both are known (see resolveOrigins), and the clamped value is what the frame renders with and commits. Clamping here would have to use previous-frame data — which silently wiped offsets restored onto containers whose previous frame had no content yet (a list rebuilt on tab switch).

func ShapedTextLayout

func ShapedTextLayout(shaped ShapedText, style TextStyleAttrs, selectionFrom int, selectionTo int, spans ...StyleSpan)

func ShapedTextLineLayout

func ShapedTextLineLayout(line *ShapedTextLine, style TextStyleAttrs, spans []StyleSpan, baseDir Direction, selectionFrom int, selectionTo int, nextLinePaddingTop *f32)

func SnapAbsPath added in v0.6.5

func SnapAbsPath(path string) string

SnapAbsPath resolves path relative to the process working directory to an absolute path for display and the report file.

func TakeCommand

func TakeCommand[T any](widget string, key any, name string) (T, bool)

TakeCommand consumes a pending command, returning its argument as T. Absent → zero, false. An argument of the wrong type is a program bug: reported on stderr (like duplicate ids), consumed, and returned as zero, false.

func Text

func Text(label string, style TextStyleAttrs, spans ...TextSpan)

Text renders a run of text as a leaf of the current container. style is a fully resolved paragraph base — usually TextStyle(mods...) so the current container text style is the starting point. spans are optional range styles resolved against that same base (see Span).

Soft-wrap width is the current container's content-box max width: MaxSize[0] minus horizontal padding (including a MaxSize cascaded from an ancestor). Zero MaxSize means unconstrained (no soft wrap). Matches TextInput and the MaxSize cascade peel for children.

Label is the convenience for current text style + call-local mods with no spans.

func TouchingIds added in v0.6.0

func TouchingIds(dst []uint32) []uint32

TouchingIds appends to dst the ids of touches whose hit chain includes the current container (direct or ancestor). Pass dst[:0] to reuse a buffer.

func TouchingIdsDirect added in v0.6.0

func TouchingIdsDirect(dst []uint32) []uint32

TouchingIdsDirect appends to dst the ids of touches for which the current container is the frontmost hit.

func UnsetMaxCross added in v0.6.0

func UnsetMaxCross(a *AttrSet)

UnsetMaxCross clears MaxSize on the parent's cross axis — the axis that MaxSize cascade writes (width under a column parent, height under a row) — and marks maxCrossUnset so open-time cascade does not write it back. Safe in Attrs(...) (same idea as YesAnimate under Viewport) or ModAttrs.

func Use

func Use[T any](itemKey any) *T

Use returns a pointer to per-container state of type T, keyed by itemKey and retained across frames on the current container's identity node. It is zero-valued on first use (and re-initialized after any frame in which it went untouched). This is Shirei's React-like local component state; use UseWithInit to supply a custom initializer.

func UseData

func UseData[T any](data any, itemKey any) *T

UseData attaches side state of type T to an arbitrary object, keyed by the (data, itemKey) pair. Unlike Use, data hooks persist whether or not they are touched each frame; call DeleteHookedData to release one.

func UseFontBytes

func UseFontBytes(data []byte) error

func UseFontFile

func UseFontFile(fpath string)

UseFontFile registers one font file. Equivalent to UseFontFiles(fpath).

func UseFontFiles

func UseFontFiles(fpaths ...string)

UseFontFiles registers zero or more font files as a single batch: all open/describe work runs without locks, then one publish critical section updates the face registry. Prefer this over repeated UseFontFile calls.

func UseFontsDirectories

func UseFontsDirectories(dirpaths ...string)

UseFontsDirectories walks dirpaths and registers font files in batches of fontScanBatchSize via UseFontFiles.

func UseWithDefault added in v0.6.5

func UseWithDefault[T any](itemKey any, initial T) *T

func UseWithInit

func UseWithInit[T any](itemKey any, initFn func() *T) *T

UI hook state lives on the container's identity node (stage 3; see identity.go). Retention is prune-per-frame, preserving the old double- buffered map's semantics: a slot is live if it was used last frame (or created this frame); one full unused frame and it reads as absent, so the next use re-initializes it.

func Viewport

func Viewport(a *AttrSet)

Viewport is a convenience preset for a scrolling/clipping region: it clips its content, sizes extrinsically, expands across, grows to fill the available space, and disables animation (NoAnimate — unset descendants inherit zero so scroll does not ease every child's relativeOrigin).

func Void

func Void()

Void adds an empty floating container pinned far behind everything: it draws nothing and takes no space in the normal layout flow.

func WantKeyboard added in v0.6.0

func WantKeyboard()

WantKeyboard marks that this frame wants platform text entry active.

func WithFrameLock

func WithFrameLock(fn func())

WithFrameLock runs fn while holding the frame lock, serializing it against the render loop. Background goroutines use it to mutate shared state (caches, stores) safely — they block until the current frame finishes if one is in progress.

Do not call WithFrameLock from code that already runs inside RunFrameFn (button handlers, widget bodies, layout): the frame lock is already held by that goroutine, and a nested Lock deadlocks the whole app. Mutate UI-thread state directly on that path; reserve WithFrameLock for background work only.

func Wrap

func Wrap(a *AttrSet)

Wrap lets children flow onto additional lines when they don't all fit along the main axis.

func XAdvance

func XAdvance(fontId FontId, glyphId GlyphId) float32

func YesAnimate

func YesAnimate(a *AttrSet)

YesAnimate enables all animation channels (Animations = AnimAll). Marks the mask set so it wins under a NoAnimate/Viewport parent without needing ModAttrs after open.

Types

type Alignment

type Alignment int
const (
	AlignUnset Alignment = iota

	AlignStart
	AlignMiddle
	AlignEnd
)

type AnimFlags added in v0.6.0

type AnimFlags uint16

AnimFlags selects which property channels ease between frames. Bits are enable flags: 1 = animate that channel, 0 = snap. Attrs() seeds AnimAll without marking the mask set, so open-time cascade still intersects with a NoAnimate/Viewport parent. Explicit NoAnimate / YesAnimate / AnimateOnly set animationsSet and block that cascade.

const (
	AnimSize    AnimFlags = 1 << iota // resolved size
	AnimPos                           // relative origin (layout / float position)
	AnimPad                           // padding
	AnimCorners                       // corner radii
	AnimBorder                        // border width
	AnimAlpha                         // Transparency (not Background alpha)

	// AnimAll enables every channel. Named bits cover the channels the apply
	// site knows about; the rest of the 0xFFFF mask is reserved so YesAnimate
	// stays "everything" when new channels are added.
	AnimAll AnimFlags = 0xFFFF

	// AnimLayout is size + position + pad + corners + border (not alpha).
	AnimLayout = AnimSize | AnimPos | AnimPad | AnimCorners | AnimBorder
)

type AttrSet

type AttrSet struct {

	// padding order is: top right bottom left
	Padding Vec4

	Gap float32

	// 0 means opaque, 1 means transperant (opacity = 1)
	// using this instead of opacity because the zero value is the good default
	Transparency float32

	MainAlign  Alignment
	CrossAlign Alignment

	// properties for self with respect to parent!
	Grow      float32
	SelfAlign Alignment // override the parent's cross-align setting

	MinSize Vec2
	MaxSize Vec2

	Float Vec2

	Background Vec4
	Gradient   Vec4 // diff applied to background

	Border

	Shadow

	// css order: top-left, top-right, bottom-right, bottom-left
	Corners Vec4

	// flags
	// Layout things ..
	Row          bool
	Wrap         bool
	ExpandAcross bool
	Floats       bool
	// size is not determined by content but by size constraints, flex growth, and cross axis expansion
	ExtrinsicSize bool

	// z-index
	Z f32

	// Event things
	ClickThrough bool

	Focusable bool // items that can receive focus via clicking or tab-cycling
	FocusTrap bool // this container wants to be a focus trap (only for modals)

	// Clip constrains children (drawing and pointer events) to this container's
	// bounds. Attrs() defaults Clip to true; opt out with NoClip. Raw AttrSet{}
	// leaves Clip false. Does not cascade — each container chooses independently.
	// Ancestor clip still applies via applyClipping's inherited clip rect.
	Clip bool

	// Animations selects which channels ease toward new values between frames.
	// Enable bits (1 = animate that channel). Default from Attrs() is AnimAll
	// with animationsSet false (inherits parent via cascade). Explicit setters
	// (NoAnimate, YesAnimate, AnimateOnly, Viewport) set animationsSet so the
	// open-time cascade does not rewrite the mask — Attrs(YesAnimate) works
	// under Viewport without ModAttrs.
	Animations AnimFlags

	// Paragraph text style for this subtree (cascades to descendants).
	// Wholesale cascade only: zero value means unset — parent.TextStyle is
	// cloned at container open. Root is initialized to DefaultTextStyle() each
	// frame. Amend with AmendTextStyle; reset with SetTextStyle.
	TextStyle TextStyleAttrs
	// contains filtered or unexported fields
}

func Attrs

func Attrs(fns ...AttrsFn) AttrSet

Attrs builds an AttrSet by applying the given setters in order. Defaults: Clip = true, Animations = AnimAll, animationsSet = false (may inherit parent mask via cascade). Call NoAnimate / YesAnimate / AnimateOnly to pin the mask; call NoClip to opt out of clipping.

func AttrsWith

func AttrsWith(a AttrSet, fns ...AttrsFn) AttrSet

AttrsWith builds an AttrSet starting from a base, then applies the setters. Does not re-apply defaults — base is used as-is (so a zero Animations on base stays "animate nothing").

func GetAttrs

func GetAttrs() AttrSet

GetAttrs returns the current container's attribute set.

type AttrsFn

type AttrsFn func(*AttrSet)

AttrsFn is a single attribute setter. The Attrs and AttrsWith builders take a list of these (Row, Pad(8), Gap(6), ...) and apply them in order; this is the blessed way to specify container attributes.

func AmendTextStyle added in v0.6.0

func AmendTextStyle(mods ...TextStyleFn) AttrsFn

AmendTextStyle inherits the text style from the parent container while applying modifications to it.

Expected to be called inside `Attrs(...)` while building a new container

Container(Attrs(AmendTextStyle(FontSize(20), ...), func() {
	// content
})

func Animate added in v0.6.0

func Animate(flags AnimFlags) AttrsFn

Animate enables the given channels without clearing others (bitwise OR). Marks the mask set. Compose with NoAnimate to start from none under a Viewport, e.g. Attrs(NoAnimate, Animate(AnimSize), Animate(AnimAlpha)). Alone after Attrs' default AnimAll it only pins the full mask (no-op on bits).

func AnimateOnly added in v0.6.0

func AnimateOnly(flags AnimFlags) AttrsFn

AnimateOnly enables exactly the given channels (others snap). Example: AnimateOnly(AnimPos) eases movement but snaps size changes. Marks the mask set (same as YesAnimate) so Attrs(AnimateOnly(...)) works under Viewport / NoAnimate parents.

func Background

func Background(h, s, l, a float32) AttrsFn

Background sets the fill color as HSLA (hue, saturation, lightness, alpha).

func BackgroundVec

func BackgroundVec(v Vec4) AttrsFn

BackgroundVec sets the fill color from an HSLA Vec4.

func BorderColor

func BorderColor(h, s, l, a float32) AttrsFn

BorderColor sets the border color as HSLA (hue, saturation, lightness, alpha).

func BorderColorVec

func BorderColorVec(v Vec4) AttrsFn

BorderColorVec sets the border color color from an HSLA Vec4.

func BorderWidth

func BorderWidth(f float32) AttrsFn

BorderWidth sets the border thickness.

func BoxShadow

func BoxShadow(r float32) AttrsFn

BoxShadow adds a drop shadow with the given blur radius and a slight downward offset.

func ComposeAttrs

func ComposeAttrs(fns ...AttrsFn) AttrsFn

ComposeAttrs bundles several setters into a single AttrsFn, so a reusable group of attributes can be passed around and applied as one.

func Corners

func Corners(v float32) AttrsFn

Corners sets a uniform border radius on all four corners.

func Corners4

func Corners4(tl, tr, br, bl f32) AttrsFn

Corners4 sets a per-corner border radius in top-left, top-right, bottom-right, bottom-left order.

func CrossAlign

func CrossAlign(a Alignment) AttrsFn

CrossAlign sets how children are aligned along the cross axis.

func FixHeight

func FixHeight(w float32) AttrsFn

FixHeight fixes the height to an exact value (min equals max), leaving width free.

func FixSize

func FixSize(w, h float32) AttrsFn

FixSize fixes the width and height to exact values (min equals max).

func FixSizeVec

func FixSizeVec(v Vec2) AttrsFn

FixSizeVec fixes the size to an exact Vec2 by setting min and max equal.

func FixWidth

func FixWidth(w float32) AttrsFn

FixWidth fixes the width to an exact value (min equals max), leaving height free.

func Float

func Float(x, y float32) AttrsFn

Float takes this container out of the normal layout flow and positions it at an explicit (x, y) offset.

func FloatVec

func FloatVec(v Vec2) AttrsFn

FloatVec takes this container out of the normal flow and positions it at the given offset — the Vec2 form of Float.

func Gap

func Gap(v float32) AttrsFn

Gap sets the spacing inserted between children along the main axis.

func Glow

func Glow(r float32) AttrsFn

Glow adds a soft, faint shadow with the given blur radius and no offset, producing a glow rather than a drop shadow.

func Grad

func Grad(dh, ds, dl, da f32) AttrsFn

Grad sets a background gradient expressed as per-channel HSLA deltas (delta hue, saturation, lightness, alpha) from the background color.

func GradVec

func GradVec(g Vec4) AttrsFn

GradVec sets a background gradient from an HSLA Vec4 of per-channel deltas added to the background color across the fill.

func Grow

func Grow(f float32) AttrsFn

Grow sets the flex-grow factor: how much of the leftover main-axis space this container claims relative to its growing siblings.

func MainAlign

func MainAlign(a Alignment) AttrsFn

MainAlign sets how children are aligned (and any extra space distributed) along the main axis.

func MaxHeight

func MaxHeight(h float32) AttrsFn

MaxHeight sets the maximum height, leaving the maximum width unchanged.

func MaxSizeVec

func MaxSizeVec(v Vec2) AttrsFn

MaxSizeVec sets the maximum size from a Vec2.

func MaxWidth

func MaxWidth(w float32) AttrsFn

MaxWidth sets the maximum width, leaving the maximum height unchanged.

func MinHeight

func MinHeight(h float32) AttrsFn

MinHeight sets the minimum height, leaving the minimum width unchanged.

func MinSize

func MinSize(w, h float32) AttrsFn

MinSize sets the minimum width and height.

func MinSizeVec

func MinSizeVec(v Vec2) AttrsFn

MinSizeVec sets the minimum size from a Vec2.

func MinWidth

func MinWidth(w float32) AttrsFn

MinWidth sets the minimum width, leaving the minimum height unchanged.

func Pad

func Pad(v float32) AttrsFn

Pad sets equal padding on all four sides.

func Pad2

func Pad2(v, h float32) AttrsFn

Pad2 sets vertical (top and bottom) and horizontal (left and right) padding.

func Pad4

func Pad4(t, r, b, l float32) AttrsFn

Pad4 sets per-side padding in top, right, bottom, left order.

func PadVec

func PadVec(v Vec4) AttrsFn

PadVec sets padding from a Vec4 in top, right, bottom, left order.

func RowF

func RowF(row bool) AttrsFn

RowF sets horizontal (row) layout when row is true, and vertical (column) when false — the parameterized form of Row.

func SelfAlign

func SelfAlign(a Alignment) AttrsFn

SelfAlign overrides the parent's cross-axis alignment for this one child.

func SetTextStyle added in v0.6.0

func SetTextStyle(base TextStyleAttrs, mods ...TextStyleFn) AttrsFn

SetTextStyle sets the text style for the container (without inherting anything from parent)

func Spacing

func Spacing(v float32) AttrsFn

Spacing is a shorthand that sets both the gap between children and equal padding around them to the same value.

func Trans

func Trans(v float32) AttrsFn

Trans sets transparency, from 0 (fully opaque) to 1 (fully transparent), applied to this container and inherited by its children.

func Z

func Z(z f32) AttrsFn

Z sets the draw order (z-index); higher values draw on top of lower ones.

type BackendContext added in v0.6.0

type BackendContext interface {
	// Platform is a stable label: "ios", "android", "darwin", "windows",
	// "x11", "wayland", …
	Platform() string
}

BackendContext is the platform host object for the escape hatch (Host.EscapeHatchBackendContext). Concrete types live with each backend (e.g. iosbackend.Context, androidbackend.Context, cocoabackend.Context). Extensions type-assert when they need native handles. See docs/mobile-extensions.md.

type Border

type Border struct {
	BorderColor Vec4
	BorderWidth f32
}

type ClipStackOp

type ClipStackOp int
const (
	ClipPush ClipStackOp
	ClipPop
)

type Color

type Color = color.NRGBA

type ContainerId

type ContainerId *identNode

ContainerId is an opaque handle to a container's identity, returned by ContainerWithKey (and Container/Element/CurrentId/GetLastId). Pass it anywhere an id is accepted — focus, hover, screen-rect queries, popup anchors. It is a value you hold and hand back; there is nothing to inspect. (The backing identity node is deliberately unexported.)

func Container

func Container(attrs AttrSet, builder func()) ContainerId

Container opens a container with the given attributes, runs builder to populate its children, closes it, and returns a handle to it. This is the primary building block; the returned ContainerId can be passed to the query functions (focus, hover, screen-rect, popup anchors). Use ContainerWithKey when the container needs an explicit reconciliation key.

func ContainerWithKey

func ContainerWithKey(key any, attrs AttrSet, builder func()) ContainerId

ContainerWithKey opens a container, runs builder inside it, and closes it, returning the container's identity node — a stable handle usable anywhere an id is accepted (focus, hover, screen-rect queries, popup anchors).

The id contract (see identity.go for the full reconciliation rule):

  • nil id: the container is matched positionally by (component type, per-type ordinal), where the component type is the builder's func literal. This is right for fixed structure and for loops whose membership doesn't change.
  • explicit id: matched by Go value equality (pointers by pointer, strings by content — dynamic strings are fine), SCOPED to the parent: the same id under two parents is two distinct containers. Ids must be unique among siblings within a frame; duplicates are reported (see claimChild). Use explicit ids for dynamic collections (rows keyed by row data) and wherever cross-frame continuity must survive structural change.

func CurrentId

func CurrentId() ContainerId

CurrentId returns the current container's identity handle: an opaque, stable, comparable token accepted anywhere a ContainerId is (focus, hover, screen-rect queries, popup anchors).

func Element

func Element(attrs AttrSet) ContainerId

small helper to make code look cleaner

func ElementWithKey

func ElementWithKey(key any, attrs AttrSet) ContainerId

ElementWithKey adds a childless (leaf) container with an explicit reconciliation key — the keyed form of Element.

func GetLastId

func GetLastId() ContainerId

GetLastId returns the identity handle of the current container's last child (like CurrentId's, for the child just built).

type ContainerTouchInfo added in v0.6.0

type ContainerTouchInfo struct {
	TouchId uint32
	Target  *identNode
	Direct  bool
}

ContainerTouchInfo is one entry in the per-frame touchingList: a touch id over a container (direct hit or ancestor), rebuilt with hoverList.

type Direction

type Direction byte
const (
	LTR Direction = iota
	RTL
)

func ParagraphBidi

func ParagraphBidi(txt string) []Direction

works with a single line of text, not an article with multiple paragraphs!

type FaceLookupKey

type FaceLookupKey struct {
	Family string
	Aspect FontAspect
}

type FileCacheStats added in v0.6.0

type FileCacheStats struct {
	// FilePaths is the number of paths with any filecontent entry.
	FilePaths int
	// DirPaths is the number of cached DirListing paths.
	DirPaths int
	// Entries is the total number of content-type slots across all file paths
	// (e.g. "content", "image", "image-config").
	Entries int
	// ContentBytes is the approximate total size of cached []byte values
	// (raw file bodies). Other entry types are not included.
	ContentBytes int64
	// InFlight is the number of paths with an outstanding async load token.
	InFlight int
	// NextLoadID is the last async load id minted (fileContentLoadSeq).
	NextLoadID uint64
	// NextGeneration bumps on every cache write (set), like image generation.
	NextGeneration uint64
}

FileCacheStats is a snapshot of the IM file/dir caches for debug HUDs (parallel to ImageCacheStats — path-keyed rather than dense ImageIds).

func DebugGetFileCacheStats added in v0.6.0

func DebugGetFileCacheStats() FileCacheStats

DebugGetFileCacheStats returns a snapshot of filecontent / direntries. Intended for debug HUDs — not a stable performance API.

type Font

type Font = font.Face

func GetParsedFont

func GetParsedFont(f FontId) *Font

type FontAspect

type FontAspect = font.Aspect

func DefaultFontAspect

func DefaultFontAspect() FontAspect

type FontFace

type FontFace struct {
	FontId FontId

	FaceLookupKey

	Filepath string

	// Inverted "Units Per eM"
	InvUPM float32

	// Extents
	Ascender  float32
	Descender float32
	LineGap   float32
	// contains filtered or unexported fields
}

FontFace holds some generic traits/info about the font face

func GetFace

func GetFace(f FontId) FontFace

type FontFaceInfo

type FontFaceInfo struct {
	FontId   FontId
	Family   string
	Aspect   FontAspect
	Filepath string
}

FontFaceInfo is a read-only snapshot of one registered font face: a single (family, aspect) entry backed by a file on disk. A family with several weights or styles contributes several entries.

func AllFontFaces

func AllFontFaces() []FontFaceInfo

AllFontFaces returns a snapshot of every registered font face, in registration order. Ensures the system font scan has run. Intended for tools that enumerate the available fonts — see examples/fontviewer.

type FontId

type FontId int32

func LookupFace

func LookupFace(key FaceLookupKey) FontId

type FrameFn

type FrameFn func()

type FrameInputData added in v0.6.0

type FrameInputData struct {
	Mouse  MouseAction
	Motion Vec2 // mouse movement
	Scroll Vec2

	// ClickCount is the click-streak position of this frame's MouseClick:
	// 1 for a single click, 2 for the second click of a double-click, and
	// so on (macOS style). Computed by core at frame start from click
	// timing and position — backends only deliver the clicks. Valid only
	// when Mouse == MouseClick.
	ClickCount int

	Key KeyCode

	Text string // text inputted this frame (could come from IME completion)

	// Touch edges this frame (ids only). Counts are the number of valid
	// leading entries; remaining slots are unspecified.
	TouchesBegan      [MaxTouches]uint32
	TouchesBeganCount int
	TouchesEnded      [MaxTouches]uint32
	TouchesEndedCount int
}

FrameInputData is transient per-frame input (click, scroll, text, touch edges). Stored on the active UI as ui.Host.FrameInput; cleared at end of each pass.

func GetFrameInput added in v0.6.0

func GetFrameInput() *FrameInputData

GetFrameInput returns a pointer to the active UI's per-frame input edges.

type FrameOutputData

type FrameOutputData struct {
	Surfaces []Surface

	Copy    string // things we want to put into the clipboard
	Paste   bool   // to request a clipboard read!
	OpenURL string // open in system browser / scheme handler after the frame

	NextFrameRequested bool
	FrameHasChanges    bool

	// SurfacesHash is the content hash of this frame's surface list (what
	// FrameHasChanges is derived from). A backend can compare it against the hash
	// of the frame currently on screen to decide there is nothing to present —
	// robust to produce/present not being 1:1 (tear-defer, collapsed produces),
	// where FrameHasChanges (produced-vs-produced) would be misleading.
	SurfacesHash uint64

	// Glyph bitmap cache deltas for this frame (only populated when
	// ui.Host.GlyphCacheBudgetBytes > 0). The backend keeps a plain map of platform
	// handles that these two lists keep mirrored with core's cache: free the
	// evicted, upload the added (via GlyphBitmap). See glyphcache.go.
	GlyphsAdded   []GlyphKey
	GlyphsEvicted []GlyphKey
}

func LastFrameOutput added in v0.6.7

func LastFrameOutput() FrameOutputData

LastFrameOutput is the FrameOutputData from the most recently completed RunFrameFn. Surfaces are a copy. Read it on a later frame (or after RunFrameFn returns); the pass currently inside frameFn has not harvested yet.

func RunFrameFn

func RunFrameFn(frameFn FrameFn) FrameOutputData

RunFrame is meant to be called by the app & rendering backend

type Framebuffer

type Framebuffer struct {
	W, H   int    // device pixels
	Stride int    // bytes per row (== W*4)
	Pix    []byte // BGRA, premultiplied, top-down; reused across frames
}

Framebuffer is a reusable BGRA, premultiplied, top-down pixel buffer at device resolution. Pix is a raw []byte (NOT image.RGBA, which is RGBA): we composite into BGRA directly so the buffer is presentable without a per-pixel swizzle.

func RenderToBuffer

func RenderToBuffer(surfaces []Surface, scale float32) *Framebuffer

RenderToBuffer renders the surfaces into a shared reusable buffer at the device size implied by ui.Host.WindowSize * scale. Convenience entry point mirroring the frameSurfaces reuse pattern; backends that own their buffer use a SoftRenderer directly.

func (*Framebuffer) ToRGBA

func (fb *Framebuffer) ToRGBA() *image.RGBA

ToRGBA copies the framebuffer into an *image.RGBA in standard R,G,B,A order (inverting Host.PixelOrder). For tests only: snapshot/parity comparisons go through PNG, which the runtime never touches.

type Glyph

type Glyph struct {
	FontId   FontId
	GlyphId  GlyphId
	Cluster  int32
	Offset   Vec2
	XAdvance float32
	Width    float32
}

type GlyphBM

type GlyphBM struct {
	W, H   int     // device-px bitmap dimensions (0 for an empty glyph, e.g. space)
	OffX   float32 // device-px offset from pen origin to bitmap top-left (x rightward)
	OffY   float32 // device-px offset from pen origin to bitmap top-left (y downward)
	Alpha  []byte  // coverage, one byte per pixel, len == Stride*H
	RGBA   []byte  // precolored stamp, 4 bytes/pixel, len == Stride*H
	Stride int
}

GlyphBM is a rasterized glyph plus the placement metrics needed to position it relative to the pen origin. All geometry is in device pixels (scale-independent), so an entry is valid regardless of the Host.WindowScale in effect when it is drawn; the backend divides by the current WindowScale to get logical coordinates.

An outline glyph fills Alpha (one coverage byte per pixel). A color-bitmap glyph fills RGBA instead: premultiplied, Host.PixelOrder, 4 bytes per pixel. Exactly one of Alpha or RGBA is non-empty for a drawable stamp.

func GlyphBitmap

func GlyphBitmap(key GlyphKey) (GlyphBM, bool)

GlyphBitmap returns the cached bitmap for a key (false if not currently cached). The backend calls this for keys in FrameOutputData.GlyphsAdded to fetch the bytes it needs to build its platform handle.

type GlyphId

type GlyphId = opentype.GID

func LookupGlyph

func LookupGlyph(fontId FontId, ch rune) GlyphId

type GlyphKey

type GlyphKey struct {
	FontId  FontId
	GlyphId GlyphId
	Px      uint16
}

GlyphKey identifies a cached glyph bitmap. Px is the glyph box height in *device* pixels (round(Rect.Size[1] * Host.WindowScale)), which subsumes the backing scale: a 16pt glyph at 2x and a 32pt glyph at 1x share one bitmap (same physical pixels).

func GlyphKeyForSurface

func GlyphKeyForSurface(s *Surface) (GlyphKey, bool)

GlyphKeyForSurface derives the cache key for a glyph surface. The SINGLE source of truth for quantization, used by both core's cache pass and the backend's draw path so the two can never disagree. ok is false for non-glyph surfaces.

type GlyphSegmentProps

type GlyphSegmentProps struct {
	Dir Direction
	// contains filtered or unexported fields
}

type GlyphsSegment

type GlyphsSegment struct {
	GlyphSegmentProps
	Width           float32
	Height          float32
	EndsWithNewline bool
	Glyphs          []Glyph
}

type Handle

type Handle int32

type HookEntryKey

type HookEntryKey struct {
	Data    any // container id
	ItemKey any
}

HookEntryKey identifies a piece of hooked side data by the object it is attached to and a caller-supplied item key.

type Host added in v0.6.0

type Host struct {
	Input      InputStateData
	FrameInput FrameInputData

	// Window (backend → core)
	WindowSize    Vec2
	WindowScale   float32 // device pixels per logical point; default 1
	WindowFocused bool

	// HardwareKeyboard is backend → app: true when a physical keyboard is
	// available (built-in laptop keys, USB/Bluetooth keyboard, etc.). False
	// for soft/IME-only devices. May change at runtime when a keyboard is
	// attached or detached (phones/tablets). Desktop backends set true;
	// headless defaults true so snapshots match desktop chrome.
	HardwareKeyboard bool

	// ComfortScale multiplies default control geometry (button/input text size
	// and padding, segment height, slider handle, checkbox/toggle size, …) so
	// touch-first devices get larger hit targets without changing desktop
	// density. Design units are authored at scale 1; widgets do
	// `size * ComfortScale` with no zero-sentinel branch. Backends set this
	// once at startup (desktop/headless: 1; phone: typically ~1.25). Apps may
	// override. Always initialize to a positive value — never leave at 0.
	ComfortScale float32

	// PrimaryMod is the platform shortcut modifier for editing and similar
	// chords (select-all, copy, undo, …): ModCmd on Apple hosts, ModCtrl
	// elsewhere. Zero means PrimaryMod() derives it from GOOS (darwin → Cmd).
	// Web backends set this from the browser platform because GOOS is always
	// "js" and would otherwise always pick Ctrl.
	PrimaryMod Modifiers

	// PixelOrder maps each destination byte slot to a source channel of
	// (R,G,B,A): slot k stores source channel PixelOrder[k]. Backends set this
	// once at window setup so SoftRenderer writes presentable memory directly.
	// Zero (all zeros) means PixelOrderBGRA. Do not change after the first
	// frame — image and region caches hold bytes in the current order.
	//
	//	PixelOrderBGRA = {2,1,0,3}  // default; win32/cocoa/wayland/x11
	//	PixelOrderRGBA = {0,1,2,3}  // canvas ImageData, Android ANativeWindow
	PixelOrder [4]uint8

	// PreferredOrientation is app → backend: sticky orientation policy
	// (unlike WantsKeyboard, it is not cleared each frame). Set once at
	// startup, e.g. GetHost().PreferredOrientation = OrientationLandscape.
	// Mobile backends apply it via the OS; 0 (OrientationAny) is the default.
	PreferredOrientation PreferredOrientation

	// IME / soft keyboard (core → backend)
	CaretPos       Vec2
	CaretHeight    float32
	CompositionPos Vec2
	WantsKeyboard  bool

	// Clipboard / open-URL requests (core → backend via FrameOutputData)
	Copy    string
	Paste   bool
	OpenURL string // non-empty: open this URL after the frame (last write wins)

	// NextFrame is set when the UI wants another frame without input
	// (animations, settle). Backends also read FrameOutputData.NextFrameRequested.
	NextFrame atomic.Bool

	// Diagnostics: LayoutTime is produce (RunFrameFn); PaintTime is the last
	// SoftRenderer pass (set at the end of Render / RenderInto). TotalFrameTime
	// is reserved for backends that want produce+present wall time.
	TotalFrameTime time.Duration
	LayoutTime     time.Duration
	PaintTime      time.Duration
	ImageScaleTime time.Duration

	// HeadlessRender is set for RenderToPNG / snapshot paths.
	HeadlessRender bool

	// GlyphCacheBudgetBytes is the soft cap for the shared glyph cache; 0 disables.
	// Backend sets this once at startup (process-wide effect via Resources).
	GlyphCacheBudgetBytes int

	// EscapeHatchBackendContext is the live platform host object for
	// extensions that must call OS APIs outside Shirei's normal surface
	// (camera, share sheet, system pickers, …). The active backend sets it
	// when the window/activity is ready; nil when headless or before attach.
	//
	// This is intentionally not a casual Host field: prefer portable Shirei
	// APIs and extension packages. Type-assert to the concrete backend
	// context (iosbackend.Context, androidbackend.Context, …) only inside
	// those packages — not in ordinary app UI code.
	// See docs/mobile-extensions.md.
	EscapeHatchBackendContext BackendContext
}

Host is the backend ↔ app I/O channel for one UI (nested on UI as ui.Host): window geometry, input, clipboard requests, IME anchors, next-frame, etc. All Host fields live here — there are no parallel package-level scalar vars.

func GetHost added in v0.6.0

func GetHost() *Host

GetHost returns a pointer to the active UI's Host I/O channel. Always follows the current ui after bindUI / Measure swaps.

type HoverableArtifacts

type HoverableArtifacts struct {
	Rect      Rect
	Container *_Container
}

type ImageCacheStats added in v0.6.0

type ImageCacheStats struct {
	// KeyCount is the number of entries in imageKeys (paths, app keys, shadows).
	KeyCount int
	// TableLen is len(imageIds), including the reserved empty slot at 0.
	TableLen int
	// LiveSlots counts non-nil *ImageData entries.
	LiveSlots int
	// FreeList is the number of recycled ids available for reuse.
	FreeList int
	// MaxId is the highest allocated ImageId (TableLen-1).
	MaxId ImageId
	// NextGeneration is the current generation counter value.
	NextGeneration uint64
	// PixelBytes is the approximate total RGBA storage (sum of len(Pix) over live slots).
	PixelBytes int64
	// PathOrAppKeys is the count of string keys (LoadImage paths and UseImage keys).
	PathOrAppKeys int
	// ShadowKeys is the count of ShadowMapKey entries.
	ShadowKeys int
}

ImageCacheStats is a snapshot of the package image registry for debugging (HUD, tests). Call under the frame lock / during a frame.

func DebugGetImageCacheStats added in v0.6.0

func DebugGetImageCacheStats() ImageCacheStats

DebugGetImageCacheStats returns a snapshot of the image handle table and key map. Intended for debug HUDs and tests — not a stable performance API.

type ImageData

type ImageData struct {
	image.Config
	image.RGBA
	// Generation is bumped whenever the RGBA pixels behind this id are established
	// or replaced (async decode completion, UseImage replacement). The region
	// raster cache folds (ImageId, Generation) into its content hash, so a change
	// to the pixels behind a stable id invalidates any cached bitmap holding the
	// old pixels — the "dangerous middle" the hash otherwise can't see (the image
	// id, and thus the surface bytes, don't change). Written under the frame lock,
	// like RGBA itself.
	Generation uint64
}

func LoadImage

func LoadImage(fpath string) *ImageData

func LookupImage

func LookupImage(id ImageId) *ImageData

this function is mostly for the backend

type ImageId

type ImageId uint32

ImageId is a handle into the package image table. It is stable only while the entry stays live: unused images are reclaimed after contentCachePruneAfterFrames (see freeImage / maybeSweepImages). Prefer path/app keys (Image, UseImage) over holding an ImageId across long idle stretches.

func GetImageId

func GetImageId(fpath string) ImageId

func UseImage

func UseImage(key string, rgba *image.RGBA) ImageId

UseImage registers (or replaces) an in-memory image under a stable app-chosen key and returns its id — the dynamic-content counterpart of LoadImage's path-keyed caching, for images that never touch disk (downloads, generated previews). Reusing a key with a different buffer replaces the pixels behind the same id and bumps Generation. Reusing a key with the same backing store only touches lastUsed (cheap; preferred every frame while visible). Call under the frame lock.

type InputStateData added in v0.6.0

type InputStateData struct {
	MousePoint  Vec2
	MouseButton MouseButton

	DownKeys []KeyCode

	// control keys state
	Modifiers Modifiers

	Composition    string // text being input via IME
	CompositionSel [2]int // selected clause/caret as rune offsets into Composition

	// Touches is the current contact set (multi-touch). Slots with Active
	// false are free; Id is meaningful only when Active. Filled by backends
	// that have touch; empty on mouse-only platforms.
	Touches [MaxTouches]TouchInfo

	// MouseFromTouch is true while the backend is driving the mouse from a
	// finger (including the short hold after a synthetic tap). Prefer
	// IsTouched for hit-testing while this is set so a delayed mouse-up
	// cannot re-engage a control after the finger has lifted.
	MouseFromTouch bool

	// AudioInterrupted is set by the platform audio backend when the OS
	// suspends output (phone call, Siri, another app taking the session on
	// iOS, etc.) and cleared when the interruption ends. Apps and media
	// widgets can pause/resume synthesis; the backend still owns restarting
	// the device stream. False on platforms that never report interruptions.
	AudioInterrupted bool
}

InputStateData is persistent input (mouse, keys, touches, composition). Backends write; widgets read. Stored on the active UI as ui.Host.Input.

func GetInputState added in v0.6.0

func GetInputState() *InputStateData

GetInputState returns a pointer to the active UI's persistent input. Always follows the current ui after bindUI / Measure swaps — no rebind.

type KeyCode

type KeyCode byte

KeyCode identifies a physical key by its US-QWERTY legend, independent of the active keyboard layout: KeyW is the second key of the top letter row whether the layout is QWERTY, AZERTY, Dvorak, or Arabic. Layouts are a text-input concern — they drive ui.Host.FrameInput.Text, not key identity — so note keys, game keys, and shortcut combos like Cmd+C stay on the physical positions users' hands know. Backends translate their native positional codes (Cocoa kVK_ANSI_*, Win32 scancodes, evdev) via internal/qwerty.

const (
	Key0 KeyCode = '0' + iota
	Key1
	Key2
	Key3
	Key4
	Key5
	Key6
	Key7
	Key8
	Key9
)
const (
	// ascii table order
	KeyA KeyCode = 'A' + iota
	KeyB
	KeyC
	KeyD
	KeyE
	KeyF
	KeyG
	KeyH
	KeyI
	KeyJ
	KeyK
	KeyL
	KeyM
	KeyN
	KeyO
	KeyP
	KeyQ
	KeyR
	KeyS
	KeyT
	KeyU
	KeyV
	KeyW
	KeyX
	KeyY
	KeyZ
)

type KeyCombo

type KeyCombo struct {
	Key KeyCode
	Mod Modifiers
}

KeyCombo is a key together with the modifier keys held with it — the unit matched against keyboard shortcuts.

func ActiveCombo

func ActiveCombo() KeyCombo

ActiveCombo returns the key pressed this frame together with the currently held modifiers, ready to compare against a shortcut Combo.

func Combo

func Combo(key KeyCode, mod Modifiers) KeyCombo

Combo builds a KeyCombo from a key and its modifiers.

type Modifiers

type Modifiers uint32
const (
	ModCtrl Modifiers = 1 << iota
	ModCmd
	ModShift
	ModAlt
	ModSuper
)

mirrors the values in gioui

const ModNone Modifiers = 0

func PrimaryMod added in v0.6.5

func PrimaryMod() Modifiers

PrimaryMod returns the shortcut modifier for the active host: Host.PrimaryMod when set by the backend, otherwise Cmd on darwin and Ctrl on every other GOOS (including js unless the backend overrides).

type MouseAction

type MouseAction uint8
const (
	MouseClick MouseAction = 1 + iota
	MouseRelease
)

type MouseButton

type MouseButton uint8
const (
	MousePrimary MouseButton = iota
	MouseSecondary
	MouseTertiary
)

mirrors the values in gioui

type PreferredOrientation added in v0.6.0

type PreferredOrientation int

PreferredOrientation is an app → backend policy for how the window should sit relative to the device. Mobile backends lock the OS interface orientation so WindowSize, safe area, and the soft keyboard follow that policy. Desktop backends ignore it. Default is OrientationAny.

const (
	// OrientationAny follows the device (no lock).
	OrientationAny PreferredOrientation = iota
	// OrientationPortrait locks to portrait (sensor may flip upright).
	OrientationPortrait
	// OrientationLandscape locks to landscape (sensor may pick left/right).
	OrientationLandscape
)

type Rect

type Rect struct {
	Origin Vec2
	Size   Vec2
}

func GetContentRect

func GetContentRect() Rect

GetContentRect returns the current container's content rectangle: its resolved rectangle inset by padding.

func GetContentRectOf

func GetContentRectOf(id ContainerId) Rect

GetContentRectOf returns the content rectangle (resolved rect inset by padding) of the container with the given handle.

func GetResolvedRectOf

func GetResolvedRectOf(target ContainerId) Rect

GetResolvedRectOf returns the laid-out rectangle (resolved origin and size, before clipping) of the container with the given handle.

func GetScreenRect

func GetScreenRect() Rect

Get the screen rect of the current element from the previous frame data

func GetScreenRectOf

func GetScreenRectOf(target ContainerId) Rect

GetScreenRectOf returns the on-screen rectangle (after clipping) of the container with the given handle.

func RectIntersect

func RectIntersect(r1 Rect, r2 Rect) Rect

RectIntersect returns the overlapping region of two rectangles.

type RegionStats

type RegionStats struct {
	Frames        int   // painted frames measured
	Regions       int64 // total clip regions seen
	StableRegions int64 // regions whose content hash matched the previous frame
	Surfaces      int64 // total surfaces across the measured frames
	Covered       int64 // surfaces lying under a stable region (would blit, not re-raster)
	MaxDepth      int   // deepest clip nesting observed
	Hits          int64 // cache blits from a stored bitmap
	Populated     int64 // regions rasterized into the cache this frame
	Inlined       int64 // regions rendered inline (first sight / ineligible)
}

RegionStats is a snapshot of the measurement counters, accumulated across frames since the last fetch. A backend's perf printer reads and resets it once a second.

type RenderData

type RenderData struct {
	AttrSet
	ResolvedSize   Vec2
	RelativeOrigin Vec2
	ResolvedOrigin Vec2
	ContentSize    Vec2
	ScrollOffset   Vec2
	// contains filtered or unexported fields
}

func GetRenderData

func GetRenderData() RenderData

GetRenderData returns the current container's render data — resolved geometry, padding, and scroll offset.

func GetRenderDataOf

func GetRenderDataOf(id ContainerId) RenderData

GetRenderDataOf returns the render data of the container with the given handle.

type Resources added in v0.6.0

type Resources struct {
	// contains filtered or unexported fields
}

Resources holds process-shared, identity-free caches: fonts, text shaping, glyph bitmaps, soft-render corner masks, images, and IM filesystem content. The process owns one instance (package res / SharedResources). UIs do not own a resource pack; Measure and multi-window share the same caches.

Code that frees or prunes entries affects the whole process — do not prune from a throwaway measure path in a way that drops live-app assets.

func NewResources added in v0.6.0

func NewResources() *Resources

NewResources constructs a full resource pack and starts fsnotify watchers for DirListing / ReadFileContent caches.

func SharedResources added in v0.6.0

func SharedResources() *Resources

SharedResources returns the process-shared resource pack (fonts, shape caches, glyph bitmaps, image registry, IM filesystem caches, …).

type Shadow

type Shadow struct {
	Offset Vec2
	Blur   f32
	Alpha  f32
}

type ShadowMapKey

type ShadowMapKey struct {
	// contains filtered or unexported fields
}

ShadowMapKey is the cache key for a generated blur shadow. It is comparable so it can sit in the shared imageKeys map alongside string path/app keys (map[any] keeps the types distinct — no collision with paths).

type ShapedText

type ShapedText struct {
	Runes   []rune
	BaseDir Direction
	Lines   []ShapedTextLine
}

func ShapeText

func ShapeText(text string, style TextStyleAttrs, spans ...TextSpan) ShapedText

ShapeText shapes text with no soft-wrap width (single long lines until hard breaks). Prefer ShapeTextMax when the wrap budget is known. style must be fully resolved — callers supply the base (no container cascade). spans are optional.

func ShapeTextMax added in v0.6.0

func ShapeTextMax(text string, style TextStyleAttrs, maxWidth float32, spans ...TextSpan) ShapedText

ShapeTextMax shapes text, soft-wrapping when maxWidth > 0. Use this for measurement outside layout (virtual-list item heights) and whenever the wrap budget is not the current container's MaxSize. style is explicit — offline measurement has no open container to read a style from.

type ShapedTextLine

type ShapedTextLine struct {
	Segments []GlyphsSegment
	Width    float32
	Height   float32
}

type SnapEvent added in v0.6.5

type SnapEvent struct {
	Pkg    string `json:"pkg"`              // absolute package directory
	Test   string `json:"test"`             // caller-supplied name, e.g. testing.T.Name()
	Name   string `json:"name"`             // snapshot id
	Status string `json:"status"`           // match | mismatch | created | updated | skip
	Golden string `json:"golden,omitempty"` // absolute path
	Actual string `json:"actual,omitempty"` // absolute path when written
}

SnapEvent is one snapshot assertion for SHIREI_SNAP_REPORT.

type SnapResult added in v0.6.5

type SnapResult struct {
	Name   string // snapshot id (basename without .png)
	Status string // SnapMatch | SnapMismatch | SnapCreated | SnapUpdated | SnapSkip
	Golden string // path used or written
	Actual string // path written on mismatch
	Err    error  // IO / encode / decode failure
	Reason string // skip (or other) explanation
}

SnapResult is the outcome of CompareImage or Snapshot.

func CompareImage added in v0.6.5

func CompareImage(name, goldenPath string, img *image.RGBA) SnapResult

CompareImage compares img to the PNG at goldenPath (create / update / mismatch / match). name is the snapshot id for reports.

func Snapshot added in v0.6.5

func Snapshot(testName, name string, w, h int, fn FrameFn) SnapResult

Snapshot renders fn at the given logical size, compares against testdata/snapshots/<name>.png, and calls ReportSnap with the outcome. Skips (Status SnapSkip) when the host has no usable fonts.

Each invocation renders inside a fresh pointer-scoped container so every snapshot is a fresh app launch: stable identity across the invocation's settle frames, no state inherited from earlier invocations in the same process. RenderToImage resets the global input/focus session for the same reason.

type SoftRenderer

type SoftRenderer struct {
	// contains filtered or unexported fields
}

SoftRenderer holds the reusable framebuffer and the clip/transparency stacks. One per window/consumer; not safe for concurrent use (neither is a frame).

func (*SoftRenderer) RegionCacheBytes

func (r *SoftRenderer) RegionCacheBytes() (entries int, bytes int64)

RegionCacheBytes reports the number of cached region bitmaps and their total byte size, for the perf printer.

func (*SoftRenderer) RegionStats

func (r *SoftRenderer) RegionStats() RegionStats

RegionStats returns and resets the measure-only region-cache counters. A backend's perf printer reads it once a second.

func (*SoftRenderer) Render

func (r *SoftRenderer) Render(surfaces []Surface, devW, devH int, scale float32) *Framebuffer

Render rasterizes the surface list into the renderer's own (reused) framebuffer at the given device dimensions and scale (device pixels per logical point), and returns it.

func (*SoftRenderer) RenderInto

func (r *SoftRenderer) RenderInto(dst []byte, stride, devW, devH int, scale float32, surfaces []Surface)

RenderInto rasterizes into a caller-owned BGRA buffer instead of the renderer's own — e.g. an IOSurface / DIB section / shm region that the backend presents zero-copy. dst must be at least stride*devH bytes; stride is bytes per row and may exceed devW*4 (row padding/alignment is honored).

type Stretch

type Stretch = font.Stretch

type Style

type Style = font.Style

type StyleSpan added in v0.5.1

type StyleSpan struct {
	From, To int
	Style    TextStyleAttrs
}

StyleSpan is one half-open rune range [From, To) with a COMPLETE style for that range. Produced by resolving TextSpan requests against a paragraph base (copy(base)+mods). The pipeline only consumes these fully resolved ranges after flattenStyleSpans.

Overlapping spans are composed internally before shaping/layout: fields that differ from the paragraph base are treated as deltas and stacked in list order (so bold then highlight keeps both on the intersection). A later span cannot clear an earlier override back to the base value (delta-vs-base limitation).

func ResolveSpan added in v0.6.0

func ResolveSpan(from, to int, base TextStyleAttrs, mods ...TextStyleFn) StyleSpan

ResolveSpan builds a fully resolved StyleSpan: copy base, apply mods. Prefer Span + Text/ShapeText for UI; use this when a StyleSpan value is needed directly (tests, flatten helpers).

type Surface

type Surface struct {
	Rect    Rect
	Color1  Vec4
	Color2  Vec4
	Corners Vec4 // corner radius

	Stroke     float32 // for borders!
	ImageId    ImageId
	ImageScale bool // if set, scales image down to fit surface!

	FontId      FontId
	GlyphId     GlyphId
	GlyphOffset Vec2

	Clip ClipStackOp

	Transparency    float32
	PopTransparency bool
}

type TextLayout

type TextLayout struct {
	Segments []GlyphsSegment
}

type TextSpan added in v0.6.0

type TextSpan struct {
	From, To int
	// contains filtered or unexported fields
}

TextSpan is a deferred range style for Text / ShapeText: mods are applied to the call's paragraph base when the call runs (never field-wise inherit). Build with Span(from, to, mods...).

func Span added in v0.5.1

func Span(from, to int, mods ...TextStyleFn) TextSpan

Span builds a deferred range style for Text / ShapeText: when the call runs, mods are applied to that call's paragraph base for [from, to).

type TextStyleAttrs added in v0.6.0

type TextStyleAttrs struct {
	FontFamilies []string
	FontAspect

	TextColor Vec4
	FontSize  f32

	// Background is a highlight painted behind glyphs (zero = none).
	// Distinct from layout AttrSet.Background.
	Background Vec4
	Underline  bool
	Strike     bool
}

func DefaultTextStyle

func DefaultTextStyle() TextStyleAttrs

func TextStyle

func TextStyle(mods ...TextStyleFn) TextStyleAttrs

TextStyle returns the current container text style with mods applied. Pass the result as Text's second argument. Does not mutate the current style for siblings. Offline code with no open container gets DefaultTextStyle() as the base.

func TextStyleClone added in v0.6.0

func TextStyleClone(s TextStyleAttrs) (out TextStyleAttrs)

TextStyleClone returns a deep copy of `s` so cascaded / amended styles do not share the Families backing array with the parent.

func TextStyleWith added in v0.6.0

func TextStyleWith(base TextStyleAttrs, mods ...TextStyleFn) TextStyleAttrs

TextStyleWith returns a copy of base with mods applied in order.

type TextStyleFn added in v0.6.0

type TextStyleFn func(*TextStyleAttrs)

TextStyleFn amends a fully resolved TextStyle (copy+mods). Same mods work for container AmendTextStyle, call-local Styles, and Span ranges.

func ComposeTextStyles added in v0.6.0

func ComposeTextStyles(fns ...TextStyleFn) TextStyleFn

ComposeTextStyles bundles several text style setters into one TextStyleFn.

func FontSize

func FontSize(h float32) TextStyleFn

FontSize sets the font size.

func FontStyle

func FontStyle(w Style) TextStyleFn

FontStyle sets the font style (e.g. normal, italic).

func FontWeight

func FontWeight(w Weight) TextStyleFn

FontWeight sets the font weight (e.g. regular, bold).

func Fonts

func Fonts(fs ...string) TextStyleFn

Fonts sets preferred font families, tried in order ahead of the defaults.

func TextBackground added in v0.5.1

func TextBackground(h, s, l, a float32) TextStyleFn

TextBackground sets a highlight color painted behind glyphs (HSLA).

func TextBackgroundVec added in v0.5.1

func TextBackgroundVec(v Vec4) TextStyleFn

TextBackgroundVec sets a highlight color painted behind glyphs.

func TextColor

func TextColor(h, s, l, a float32) TextStyleFn

TextColor sets the text color as HSLA (hue, saturation, lightness, alpha).

func TextColorVec

func TextColorVec(v Vec4) TextStyleFn

TextColorVec sets the text color from an HSLA Vec4.

func TextStrike added in v0.5.1

func TextStrike(on bool) TextStyleFn

TextStrike enables or disables strikethrough on the text style.

func TextUnderline added in v0.5.1

func TextUnderline(on bool) TextStyleFn

TextUnderline enables or disables underline on the text style.

type TouchInfo added in v0.6.0

type TouchInfo struct {
	Active bool
	Id     uint32 // stable for the life of this contact; new value next contact
	Pos    Vec2   // logical points, same space as MousePoint
}

TouchInfo is one contact in ui.Host.Input.Touches. Backends fill Active/Id/Pos; force/radius/rotation are omitted until needed.

func TouchById added in v0.6.0

func TouchById(id uint32) (TouchInfo, bool)

TouchById returns the active contact with the given id, if any.

type UI added in v0.6.0

type UI struct {
	// Host is backend ↔ app I/O for this UI (window size, input, clipboard
	// requests, IME anchors, next-frame, …). Nested rather than embedded so
	// call sites read ui.Host.* during migration; embedding is optional later.
	Host Host

	SurfaceCount int // debug: surfaces emitted last pass

	// Frame clock and pass control (per-UI).
	FrameNumber int64
	// contains filtered or unexported fields
}

UI is the per-window (per-frame-world) runtime context. Today the process has a single package-level ui pointer; Measure and multi-window will swap or allocate additional *UI values.

Field migration onto UI is incremental: some state still lives in package vars and will move here over time.

Shared caches (fonts, shape, glyphs, images, …) are process-global on package res / SharedResources() — not a field of UI.

func ActiveUI added in v0.6.0

func ActiveUI() *UI

ActiveUI returns the currently building/presenting UI. Nil only before init.

func NewUI added in v0.6.0

func NewUI() *UI

NewUI constructs a UI world. Shared resources are always the process pack (SharedResources / res), not owned by the UI.

type Vec2

type Vec2 = [2]f32

func CachedMeasure added in v0.6.5

func CachedMeasure[K comparable](key K, maxSize Vec2, fn FrameFn) Vec2

CachedMeasure returns Measure(maxSize, fn), memoized by key plus maxSize and host salts (window scale, font lookup epoch). fn must be a pure layout builder for that key: skipped on cache hit, so do not rely on measure-only side effects.

Key must capture every caller-owned input that affects size (e.g. document generation, row width, item index). Include a call-site tag in the key when unrelated builders could otherwise collide.

func GetAvailableSize

func GetAvailableSize() Vec2

GetAvailableSize returns the size of the current container's content area — its resolved size minus padding.

func GetLastSize

func GetLastSize() Vec2

should be considered a low level function it returns the resolved *intrinsic* size of the last child of the current container

func GetResolvedSize

func GetResolvedSize() Vec2

GetResolvedSize returns the current container's resolved (laid-out) size.

func GetScrollOffset

func GetScrollOffset() Vec2

GetScrollOffset returns the current container's scroll offset.

func Measure added in v0.6.0

func Measure(maxSize Vec2, fn FrameFn) Vec2

Measure lays out fn under maxSize constraints in a fresh *UI and returns the intrinsic resolved size of that layout. Process-shared Resources (fonts, shape caches, images, …) are unchanged — Measure never frees shared caches.

maxSize is applied as the measure root's MaxSize (zero components mean unconstrained on that axis, same as MaxSize elsewhere). Host.WindowSize is set to the same value so widgets that read window size see the budget.

Call sites:

  • Inside RunFrameFn (or another Measure): nested; reuses the caller's frame lock via a fresh UI swap, then restores the previous active UI.
  • Outside a frame: takes the frame mutex like RunFrameFn.

Caveat: identity hooks (Use) on the live tree are not visible here — the measure UI has a fresh identity root, so ephemeral component state is at defaults unless the caller put that state on app-owned data.

func PadSize

func PadSize(padding Vec4) Vec2

PadSize returns the space a padding Vec4 consumes: combined left+right padding in x, combined top+bottom padding in y.

func RestrictedSize

func RestrictedSize(size Vec2, maxSize Vec2) Vec2

RestrictedSize scales size down to fit within maxSize while preserving aspect ratio. A zero maxSize component leaves that dimension unconstrained; size is only ever shrunk, never enlarged.

func Vec2Add

func Vec2Add(v1 Vec2, v2 Vec2) Vec2

Vec2Add returns the component-wise sum v1 + v2.

func Vec2Mul

func Vec2Mul(v1 Vec2, f float32) Vec2

Vec2Mul returns v1 scaled by the scalar f.

func Vec2Sub

func Vec2Sub(v1 Vec2, v2 Vec2) Vec2

Vec2Sub returns the component-wise difference v1 - v2.

type Vec4

type Vec4 = [4]f32

func ContrastingTextColor

func ContrastingTextColor(bg Vec4) Vec4

ContrastingTextColor picks white or near-black — whichever has the higher WCAG contrast ratio — for text/icons drawn over an HSLA background color. Ignores bg's alpha: callers with a translucent background should pass the color it's actually blended to. https://www.w3.org/TR/WCAG20/#relativeluminancedef

func N4

func N4(v f32) Vec4

N4 returns a Vec4 with all four components set to v — handy for uniform padding, corner radii, or grayscale colors.

func PaddingVH

func PaddingVH(v float32, h float32) Vec4

PaddingVH builds a padding Vec4 from a vertical (top and bottom) and a horizontal (left and right) amount.

func Vec4Add

func Vec4Add(v1 Vec4, v2 Vec4) Vec4

Vec4Add returns the component-wise sum v1 + v2.

func Vec4Sub

func Vec4Sub(v1 Vec4, v2 Vec4) Vec4

Vec4Sub returns the component-wise difference v1 - v2.

type Weight

type Weight = font.Weight

Directories

Path Synopsis
Package app is shirei's GOOS-selected native backend.
Package app is shirei's GOOS-selected native backend.
Package audio is the pure-Go mixing layer above app.StartAudio: a mixer of active voices plus a couple of generic voice types.
Package audio is the pure-Go mixing layer above app.StartAudio: a mixer of active voices plus a couple of generic voice types.
behavior_test
btmode
Package btmode is the shared CLI / window contract for behavior_test programs.
Package btmode is the shared CLI / window contract for behavior_test programs.
kanban-ordered-drop command
Behavior test: ordered kanban drop inserts at the highlighted index, not always at lane end.
Behavior test: ordered kanban drop inserts at the highlighted index, not always at lane end.
logview-stream command
modal-nested-panel command
Behavior test: PopupPanel opened from inside a Modal runs in the same PopupsHost pass (drain-until-empty) and stacks above the modal.
Behavior test: PopupPanel opened from inside a Modal runs in the same PopupsHost pass (drain-until-empty) and stacks above the modal.
popup-hit-stack command
Behavior test: pointer hit-testing across stacked layers (content → panel → modal).
Behavior test: pointer hit-testing across stacked layers (content → panel → modal).
text-view-large command
textinput command
toast command
Behavior test: toast notifications appear on the next frame after a click, pin the dismiss control near the card’s right edge, and auto-dismiss when their lifetime elapses.
Behavior test: toast notifications appear on the next frame after a click, pin the dismiss control near the card’s right edge, and auto-dismiss when their lifetime elapses.
cmd
behavior_runner command
Command behavior_runner is a list-only GUI for shirei/behavior_test programs.
Command behavior_runner is a list-only GUI for shirei/behavior_test programs.
shirei_bundle command
shirei_bundle builds release packages for shirei apps.
shirei_bundle builds release packages for shirei apps.
shirei_mobilerun command
shirei_mobilerun builds and launches shirei main packages on iOS or Android for local development (device/simulator iteration).
shirei_mobilerun builds and launches shirei main packages on iOS or Android for local development (device/simulator iteration).
shirei_tester command
Command shirei_tester is an IDE-style snapshot test runner (usually for Shirei UI tests, works for any Go module that follows the same patterns).
Command shirei_tester is an IDE-style snapshot test runner (usually for Shirei UI tests, works for any Go module that follows the same patterns).
shirei_web command
Command shirei_web builds a shirei app for GOOS=js/GOARCH=wasm into a static site directory (index.html, wasm_exec.js, main.wasm, .headers, embed.js).
Command shirei_web builds a shirei app for GOOS=js/GOARCH=wasm into a static site directory (index.html, wasm_exec.js, main.wasm, .headers, embed.js).
Package cocoabackend is a direct-macOS (AppKit) backend for shirei.
Package cocoabackend is a direct-macOS (AppKit) backend for shirei.
example command
Manual test harness for the cocoa backend.
Manual test harness for the cocoa backend.
demos
animate-size command
balls-buckets command
browse command
browse: two-tab network demo for desktop and iPhone.
browse: two-tab network demo for desktop and iPhone.
color-picker command
color-picker: one shared HSLA color edited three ways — channel sliders whose tracks show the colors each slider can pick, a saturation×lightness grid at the current hue, and a hue/saturation wheel at the current lightness.
color-picker: one shared HSLA color edited three ways — channel sliders whose tracks show the colors each slider can pick, a saturation×lightness grid at the current hue, and a hue/saturation wheel at the current lightness.
custom-buttons command
custom-icon-fonts command
custom-icon-fonts demos IconGlyph with a third-party icon font: register Remix Icon via UseFontBytes, define IconGlyph values with Font set to "remixicon", and pass them to Icon / Button.
custom-icon-fonts demos IconGlyph with a third-party icon font: register Remix Icon via UseFontBytes, define IconGlyph values with Font set to "remixicon", and pass them to Icon / Button.
custom-radios command
custom-sliders command
custom-toggles command
font-scan command
font-scan exercises critical-path vs background system font discovery.
font-scan exercises critical-path vs background system font discovery.
image-diff-1 command
image-diff-2 command
image-list command
image-resize command
image-viewer command
kanban command
landing-snippets command
landing-snippets renders the small code/output examples used on the Shirei landing page.
landing-snippets renders the small code/output examples used on the Shirei landing page.
layout command
layout-shell/step01 command
Layout tutorial step 01: paint the engine root.
Layout tutorial step 01: paint the engine root.
layout-shell/step02 command
Layout tutorial step 02: top bar + body (column + Grow).
Layout tutorial step 02: top bar + body (column + Grow).
layout-shell/step03 command
Layout tutorial step 03: body splits into server rail + rest (Row).
Layout tutorial step 03: body splits into server rail + rest (Row).
layout-shell/step04 command
Layout tutorial step 04: rest → channels | main | members.
Layout tutorial step 04: rest → channels | main | members.
layout-shell/step05 command
Layout tutorial step 05: subdivide main into header | messages | compose.
Layout tutorial step 05: subdivide main into header | messages | compose.
layout-shell/step06 command
Layout tutorial step 06: name every region (including main's three rows).
Layout tutorial step 06: name every region (including main's three rows).
layout-shell/step07 command
Layout tutorial step 07: server rail content (column of icons).
Layout tutorial step 07: server rail content (column of icons).
layout-shell/step08 command
Layout tutorial step 08: channel list (header + scrollable rows).
Layout tutorial step 08: channel list (header + scrollable rows).
layout-shell/step09 command
Layout tutorial step 09: main column — intentional WRONG scroll recipe.
Layout tutorial step 09: main column — intentional WRONG scroll recipe.
layout-shell/step10 command
Layout tutorial step 10: fix compose with Extrinsic.
Layout tutorial step 10: fix compose with Extrinsic.
layout-shell/step11 command
Layout tutorial step 11: same fix packaged as Viewport.
Layout tutorial step 11: same fix packaged as Viewport.
layout-shell/step12 command
Layout tutorial step 12: members list (Viewport scroll regions).
Layout tutorial step 12: members list (Viewport scroll regions).
layout-shell/step13 command
Layout tutorial step 13: polish — light chrome + real TextInput compose.
Layout tutorial step 13: polish — light chrome + real TextInput compose.
layout-shell/step14 command
Layout tutorial step 14: VirtualList for messages + members (scale).
Layout tutorial step 14: VirtualList for messages + members (scale).
layout-shell/step15 command
Custom-widgets tutorial sample: chat compose on top of layout step 14.
Custom-widgets tutorial sample: chat compose on top of layout step 14.
layout-shell/step15a command
Custom-widgets intermediate: circular ProcessButtonEvents send + default TextInput.
Custom-widgets intermediate: circular ProcessButtonEvents send + default TextInput.
layout-shell/step16 command
Custom-widgets tutorial sample: dark chat shell + light scrollbar tint.
Custom-widgets tutorial sample: dark chat shell + light scrollbar tint.
measure-list command
measure-list: scrollable cards with title + free-form description.
measure-list: scrollable cards with title + free-form description.
modal-panel command
Demo: a Modal that opens a PopupPanel from inside its card.
Demo: a Modal that opens a PopupPanel from inside its card.
orientation command
orientation: Host.PreferredOrientation at runtime.
orientation: Host.PreferredOrientation at runtime.
script-fallback command
script-fallback shapes a fixed mixed-script corpus with the default UI font so per-rune fallback walks the system chain.
script-fallback shapes a fixed mixed-script corpus with the default UI font so per-rune fallback walks the system chain.
small command
split-panes command
style-spans command
synthpad command
synthpad: a small grid of tone pads for exercising app.StartAudio.
synthpad: a small grid of tone pads for exercising app.StartAudio.
temp-converter command
text-fields command
text-view command
theme command
toast command
toast demos the notification stack: colors, title/body, icons, corners, countdown bar, custom content, and wrapping.
toast demos the notification stack: colors, title/body, icons, corners, countdown bar, custom content, and wrapping.
vlist-pin command
window-size command
window-size: probe WindowSize vs soft keyboard / orientation (iOS-focused).
window-size: probe WindowSize vs soft keyboard / orientation (iOS-focused).
examples
dir_weight command
fontviewer command
Command fontviewer is a browsable catalog of the system fonts shirei has discovered.
Command fontviewer is a browsable catalog of the system fonts shirei has discovered.
hacker-news-reader command
hacker-news-reader: browse Hacker News feeds and threaded comments.
hacker-news-reader: browse Hacker News feeds and threaded comments.
haystack command
haystack: a "find in files" utility built on shirei.
haystack: a "find in files" utility built on shirei.
icons command
Command icons is a browsable gallery of shirei's bundled icon fonts: every Microns (Sym*) and Typicons (Typ*) rune constant from the widgets package, in a filterable virtualized grid.
Command icons is a browsable gallery of shirei's bundled icon fonts: every Microns (Sym*) and Typicons (Typ*) rune constant from the widgets package, in a filterable virtualized grid.
piano command
piano: a one-row piano keyboard played with the computer keyboard, multi-touch, or mouse, with a small Go port of awtar's Karplus-Strong string synth.
piano: a one-row piano keyboard played with the computer keyboard, multi-touch, or mouse, with a small Go port of awtar's Karplus-Strong string synth.
see_exe command
The see_exe GUI: header stacked bar (the whole file at a glance), a sortable module table annotated with why-chains, and a detail pane with the selected module's require edges in both directions.
The see_exe GUI: header stacked bar (the whole file at a glance), a sortable module table annotated with why-chains, and a detail pane with the selected module's require edges in both directions.
du module
ferry module
git_history module
ext
camera module
internal
iconimg
Package iconimg loads and prepares window-icon images for the native backends: decode to straight-alpha NRGBA, downsample, square-pad.
Package iconimg loads and prepares window-icon images for the native backends: decode to straight-alpha NRGBA, downsample, square-pad.
qwerty
Package qwerty maps hardware key positions to shirei KeyCodes named by their US-QWERTY legends, making key identity layout-independent: pressing the second key of the top letter row yields KeyW whether the OS layout is QWERTY, AZERTY, Dvorak, or Arabic.
Package qwerty maps hardware key positions to shirei KeyCodes named by their US-QWERTY legends, making key identity layout-independent: pressing the second key of the top letter row yields KeyW whether the OS layout is QWERTY, AZERTY, Dvorak, or Arabic.
wayland/cursorshape
Package cursorshape implements the staging wp-cursor-shape-v1 protocol (not shipped by upstream neurlang; originally hand-written inside shirei's wayland backend and graduated here).
Package cursorshape implements the staging wp-cursor-shape-v1 protocol (not shipped by upstream neurlang; originally hand-written inside shirei's wayland backend and graduated here).
wayland/os
Package os implements an operating system routines useful for graphics
Package os implements an operating system routines useful for graphics
wayland/textinput
Package textinput implements the unstable text-input-v3 protocol (zwp_text_input_manager_v3 / zwp_text_input_v3).
Package textinput implements the unstable text-input-v3 protocol (zwp_text_input_manager_v3 / zwp_text_input_v3).
wayland/wl
Package wl implements the stable Wayland protocol
Package wl implements the stable Wayland protocol
wayland/wlclient
Package wlclient implements a wayland-client like api
Package wlclient implements a wayland-client like api
wayland/wlcursor
Package wlcursor implements a Wayland cursor
Package wlcursor implements a Wayland cursor
wayland/wlcursor/xcursor
Package xcursor loads and parses the X cursor
Package xcursor loads and parses the X cursor
wayland/xdg
Package xdg implements the stable XDG Window Manager Base protocol
Package xdg implements the stable XDG Window Manager Base protocol
wayland/xkbcommon
Package xkbcommon wraps the libxkbcommon library.
Package xkbcommon wraps the libxkbcommon library.
Package layout_tests contains snapshot tests for the shirei layout engine.
Package layout_tests contains snapshot tests for the shirei layout engine.
Package waylandbackend is shirei's native Wayland shell: it owns the window and input and presents the shared core software renderer's BGRA buffer via a wl_shm shared-memory pool (no per-frame pixels over the socket), mirroring what cocoabackend/win32backend/x11backend do on their platforms.
Package waylandbackend is shirei's native Wayland shell: it owns the window and input and presents the shared core software renderer's BGRA buffer via a wl_shm shared-memory pool (no per-frame pixels over the socket), mirroring what cocoabackend/win32backend/x11backend do on their platforms.
Win32 API surface used by the backend: lazily-bound user32/gdi32/kernel32 procedures plus the constants and structs they need.
Win32 API surface used by the backend: lazily-bound user32/gdi32/kernel32 procedures plus the constants and structs they need.
Package x11backend is a direct-X11 backend for shirei: it opens a window via the X11 core protocol (pure Go, github.com/jezek/xgb), routes input, and presents the core software renderer's BGRA buffer with PutImage.
Package x11backend is a direct-X11 backend for shirei: it opens a window via the X11 core protocol (pure Go, github.com/jezek/xgb), routes input, and presents the core software renderer's BGRA buffer with PutImage.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL