Latest: v0.20.0 β Enterprise-grade GPU backend, color emoji, anti-aliased rendering. Part of the 280K+ LOC Pure Go graphics ecosystem.
Previous: GPU Compute Shaders in Pure Go (v0.15.0)
What is gogpu/gg?
gg is a production-grade 2D graphics library for Go, designed to power:
- IDEs β Syntax highlighting, code rendering, UI components
- Browsers β Canvas-like rendering, WebGPU acceleration
- Professional apps β Vector graphics, data visualization, games
Key differentiator: Pure Go. No CGO. No external dependencies. Just go build.
go get github.com/gogpu/gg@v0.20.0
Feature Overview
| Category | Capabilities |
|---|---|
| Drawing | Rectangles, circles, ellipses, arcs, lines, polygons, stars, bezier curves |
| Paths | MoveTo, LineTo, QuadraticTo, CubicTo, ArcTo, Close + fluent PathBuilder |
| Text | TrueType fonts, MSDF rendering, bidirectional text, color emoji |
| Images | PNG/JPEG I/O, 7 pixel formats, affine transforms, mipmaps |
| Compositing | 29 blend modes (Porter-Duff, Advanced, HSL), layer isolation |
| Rendering | Software (CPU), GPU (Vulkan/Metal/DX12), hybrid auto-selection |
| Performance | SIMD optimization, parallel tile rendering, LRU caching |
Quick Start
Hello World
package main
import "github.com/gogpu/gg"
func main() {
dc := gg.NewContext(512, 512)
defer dc.Close()
// Clear background
dc.ClearWithColor(gg.White)
// Draw anti-aliased circle
dc.SetHexColor("#3498db")
dc.DrawCircle(256, 256, 100)
dc.Fill()
// Draw stroked rectangle
dc.SetHexColor("#e74c3c")
dc.SetLineWidth(3)
dc.DrawRectangle(156, 156, 200, 200)
dc.Stroke()
dc.SavePNG("output.png")
}
Text Rendering
package main
import (
"github.com/gogpu/gg"
"github.com/gogpu/gg/text"
)
func main() {
dc := gg.NewContext(800, 200)
defer dc.Close()
dc.ClearWithColor(gg.White)
// Load font
source, _ := text.NewFontSourceFromFile("Roboto-Regular.ttf")
defer source.Close()
// Render text
dc.SetFont(source.Face(48))
dc.SetColor(gg.Black)
dc.DrawString("Hello, GoGPU!", 50, 100)
// Centered text
dc.DrawStringAnchored("Centered Text", 400, 150, 0.5, 0.5)
dc.SavePNG("text.png")
}
Gradients
dc := gg.NewContext(400, 400)
defer dc.Close()
// Linear gradient
grad := gg.NewLinearGradientBrush(0, 0, 400, 400)
grad.AddColorStop(0, gg.Hex("#ff6b6b"))
grad.AddColorStop(0.5, gg.Hex("#4ecdc4"))
grad.AddColorStop(1, gg.Hex("#45b7d1"))
dc.SetFillBrush(grad)
dc.DrawRectangle(0, 0, 400, 400)
dc.Fill()
dc.SavePNG("gradient.png")
Transforms
dc := gg.NewContext(400, 400)
defer dc.Close()
dc.ClearWithColor(gg.White)
// Save state, transform, draw, restore
dc.Push()
dc.Translate(200, 200)
dc.Rotate(math.Pi / 4) // 45 degrees
dc.Scale(1.5, 1.5)
dc.SetHexColor("#9b59b6")
dc.DrawRectangle(-50, -50, 100, 100)
dc.Fill()
dc.Pop() // Restore original state
dc.SavePNG("transform.png")
Canvas API
gg provides a familiar Canvas-like API inspired by HTML5 Canvas and Cairo:
Drawing Primitives
// Rectangles
dc.DrawRectangle(x, y, width, height)
dc.DrawRoundedRectangle(x, y, w, h, radius)
// Circles and ellipses
dc.DrawCircle(cx, cy, radius)
dc.DrawEllipse(cx, cy, rx, ry)
dc.DrawArc(cx, cy, r, startAngle, endAngle)
// Lines
dc.DrawLine(x1, y1, x2, y2)
dc.MoveTo(x, y)
dc.LineTo(x, y)
// Curves
dc.QuadraticTo(cx, cy, x, y)
dc.CubicTo(cx1, cy1, cx2, cy2, x, y)
// Polygons
dc.DrawPolygon(points...)
dc.DrawRegularPolygon(n, cx, cy, r, rotation)
dc.DrawStar(cx, cy, outerR, innerR, points)
Styles
// Colors
dc.SetColor(gg.Red)
dc.SetRGB(1.0, 0.5, 0.0)
dc.SetRGBA(1.0, 0.5, 0.0, 0.8)
dc.SetHexColor("#3498db")
// Strokes
dc.SetLineWidth(2.0)
dc.SetLineCap(gg.LineCapRound) // Butt, Round, Square
dc.SetLineJoin(gg.LineJoinMiter) // Miter, Round, Bevel
dc.SetDash(5, 3) // Pattern: 5px on, 3px off
// Fill and stroke
dc.Fill()
dc.Stroke()
dc.FillPreserve() // Fill but keep path
dc.StrokePreserve() // Stroke but keep path
Clipping
// Clip to circle
dc.DrawCircle(200, 200, 100)
dc.Clip()
// All subsequent drawing is clipped
dc.DrawImage(img, 0, 0)
dc.ResetClip()
Fluent PathBuilder
Build complex paths with method chaining for use with Scene Graph:
import (
"github.com/gogpu/gg"
"github.com/gogpu/gg/scene"
)
// Build path with fluent API
path := gg.BuildPath().
MoveTo(100, 100).
LineTo(200, 100).
QuadTo(250, 150, 200, 200).
CubicTo(150, 250, 100, 250, 50, 200).
Close().
Circle(300, 150, 50).
Star(400, 150, 40, 20, 5).
RoundRect(50, 250, 100, 80, 10).
Build()
// Use with scene graph
s := scene.NewScene()
s.Fill(scene.FillNonZero, scene.IdentityAffine(),
scene.SolidBrush(gg.Hex("#2ecc71")), scene.NewPathShape(path))
Available shape methods:
-
MoveTo,LineTo,QuadTo,CubicTo,Close -
Circle,Ellipse -
Rect,RoundRect -
Polygon,Star
Text Rendering
Font Loading
// From file
source, err := text.NewFontSourceFromFile("font.ttf")
// From bytes
source, err := text.NewFontSourceFromBytes(fontBytes)
// Create face at specific size
face := source.Face(24) // 24pt
defer source.Close()
Multi-Face (Font Fallback)
// Primary font + emoji fallback
mainFont, _ := text.NewFontSourceFromFile("Roboto.ttf")
emojiFont, _ := text.NewFontSourceFromFile("NotoColorEmoji.ttf")
multiFace, _ := text.NewMultiFace(
mainFont.Face(16),
text.NewFilteredFace(emojiFont.Face(16), text.RangeEmoji),
)
dc.SetFont(multiFace)
dc.DrawString("Hello World! ππ", 50, 100)
Text Layout with Wrapping
opts := text.LayoutOptions{
MaxWidth: 400,
WrapMode: text.WrapWordChar, // Word-first, char fallback
Alignment: text.AlignCenter,
LineSpacing: 1.2,
}
layout := text.LayoutText(longText, face, 16, opts)
// Render using glyph renderer
renderer := text.NewGlyphRenderer()
outlines := renderer.RenderLayout(layout)
// Or access line metrics directly
for _, line := range layout.Lines {
// line.Y is the baseline Y position
// line.Width, line.Ascent, line.Descent available
// line.Glyphs contains positioned glyphs
}
Color Emoji
gg supports both bitmap (CBDT/CBLC) and vector (COLR/CPAL) color emoji:
// Extract bitmap emoji (Noto Color Emoji)
extractor, _ := emoji.NewCBDTExtractor(cbdtData, cblcData)
glyph, _ := extractor.GetGlyph(glyphID, ppem)
img, _ := png.Decode(bytes.NewReader(glyph.Data))
// Parse vector emoji layers (Segoe UI Emoji)
parser, _ := emoji.NewCOLRParser(colrData, cpalData)
glyph, _ := parser.GetGlyph(glyphID, paletteIndex)
for _, layer := range glyph.Layers {
// Render each layer with layer.Color
}
Layer Compositing
29 Blend Modes
Porter-Duff: Clear, Src, Dst, SrcOver, DstOver, SrcIn, DstIn, SrcOut, DstOut, SrcAtop, DstAtop, Xor
Advanced: Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight, SoftLight, Difference, Exclusion
HSL: Hue, Saturation, Color, Luminosity
dc.PushLayer(gg.BlendMultiply, 0.8) // Blend mode + opacity
dc.SetHexColor("#e74c3c")
dc.DrawCircle(150, 200, 100)
dc.Fill()
dc.SetHexColor("#3498db")
dc.DrawCircle(250, 200, 100)
dc.Fill()
dc.PopLayer() // Composite layer
Alpha Masks
// Create mask from shape
dc.DrawCircle(200, 200, 100)
dc.Fill()
mask := dc.AsMask()
// Apply mask to new context
dc2 := gg.NewContext(400, 400)
dc2.SetMask(mask)
dc2.DrawImage(backgroundImage, 0, 0) // Only visible through mask
Scene Graph (Retained Mode)
For complex, frequently-updated scenes:
import (
"github.com/gogpu/gg"
"github.com/gogpu/gg/scene"
)
s := scene.NewScene()
// Build scene graph with layer compositing
s.PushLayer(scene.BlendNormal, 1.0, nil) // blend, alpha, clip
s.Fill(scene.FillNonZero, scene.IdentityAffine(),
scene.SolidBrush(gg.Red), scene.NewCircleShape(150, 200, 100))
s.Fill(scene.FillNonZero, scene.IdentityAffine(),
scene.SolidBrush(gg.Blue), scene.NewCircleShape(250, 200, 100))
s.PopLayer()
// Render to pixmap
renderer := scene.NewRenderer(width, height)
renderer.Render(s)
Benefits:
- GPU-optimized command batching
- Efficient dirty region tracking
- Parallel tile rendering
Backend Architecture
gg supports three rendering backends:
| Backend | Package | Description | Use Case |
|---|---|---|---|
| Native | backend/native/ |
Pure Go via gogpu/wgpu | Default, zero deps |
| Rust | backend/rust/ |
wgpu-native FFI | Max performance |
| Software | backend/software/ |
CPU rasterizer | Fallback |
import "github.com/gogpu/gg/backend"
// Auto-select best available
b := backend.Default()
// Explicit selection
b := backend.Get(backend.BackendNative)
b := backend.Get(backend.BackendRust) // Requires -tags rust
b := backend.Get(backend.BackendSoftware)
GPU Backend Features (v0.20.0)
- Command Encoder β State machine for GPU command recording
-
Texture Management β Lazy views with
sync.Once - Buffer Mapping β Async with device polling
- Pipeline Cache β FNV-1a descriptor hashing
- Compute Shaders β WGSL shaders for path rasterization
Performance
Benchmarks
| Operation | Time | Notes |
|---|---|---|
| sRGB β Linear | 0.16ns | 260x faster than math.Pow |
| LayerCache.Get | 90ns | Thread-safe LRU |
| DirtyRegion.Mark | 10.9ns | Lock-free atomic |
| MSDF lookup | <10ns | Zero-allocation |
| Path iteration | 438ns | iter.Seq, 0 allocs |
Optimizations
- SIMD β Vectorized color operations
- Parallel rendering β Tile-based multi-threaded rasterization
- LRU caching β Glyph cache, texture cache, layer cache
- GPU compute β Path flattening, tile binning, coverage calculation
Anti-Aliased Rendering
v0.19.0 introduced professional-grade anti-aliasing using the tiny-skia algorithm:
// AA is enabled by default
dc.Fill()
// Disable AA for performance
dc.FillNoAA()
Implementation:
- 4x supersampling with coverage accumulation
-
AlphaRunsβ RLE-encoded sparse alpha buffer - SIMD batch blending for 16 pixels at a time
- Same algorithm as Chrome, Android, Flutter
The GoGPU Ecosystem
gg is part of a complete Pure Go graphics stack:
| Project | Version | LOC | Description |
|---|---|---|---|
| gogpu/gg | v0.20.0 | ~122K | 2D graphics (this library) |
| gogpu/wgpu | v0.10.1 | ~95K | Pure Go WebGPU |
| gogpu/naga | v0.8.4 | ~33K | WGSL shader compiler |
| gogpu/gogpu | v0.11.1 | ~28K | Graphics framework |
Total: ~280K lines of Pure Go.
Design Principles
- Pure Go β No CGO, easy cross-compilation, single binary
- GPU-First β Designed for GPU acceleration from day one
- Production-Ready β Enterprise-grade error handling, logging
- API Stability β Semantic versioning, deprecation policy
Inspired By
- vello (Rust) β GPU compute shaders, sparse strips
- tiny-skia (Rust) β Anti-aliasing, stroke expansion
- kurbo (Rust) β Path algorithms
- peniko (Rust) β Brush/paint system
- skrifa/swash (Rust) β Font parsing, color emoji
Installation
go get github.com/gogpu/gg@v0.20.0
Requirements: Go 1.25+
Build Tags
# Default: Native + Software backends
go build ./...
# With Rust backend (requires wgpu-native)
go build -tags rust ./...
# Software only
go build -tags nogpu ./...
Examples
Complete Examples
-
examples/basic/β Basic shapes and colors -
examples/text/β Text rendering -
examples/color_emoji/β Color emoji extraction -
examples/gpu/β GPU backend usage -
examples/scene/β Scene graph
Run Examples
cd examples/basic
go run main.go
Documentation
- README β Quick start
- ARCHITECTURE.md β System design
- ROADMAP.md β Development milestones
- pkg.go.dev β API reference
Links
- Repository: https://github.com/gogpu/gg
- Release v0.20.0: https://github.com/gogpu/gg/releases/tag/v0.20.0
- GoGPU Organization: https://github.com/gogpu
- Discussions: https://github.com/orgs/gogpu/discussions
122K lines. Pure Go. Production-ready 2D graphics.
go get github.com/gogpu/gg@v0.20.0
Star the repo if you find it useful!
Part of the GoGPU Journey series
Top comments (0)