Documentation
¶
Overview ¶
Package fresco is a generative terminal field engine: it renders a slow-drifting, palette-coloured pattern that appears to emanate from a focal row. It is a self-contained engine — the field math, the gradient LUT, and the variant vocabulary — that the caller drives through Render. The caller owns any scene composition (an overlay/message on top) and variant selection.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AppendRender ¶ added in v0.3.0
AppendRender appends the rendered frame to dst and returns the extended slice. It is the allocation-free core Render wraps: a caller driving an animation can reuse one buffer across frames — AppendRender(buf[:0], …) — instead of letting Render allocate a fresh string every time. Pass a nil dst to start fresh.
It is otherwise identical to Render: the same inputs yield the same bytes, and it writes exactly h rows of exactly w visible cells (appending nothing for a degenerate pane). Pure over its inputs — deterministic and snapshot-testable.
The returned slice aliases dst's backing array whenever it has room, so bytes read out of a previous frame are invalidated by the next AppendRender(buf[:0], …): fully consume (write or composite) one frame before rendering the next into the same buffer.
func Render ¶
Render builds the colored splash field background: exactly h rows of exactly w visible cells, or "" on a degenerate pane. Pure over its inputs (deterministic, snapshot-testable). It is a thin convenience wrapper over AppendRender — the two produce byte-identical output for identical inputs.
Example ¶
ExampleRender shows the core call and its contract: Render returns exactly h lines of exactly w visible cells. Pinning Options.Profile makes the output deterministic regardless of the ambient terminal — useful in tests and when writing to a non-TTY.
package main
import (
"fmt"
"strings"
"unicode/utf8"
"github.com/ZviBaratz/fresco"
)
// examplePalette is the tokyo-night-leaning gradient used across the examples:
// A0..A3 are the warm→cool anchors, Highlight is the star/rain-head near-white.
var examplePalette = fresco.Palette{
A0: "#f7768e",
A1: "#bb9af7",
A2: "#7aa2f7",
A3: "#7dcfff",
Highlight: "#c0caf5",
}
func main() {
frame := fresco.Render(12, 3, 0, fresco.Options{
Palette: examplePalette,
Variant: fresco.Ripple,
Profile: fresco.NoColor, // pin the colour depth so the output is stable
})
lines := strings.Split(frame, "\n")
fmt.Printf("%d lines\n", len(lines))
fmt.Printf("%d cells per line\n", utf8.RuneCountInString(lines[0]))
}
Output: 3 lines 12 cells per line
Types ¶
type ColorProfile ¶ added in v0.3.0
type ColorProfile int
ColorProfile selects the colour depth Render bakes its SGR bytes for.
The zero value, Auto, defers to the terminal's auto-detected profile — so an Options with no Profile set behaves exactly as the old unset (nil) *termenv.Profile did, and a caller that never pins depth needs to name neither this type nor termenv. Pinning any other value makes Render pure over its inputs: the same Options yield the same bytes regardless of ambient stdout state, which is what a standalone consumer (and a snapshot test) needs.
termenv's own Profile cannot serve this role directly: its zero value is TrueColor, so "unset" could not mean auto-detect. That asymmetry — not merely the wish to hide termenv — is why fresco owns the type (see resolve).
const ( // Auto auto-detects the terminal's colour profile (the pre-enum nil default). Auto ColorProfile = iota // TrueColor pins 24-bit colour. TrueColor // ANSI256 pins the 256-colour palette. ANSI256 // ANSI16 pins the 16-colour palette. ANSI16 // NoColor emits no colour at all; the glyphs still render as plain text. NoColor )
type Options ¶
type Options struct {
// Palette supplies the four warm→cool gradient anchors plus the star /
// rain-head highlight.
Palette Palette
// Variant selects the field generator.
Variant Variant
// FocalRow is the pane row the pattern emanates from — the origin of the
// focal-relative coordinates every field is evaluated in. A negative value
// centres it on the pane.
FocalRow int
// LumRange, when non-nil, overrides the variant's shipped luminance-range
// policy (the split between glyph density and colour luminance); nil keeps
// the variant's default. It stays a pointer because 0 is a meaningful value
// (density carries all the brightness), so no float64 sentinel could stand
// for "unset". It is how a caller applies a luminance-range override without
// this package reading the environment.
LumRange *float64
// Profile pins the colour depth Render emits at, independent of the
// process-global colour profile. The zero value, Auto, defers to the
// auto-detected terminal profile — what a caller wants when rendering to a
// real pane, and the behaviour of an unset field. Pinning any other value
// (TrueColor / ANSI256 / ANSI16 / NoColor) makes Render pure over its
// inputs: the same Options yield the same bytes regardless of ambient stdout
// state, which is what a standalone consumer (and a snapshot test) needs.
// It is a fresco-owned ColorProfile so a caller need not import termenv.
Profile ColorProfile
}
Options configures Render.
type Palette ¶
Palette is the splash field's colour input: four warm→cool gradient anchors plus a highlight, each a hex string ("#rgb" or "#rrggbb"). A0..A3 are the nebula gradient (e.g. pink, purple, blue, cyan); consecutive anchors are meant to be hue-adjacent so HCL blending between them stays smooth. A3 doubles as rain's stream hue. Highlight is the star / rain-head white — the brightest colour the field can reach (the foreground / near-white).
Render never rejects a Palette: an anchor that is not parseable hex degrades gracefully to a documented fallback (see splashGradientColors, splashShadeParse, rainRampHexAt), so the exactly-h×w-cells contract holds for any Palette. Call Validate to check a palette up front instead of discovering a typo on screen.
func (Palette) Validate ¶ added in v0.3.0
Validate reports whether every anchor is a canonical hex colour ("#rgb" or "#rrggbb"). It is advisory and opt-in: Render never returns an error and never panics on a malformed Palette — each unparseable anchor degrades to a documented fallback, so the h×w-cells contract always holds. Validate exists so a caller loading a theme can surface a bad colour deliberately rather than see it painted as a fallback.
It is intentionally stricter than Render's parser (go-colorful's Hex, which also accepts a missing digit or trailing garbage — "#12345g" parses there): Validate flags anything a human would call a typo (a missing '#', a non-hex digit, a wrong length, trailing characters) even when Render would still paint something for it. So Validate may reject a string Render nonetheless colours; that gap is the point.
The returned error names every offending field and its value (joined, so one call reports all of them); it is nil when all five anchors are canonical.
type Variant ¶
type Variant int
Variant selects the field generator + glyph technique. The caller pins one (or keeps a random per-launch rotation) and passes it in through Options; a caller-side override affordance can trump that.
const ( // Rain ("f") is Matrix-style digital rain: per-column streams with bright // heads and fading tails, layered at four depths. The roster's motion entry // — and the only variant that shades by luminance alone, with no hue of its // own to spend (see buildRainRamp). // // It is also the fallback: a variant with no case in splashFieldAt or ops // renders as rain, and a caller resolves an unrecognized override name to // it too. Rain Variant = iota // Tunnel ("g") is a textured wall flying past a vanishing point that sits on // the focal point: screen position maps to (depth, angle), so a plain noise // lookup becomes an infinite corridor. The roster's depth entry — z-fog // carries distance in luminance, and hue bands by depth into coloured rings // receding down the wall. Tunnel // Ripple ("h") is drops falling on a dark pool: each one flashes where it // lands and expands into a ring that shifts hue as it ages, and the rings // interfere where they cross. The roster's event entry — the only field with // a birth and a death in it rather than a steady state. Ripple // Galaxy ("i") is an inclined spiral turning around the focal point: a soft // bright bulge, arms mottled with turbulence and star-knots, a dust lane // silhouetting the disk's near edge, warm at the core and cool at the rim. The // tunnel's single-object sibling — brightness is the whole subject, and the // arms are a rigidly rotating density wave rather than winding matter (see // splashGalaxyAtFor). Galaxy // Aurora ("j") is a sky of polar light: tall curtains that drift sideways as a // body while each one's spine snakes, hung over dark sky with the hue sliding // warm↔cool by altitude. The roster's weather entry, and rain's absolute-field // sibling — a bigger pane shows more sky rather than the same object scaled up, // and its hue is a property of altitude rather than of any object's radius (see // splashAuroraAt). Aurora )
func ParseVariant ¶
ParseVariant resolves a pinnable pattern name to its variant. It knows only the user-facing names, not the dev letters (f/g/h) — those are a caller-side affordance layered on top. The bool is false for an unknown name.
Example ¶
ExampleParseVariant resolves a pinnable variant name; the bool reports whether the name was recognized.
package main
import (
"fmt"
"github.com/ZviBaratz/fresco"
)
func main() {
v, ok := fresco.ParseVariant("ripple")
fmt.Println(v, ok)
_, ok = fresco.ParseVariant("nope")
fmt.Println(ok)
}
Output: ripple true false
func Variants ¶
func Variants() []Variant
Variants lists the shipped variants — the pool a caller's random rotation draws from. The order is the rotation order; the returned slice is a fresh copy, so callers cannot mutate the pool.
Example ¶
ExampleVariants lists the shipped variants in their rotation order.
package main
import (
"fmt"
"github.com/ZviBaratz/fresco"
)
func main() {
for _, v := range fresco.Variants() {
fmt.Println(v)
}
}
Output: rain tunnel ripple galaxy aurora
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
fresco
command
Command fresco is a terminal screensaver for the fresco field engine: it fills the pane with a slow-drifting, palette-coloured generative field and animates it full-screen until you quit.
|
Command fresco is a terminal screensaver for the fresco field engine: it fills the pane with a slow-drifting, palette-coloured generative field and animates it full-screen until you quit. |