renderer

package
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: Jul 27, 2026 License: GPL-2.0 Imports: 22 Imported by: 0

README

renderer

thrupty's own WebGPU render host — the cellgpu backend. Owns the gogpu window and event loop, the MSDF glyph cache and atlas, and the render pass: a single fullscreen triangle whose WGSL shader expands the terminal cell grid into pixels (refterm's cell-expansion design). Text supports CJK wide glyphs, combining marks, and ligatures.

The API is callback-driven: the host supplies the baked cell grid once per frame and receives input/resize events.

app, err := renderer.New(renderer.AppConfig{
	Title:    "thruPTY",
	Width:    1280,
	Height:   720,
	FontPath: "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf",
	FontSize: 16,
})
if err != nil {
	log.Fatal(err)
}

app.SetFrameFunc(func() []renderer.Cell { return bakedGrid })
app.SetKeyFunc(func(e renderer.KeyEvent) { /* translate & write to pty */ })

log.Fatal(app.Run())

Debug helpers: F11 saves thrupty_screenshot.png, F12 dumps the glyph atlas to thrupty_atlas.png; the window title shows live grid size, FPS, and glyph cache statistics.

Embedding scenarios normally use termui + vtuibridge instead, which draw through vtui hosts (gogpu, X11, Wayland, or console ANSI).

Documentation

Overview

Package renderer is thrupty's own WebGPU render host — the cellgpu backend. It owns the window and event loop (gogpu), the MSDF glyph cache and atlas, and a single fullscreen-triangle pass whose WGSL shader expands the terminal cell grid into pixels: refterm's cell-expansion design, ported to Go and made cross-platform.

The App API is callback-driven: the host supplies the baked cell grid once per frame (SetFrameFunc) and receives input and resize events. Embedding scenarios normally use packages termui and vtuibridge instead, which render through vtui hosts (gogpu, X11, Wayland, or console ANSI).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FontCandidates added in v0.1.3

func FontCandidates(requested string) []string

FontCandidates builds the probe list for a requested font name, mirroring vtui's gui_font.go: the requested name (as-is, with a .ttf suffix, and inside the usual system font directories, one subdirectory deep), followed by the default monospace fonts per OS. An empty requested name yields just the defaults.

Types

type App

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

App wraps a gogpu window and the terminal renderer pipeline.

func New

func New(cfg AppConfig) (*App, error)

New creates a new renderer application. It does not open the window yet; call Run to start the event loop.

func (*App) Bake

func (a *App) Bake(dst []Cell, text []termcell.TextCell, wide []uint8, direct, directItal *[directTileCount]GlyphInfo) []Cell

Bake converts the terminal's text grid into the GPU cell payload, reusing dst when it is large enough. See GlyphCache.Bake. It is only valid after the renderer has been initialized (i.e. inside a frame callback).

func (*App) CellHeight

func (a *App) CellHeight() float32

CellHeight returns the terminal cell height in pixels.

func (*App) CellSize

func (a *App) CellSize() (width, height float32)

CellSize returns the terminal cell dimensions in framebuffer pixels. It is only valid after the renderer has been initialized.

func (*App) CellWidth

func (a *App) CellWidth() float32

CellWidth returns the terminal cell width in pixels.

func (*App) ClipboardRead

func (a *App) ClipboardRead() (string, error)

ClipboardRead reads text content from the system clipboard.

func (*App) ClusterGlyphs

func (a *App) ClusterGlyphs(s string, flags uint32) ([]GlyphInfo, error)

ClusterGlyphs returns one glyph tile per terminal cell occupied by the Unicode cluster s. The flags argument uses the same TerminalCell* constants as the terminal grid (only italic currently changes glyph geometry).

func (*App) CurrentStats

func (a *App) CurrentStats() Stats

CurrentStats returns the most recent renderer statistics. FPS is updated once per second; other fields reflect the last rendered frame.

func (*App) DirectTile

func (a *App) DirectTile(codepoint uint16) (GlyphInfo, bool)

