ir

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Sep 4, 2026 License: MIT Imports: 3 Imported by: 0

Documentation

Overview

Package ir defines refract's intermediate representation: a small, backend-agnostic scene description, plus the Backend interface every renderer implements.

The IR is deliberately thin. It maps cleanly onto an immediate-mode canvas (github.com/gogpu/gg), onto a retained scene graph, and onto the built-in SVG emitter, without any of them leaking into the model layer. Geoms, scales and layout produce IR; they never talk to a backend directly.

Stability

The primitive set and the Backend interface are frozen for the v0.1 cycle. Pre-1.0 they may still change between minor releases; see docs/adr/0002.

Coordinates

Device coordinates, origin at the top-left, X right, Y down — the same convention as SVG, HTML canvas and gg. Positions are float32: they are device-space values after the model layer has already done its float64 work, and float32 is what a GPU backend ultimately wants.

Index

Constants

This section is empty.

Variables

View Source
var Identity = Affine{A: 1, D: 1}

Identity is the transform that changes nothing.

View Source
var Transparent = Color{}

Transparent is the fully transparent colour. A fill or stroke with A == 0 is skipped by every backend.

Functions

This section is empty.

Types

type Affine

type Affine struct {
	A, B, C, D, E, F float32
}

Affine is a 2D affine transform in row-major order:

| A C E |
| B D F |
| 0 0 1 |

which is the same element order SVG's matrix(a,b,c,d,e,f) uses.

func Rotate

func Rotate(angle float64) Affine

Rotate returns a rotation transform by angle radians, clockwise in screen coordinates (Y down).

func Scale

func Scale(sx, sy float32) Affine

Scale returns a scaling transform.

func Translate

func Translate(dx, dy float32) Affine

Translate returns a translation transform.

func (Affine) Apply

func (a Affine) Apply(p Point) Point

Apply transforms p by a.

func (Affine) IsIdentity

func (a Affine) IsIdentity() bool

IsIdentity reports whether a is the identity transform.

func (Affine) Mul

func (a Affine) Mul(b Affine) Affine

Mul returns a*b: the transform that applies b first, then a.

type Backend

type Backend interface {
	// Polyline strokes an open sequence of points. It is the fast path for
	// line geoms; it is exactly equivalent to StrokePath of a path built with
	// Path.Polyline, but lets a backend skip path construction entirely.
	Polyline(pts []Point, style Stroke)

	// StrokePath strokes an arbitrary path.
	StrokePath(p *Path, style Stroke)

	// FillPath fills a path's interior according to rule.
	FillPath(p *Path, fill Fill, rule FillRule)

	// Text draws a single-line run. The backend shapes it.
	Text(run TextRun)

	// Markers draws one shape at each of the given positions. This is the
	// scatter fast path: a backend may instance it.
	Markers(shape Marker, at []Point, style MarkerStyle)

	// Image blits a raster into dst, scaling to fit. This carries the
	// density-raster big-data path.
	Image(img image.Image, dst Rect)

	// Push pushes a transform and an optional clip path onto the state stack.
	// The transform composes with whatever is already on the stack; a nil clip
	// means "no additional clipping".
	Push(clip *Path, xform Affine)

	// Pop undoes the most recent Push.
	Pop()

	// Measure reports metrics for a run, from the same font stack that Text
	// will draw with. It must be callable before any drawing, because layout
	// runs first.
	Measure(run TextRun) TextMetrics

	// Flush completes the frame and reports any deferred error. A backend that
	// writes a file writes it here.
	Flush() error
}

Backend is what every renderer implements. It is an immediate-mode drawing sink: refract lowers a chart into calls on a Backend, in paint order.

Stability

This interface is frozen for the v0.1 cycle (docs/adr/0002). It exists so that refract is insulated from any single rendering library: a change in a backend's own API is contained to that backend's adapter.

State

A Backend carries no style state between calls — every drawing call is self-contained. The only state is the transform/clip stack managed by Push and Pop.

Concurrency

A Backend is not safe for concurrent use. refract may build IR on several goroutines but always plays it back into a backend from one.

type Color

type Color = color.NRGBA

Color is refract's colour type: 8-bit non-premultiplied sRGBA.

It is an alias for color.NRGBA rather than a new type so that colours pass straight into any stdlib or backend API taking a color.Color, with no conversion layer and no import of refract in code that only wants to name a colour.

func Fade

func Fade(c Color, f float64) Color

Fade returns c with its alpha scaled by f, clamped to [0, 1].

func RGB