DirectTile returns the atlas tile info for a direct ASCII codepoint. It is only valid after the renderer has been initialized (i.e. inside a frame callback).

func (*App) DirectTileItalic

func (a *App) DirectTileItalic(codepoint uint16) (GlyphInfo, bool)

DirectTileItalic returns the italic atlas tile info for a direct ASCII codepoint.

func (*App) DumpAtlas

func (a *App) DumpAtlas(path string) error

DumpAtlas saves the current MSDF atlas texture as a PNG for debugging.

func (*App) GridSize

func (a *App) GridSize() (cols, rows int)

GridSize returns the current terminal grid dimensions in cells. It is only valid after the renderer has been initialized.

func (*App) Quit

func (a *App) Quit()

Quit asks the gogpu event loop to exit after the current frame (used to close the window when the shell session ends).

func (*App) Run

func (a *App) Run() error

Run starts the event loop and blocks until the window is closed.

func (*App) Screenshot

func (a *App) Screenshot(path string) error

Screenshot renders one frame off-screen and saves it as a PNG. It must be called while the event loop is running (e.g. from a callback).

func (*App) SetFrameFunc

func (a *App) SetFrameFunc(fn FrameFunc)

SetFrameFunc sets the callback that supplies the terminal cell grid each frame.

func (*App) SetKeyFunc

func (a *App) SetKeyFunc(fn KeyFunc)

SetKeyFunc sets the callback for physical key presses and releases.

func (*App) SetMouseFunc

func (a *App) SetMouseFunc(fn MouseFunc)

SetMouseFunc sets the callback for mouse movement, presses and releases.

func (*App) SetResizeFunc

func (a *App) SetResizeFunc(fn ResizeFunc)

SetResizeFunc sets the callback that is invoked when the visible cell grid changes size. The callback receives the new column and row counts.

func (*App) SetTextFunc

func (a *App) SetTextFunc(fn TextFunc)

SetTextFunc sets the callback for text input produced by key presses.

func (*App) ShapeLine

func (a *App) ShapeLine(text string, flags uint32) ([]CellRun, error)

ShapeLine splits a UTF-8 text run into cell runs using the font shaper.

type AppConfig

type AppConfig struct {
	Title    string
	Width    int
	Height   int
	FontPath string
	FontSize float64
}

AppConfig configures the terminal renderer window.

type Cell

type Cell = termcell.Cell

Cell is the per-cell GPU payload consumed by the renderer's cell shader. It is an alias so callers can share the layout without a type conversion.

type CellRun

type CellRun = termcell.CellRun

CellRun describes one layout unit returned by ShapeLine: a Unicode cluster that occupies Width terminal cells and consumes ByteLen bytes of source text. Alias of termcell.CellRun (see GlyphInfo above).

type CellWidthMode

type CellWidthMode int

CellWidthMode selects how the terminal cell width is derived from the font.

const (
	// CellWidthFromFont uses the horizontal advance of the 'M' glyph.
	CellWidthFromFont CellWidthMode = iota
	// CellWidthFromHeight uses a fixed ratio of the cell height (0.6).
	CellWidthFromHeight
)

type Config

type Config struct {
	FontPath string
	FontSize float64
}

Config holds renderer creation settings.

type Font

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

Font holds a loaded font face and the tools to extract glyph outlines.

func LoadBestFont added in v0.1.3

func LoadBestFont(requested string, size float64) (*Font, error)

LoadBestFont tries each candidate in order and returns the first font that loads (vtui's loadBestFont approach, but through gg/text since the renderer needs glyph outlines, not bitmap faces).

func LoadFont

func LoadFont(path string, size float64) (*Font, error)

LoadFont loads a TrueType/OpenType font from the given path at the specified size in pixels (ppem).

func (*Font) Close

func (f *Font) Close() error

Close releases the font source.

func (*Font) GlyphAdvance

func (f *Font) GlyphAdvance(r rune) float64

GlyphAdvance returns the horizontal advance width for the glyph identified by rune r at the face size.

func (*Font) GlyphBounds

func (f *Font) GlyphBounds(r rune) text.Rect

GlyphBounds returns the bounding box for the glyph identified by rune r at the face size.

func (*Font) GlyphOutline

func (f *Font) GlyphOutline(r rune) (*text.GlyphOutline, error)

GlyphOutline returns the vector outline for a rune, or nil for an empty glyph.

func (*Font) GlyphOutlineItalic

func (f *Font) GlyphOutlineItalic(r rune) (*text.GlyphOutline, error)

GlyphOutlineItalic returns the italic/varied vector outline for a rune. If the font is not variable or lacks slant/italic axis, falls back to regular outline.

func (*Font) IsVariable

func (f *Font) IsVariable() bool

IsVariable returns true if the font supports OpenType variations.

func (*Font) Metrics

func (f *Font) Metrics() text.Metrics

Metrics returns the font metrics at the face size.

type FrameFunc

type FrameFunc func() []Cell

FrameFunc is called each frame to obtain the current terminal cell grid.

type GlyphCache

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

GlyphCache maps Unicode codepoints to MSDF atlas tiles.

It follows the refterm idea of a hash → tile cache, but leverages gg/text/msdf.AtlasManager for the actual distance-field generation and grid-packed atlas storage.

func NewGlyphCache

func NewGlyphCache(font *Font, widthMode CellWidthMode) (*GlyphCache, error)

NewGlyphCache creates a cache and pre-populates the direct ASCII tiles.

func (*GlyphCache) AtlasData

func (c *GlyphCache) AtlasData() []byte

AtlasData returns the RGB pixel data for the first (and only) atlas.

func (*GlyphCache) AtlasSize

func (c *GlyphCache) AtlasSize() int

AtlasSize returns the atlas texture size in pixels.

func (*GlyphCache) Bake

func (c *GlyphCache) Bake(dst []termcell.Cell, text []termcell.TextCell, wide []uint8, direct, directItal *[directTileCount]termcell.GlyphInfo) []termcell.Cell

Bake converts the terminal's text grid (the single source of truth) into the GPU cell payload consumed by the renderer and vtuibridge.Composite. The result reproduces exactly what the layout pass used to write into the grid: direct ASCII runes resolve through the reserved tile tables (italic variant when the style flag is set and the variant exists), clusters and non-direct runes go through GetCluster — always a cache hit, because the layout's shaping pass already resolved the same cluster with the same italic flag; no re-shaping happens here. Reverse-video swaps fg/bg and invisible blanks the quad, matching the old SetCellDirect word layout (Foreground | flags<<24, Background, UV/quad from GlyphInfo).

wide mirrors the terminal's Wide table (bit 7 = continuation cell); it is only used to pick the per-cell tile of a wide cluster. dst is reused when large enough; the returned slice is len(text) cells long.

func (*GlyphCache) CellSize

func (c *GlyphCache) CellSize() (width, height float32)

CellSize returns the terminal cell dimensions in pixels.

func (*GlyphCache) DirectTile

func (c *GlyphCache) DirectTile(codepoint uint16) (GlyphInfo, bool)

DirectTile returns the tile info for a direct ASCII codepoint.

func (*GlyphCache) DirectTileItalic

func (c *GlyphCache) DirectTileItalic(codepoint uint16) (GlyphInfo, bool)

DirectTileItalic returns the italic tile info for a direct ASCII codepoint.

func (*GlyphCache) DirtyRects

func (c *GlyphCache) DirtyRects() []image.Rectangle

DirtyRects returns the atlas regions that have changed since the last upload.

func (*GlyphCache) GetCluster

func (c *GlyphCache) GetCluster(s string, italic bool) ([]GlyphInfo, error)

GetCluster returns the glyph tiles for a Unicode cluster (a single codepoint, a base + combining marks, a ligature, or a wide icon). The returned slice has one entry per terminal cell occupied by the cluster.

func (*GlyphCache) GetOrInsert

func (c *GlyphCache) GetOrInsert(r rune) (GlyphInfo, error)

GetOrInsert returns the tile info for a rune, generating it if necessary.

func (*GlyphCache) GetOrInsertItalic

func (c *GlyphCache) GetOrInsertItalic(r rune) (GlyphInfo, error)

GetOrInsertItalic returns the italic tile info for a rune. If the font does not support variable italic, falls back to regular.

func (*GlyphCache) GlyphSize

func (c *GlyphCache) GlyphSize() int

GlyphSize returns the tile size in pixels.

func (*GlyphCache) RGBAToRGBA

func (c *GlyphCache) RGBAToRGBA() []byte

RGBAToRGBA converts the atlas's RGB data to RGBA for GPU upload.

func (*GlyphCache) ShapeLine

func (c *GlyphCache) ShapeLine(line string, flags uint32) ([]CellRun, error)

ShapeLine splits a UTF-8 text run into terminal cell runs. Each run is a grapheme cluster whose width is derived from the font advance. Combining marks are merged with the preceding base cluster.

func (*GlyphCache) Stats

func (c *GlyphCache) Stats() (hits, misses uint64, atlasCount int)

Stats returns cache hits, misses and the number of active atlases.

type GlyphInfo

type GlyphInfo = termcell.GlyphInfo

GlyphInfo describes where a glyph lives in the atlas and how its quad should be positioned inside a terminal cell. UV coordinates are in atlas [0,1] space; quad bounds are in framebuffer pixels relative to the cell top-left. Alias of termcell.GlyphInfo so the terminal package can share the type without importing the GPU-backed renderer.

type KeyEvent

type KeyEvent struct {
	Key  gpucontext.Key
	Mods gpucontext.Modifiers
	Down bool
}

KeyEvent describes a physical key press or release.

type KeyFunc

type KeyFunc func(KeyEvent)

KeyFunc is called for every key press and release.

type MouseEvent

type MouseEvent struct {
	Kind       MouseEventKind
	Button     gpucontext.MouseButton // valid for MousePress/MouseRelease
	WheelDelta int                    // valid for MouseWheel: -1 or 1
	X, Y       int                    // cell coordinates
}

MouseEvent describes a mouse action in grid cell coordinates.

type MouseEventKind

type MouseEventKind int

MouseEventKind identifies the kind of mouse action.

const (
	// MouseMove is pointer movement (with or without buttons held).
	MouseMove MouseEventKind = iota
	// MousePress is a mouse button press.
	MousePress
	// MouseRelease is a mouse button release.
	MouseRelease
	// MouseWheel is one scroll wheel step (WheelDelta carries the direction).
	MouseWheel
)

type MouseFunc

type MouseFunc func(MouseEvent)

MouseFunc is called for mouse movement, presses, releases and wheel steps.

type Renderer

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

Renderer owns the WebGPU pipeline, glyph atlas texture and cell buffer.

func (*Renderer) CacheStats

func (r *Renderer) CacheStats() (hits, misses uint64, atlasCount int)

CacheStats returns glyph cache hits, misses and atlas count.

func (*Renderer) CellAt

func (r *Renderer) CellAt(x, y float64) (col, row int, ok bool)

CellAt converts window pixel coordinates to grid cell coordinates, accounting for the centered margins. The result is clamped to the grid; ok is false until the renderer has drawn its first frame.

func (*Renderer) GridSize

func (r *Renderer) GridSize() (cols, rows int)

GridSize returns the last computed terminal grid dimensions.

func (*Renderer) Resize

func (r *Renderer) Resize(fbWidth, fbHeight uint32) bool

Resize updates the stored grid dimensions for a new framebuffer size. It returns true if the grid actually changed.

type ResizeFunc

type ResizeFunc func(cols, rows int)

ResizeFunc is called when the terminal grid size changes.

type Stats

type Stats struct {
	Cols        int
	Rows        int
	FPS         float64
	CacheHits   uint64
	CacheMisses uint64
	AtlasCount  int
}

Stats holds the latest renderer diagnostics.

type TextFunc

type TextFunc func(text string)

TextFunc is called with the text produced by a key press (after IME / dead-key processing by the OS).

Jump to

Keyboard shortcuts

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