func RGB(r, g, b uint8) Color

RGB returns an opaque colour.

func RGBA

func RGBA(r, g, b, a uint8) Color

RGBA returns a colour with explicit alpha.

type Fill

type Fill struct {
	Color Color
	Start Point
	End   Point
	Stops []GradientStop
}

Fill describes how a path's interior is painted.

A Fill with no Stops is a solid Color. With Stops, it is a linear gradient running from Start to End in the same coordinate space as the path; Color is then ignored. Radial and sweep gradients are not in the v0.1 IR — no v0.1 geom needs them, and adding them later is additive.

func Solid

func Solid(c Color) Fill

Solid returns an opaque-rules solid fill of colour c.

func (Fill) IsGradient

func (f Fill) IsGradient() bool

IsGradient reports whether f paints a gradient rather than a solid colour.

func (Fill) Visible

func (f Fill) Visible() bool

Visible reports whether filling with f would put any ink on the canvas.

type FillRule

type FillRule uint8

FillRule selects how a path's interior is determined.

const (
	NonZero FillRule = iota
	EvenOdd
)

The fill rules.

type FontRef

type FontRef struct {
	Family string  // logical family; "" means the backend's default sans
	Size   float64 // em size in device units
	Weight int     // CSS-style numeric weight; 0 means 400
	Italic bool
}

FontRef names a font logically. refract never carries glyph data or font files through the IR: a backend resolves a FontRef with whatever font stack it has (gg's shaper, the SVG viewer, a host framework's text engine).

type GradientStop

type GradientStop struct {
	Offset float32
	Color  Color
}

GradientStop is one colour stop of a linear gradient, at offset t in [0, 1] along the gradient axis.

type HAlign

type HAlign uint8

HAlign is horizontal alignment of a text run relative to its anchor point.

const (
	AlignStart HAlign = iota
	AlignCenter
	AlignEnd
)

The horizontal alignments.

type LineCap

type LineCap uint8

LineCap is how a stroke terminates.

const (
	CapButt LineCap = iota
	CapRound
	CapSquare
)

The line caps.

type LineJoin

type LineJoin uint8

LineJoin is how two stroke segments meet.

const (
	JoinMiter LineJoin = iota
	JoinRound
	JoinBevel
)

The line joins.

type Marker

type Marker uint8

Marker is a scatter-point shape, drawn centred on its position.

const (
	MarkerCircle Marker = iota
	MarkerSquare
	MarkerDiamond
	MarkerTriangle
	MarkerCross
	MarkerPlus
)

The marker shapes.

type MarkerStyle

type MarkerStyle struct {
	Size   float32 // nominal diameter in device units
	Fill   Color
	Stroke Stroke
}

MarkerStyle is the paint applied to every instance of a Markers call.

type Path

type Path struct {
	Ops []PathOp
	Pts []Point
}

Path is a sequence of subpaths built from MoveTo/LineTo/CubicTo/Close.

Ops and Pts are parallel: walking Ops and consuming Op.Points() entries from Pts per op reconstructs the path. Splitting them this way keeps a path two allocations regardless of length and lets callers reuse both slices via Reset.

func (*Path) Bounds

func (p *Path) Bounds() Rect

Bounds returns the control-point bounding box of p. For paths containing cubics this is conservative: it bounds the control polygon, not the exact curve. That is what layout and clip-culling need, and it is cheap.

func (*Path) Close

func (p *Path) Close() *Path

Close closes the current subpath.

func (*Path) CubicTo

func (p *Path) CubicTo(c1x, c1y, c2x, c2y, x, y float32) *Path

CubicTo appends a cubic Bézier segment with the given control points.

func (*Path) Empty

func (p *Path) Empty() bool

Empty reports whether p contains no ops.

func (*Path) LineTo

func (p *Path) LineTo(x, y float32) *Path

LineTo appends a straight segment to (x, y).

func (*Path) MoveTo

func (p *Path) MoveTo(x, y float32) *Path

MoveTo starts a new subpath at (x, y).

func (*Path) Polyline

func (p *Path) Polyline(pts []Point) *Path

Polyline appends pts as one open subpath. It is a no-op for fewer than two points.

func (*Path) Rect

func (p *Path) Rect(r Rect) *Path

Rect appends a closed rectangular subpath.

func (*Path) Reset

func (p *Path) Reset()

Reset clears p while keeping its capacity, so a caller can reuse it across frames without reallocating.

func (*Path) Walk

func (p *Path) Walk(fn func(op PathOp, pts []Point))

Walk calls fn for each op with the points that op consumes. The slice passed to fn aliases p.Pts and must not be retained.

type PathOp

type PathOp uint8

PathOp is a single path-construction verb.

const (
	OpMoveTo  PathOp = iota // 1 point
	OpLineTo                // 1 point
	OpCubicTo               // 3 points: control 1, control 2, end
	OpClose                 // 0 points
)

The path verbs. The set is deliberately minimal: every curve a chart needs (rounded corners, tension-smoothed lines, arcs) is expressible as cubics, and both SVG and gg consume cubics natively.

func (PathOp) Points

func (op PathOp) Points() int

Points reports how many points in Path.Pts the op consumes.

type Point

type Point struct {
	X, Y float32
}

Point is a position in device space.

The concept document calls this f32.Point; refract keeps it here rather than spending a package on two fields (see docs/adr/0002).

type Rect

type Rect struct {
	Min, Max Point
}

Rect is an axis-aligned rectangle in device space. Min is the top-left corner, Max the bottom-right; a Rect with Max below Min on either axis is empty.

func R

func R(x0, y0, x1, y1 float32) Rect

R builds a Rect from its edges.

func (Rect) Contains

func (r Rect) Contains(p Point) bool

Contains reports whether p lies inside r, edges included.

func (Rect) Dx

func (r Rect) Dx() float32

Dx returns the width of r.

func (Rect) Dy

func (r Rect) Dy() float32

Dy returns the height of r.

func (Rect) Empty

func (r Rect) Empty() bool

Empty reports whether r encloses no area.

func (Rect) Inset

func (r Rect) Inset(left, top, right, bottom float32) Rect

Inset returns r shrunk by the given amounts on each side.

type Stroke

type Stroke struct {
	Color      Color
	Width      float32
	Cap        LineCap
	Join       LineJoin
	MiterLimit float32   // 0 means the backend default (4)
	Dash       []float32 // nil or empty means solid
	DashOffset float32
}

Stroke is the full state needed to stroke a polyline or path.

func (Stroke) Visible

func (s Stroke) Visible() bool

Visible reports whether stroking with s would put any ink on the canvas.

type Target

type Target interface {
	// Open returns a Backend drawing into a surface of widthPx by heightPx
	// device pixels. dpr is the device pixel ratio: coordinates handed to the
	// backend are already in device pixels, so dpr is informational — backends
	// use it to pick hinting and stroke-snapping strategies.
	Open(widthPx, heightPx int, dpr float64) (Backend, error)

	// Close finalises the destination. It is called after the Backend's Flush.
	Close() error
}

Target is a render destination: it opens a Backend sized for one chart, and finalises whatever it is writing to when Close is called.

Splitting Target from Backend is what lets refract.Render take a destination before the chart's pixel size is known to that destination, and lets the same backend implementation serve a file, an io.Writer, or a window surface.

type TextMetrics

type TextMetrics struct {
	// Advance is the total advance width of the run.
	Advance float32
	// Ascent and Descent are the font's ascent above and descent below the
	// baseline, both positive. They describe the font box, not this run's ink,
	// so successive runs in one font line up.
	Ascent  float32
	Descent float32
	// Ink is the run's tight bounding box relative to an origin at the
	// baseline start, Y up-negative as usual for screen coordinates.
	Ink Rect
}

TextMetrics is what layout needs back from a backend about a run.

Measure is the only text capability refract requires beyond drawing: layout must size margins, space ticks, and detect label collisions using metrics from the very shaper that will draw the text.

func (TextMetrics) Height

func (m TextMetrics) Height() float32

Height returns the font box height, Ascent + Descent.

type TextRun

type TextRun struct {
	Text     string
	Font     FontRef
	At       Point   // anchor position in device space
	H        HAlign  // horizontal alignment about At
	V        VAlign  // vertical alignment about At
	Rotation float64 // radians, clockwise, about At
	Color    Color
}

TextRun is a single-line string to be drawn.

refract passes strings, never pre-shaped glyphs: shaping belongs to the active backend. refract owns only placement — anchoring, rotation, and overlap avoidance. Paragraph layout is out of scope (see CONCEPT.md §5).

type VAlign

type VAlign uint8

VAlign is vertical alignment of a text run relative to its anchor point.

const (
	AlignBaseline VAlign = iota
	AlignTop
	AlignMiddle
	AlignBottom
)

The vertical alignments. AlignBaseline puts the anchor on the text baseline; the others align the anchor to the run's font box.

Jump to

Keyboard shortcuts

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