Documentation
¶
Overview ¶
Package record captures frames from a running visualizer into demo GIFs, MP4 clips and PNG screenshots, the way the family's --record flags and screenshot keys do.
A Recorder (from NewRecorder) accumulates downscaled, dithered frames via Recorder.Add and writes a looping GIF with Recorder.Save. WithVideo — applied automatically by New for an .mp4 path — switches it to an H.264 MP4 instead, which stays small where a long GIF would not. For stills, FromRGBA wraps a software renderer's raw framebuffer as an image and SavePNG writes it out.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrNoFFmpeg = errors.New("record: ffmpeg not found on PATH (needed for MP4 output)")
ErrNoFFmpeg reports that MP4 encoding was requested but the ffmpeg binary is not on PATH. GIF and PNG output need no external tools; only video does.
Functions ¶
func EncodeMP4 ¶ added in v0.14.0
EncodeMP4 pipes raw w×h RGBA frames to ffmpeg and writes an H.264 MP4 at path, played back at fps frames per second. Video stays small where a long GIF would not, which is why the family's longer demo clips use it. It returns ErrNoFFmpeg when ffmpeg is unavailable, so a caller can fall back to a GIF or report the missing dependency plainly.
func FromRGBA ¶
FromRGBA wraps a raw RGBA framebuffer (the software renderers' native output) as an image without copying.
func IsVideoPath ¶ added in v0.14.0
IsVideoPath reports whether path names a video file, i.e. one this package encodes with ffmpeg rather than as a GIF. Front-ends use it to decide the output format from a --record path alone.
func SavePNG ¶
SavePNG writes img as a PNG at path — the family's screenshot key.
Example ¶
ExampleSavePNG writes a software renderer's raw framebuffer as a screenshot.
package main
import (
"fmt"
"os"
"path/filepath"
"github.com/danielriddell21/crucible/record"
)
func main() {
dir, _ := os.MkdirTemp("", "crucible-png-example")
defer os.RemoveAll(dir)
const w, h = 320, 200
fb := make([]byte, w*h*4) // the renderer's RGBA framebuffer
err := record.SavePNG(filepath.Join(dir, "shot.png"), record.FromRGBA(fb, w, h))
fmt.Println(err)
}
Output: <nil>
Types ¶
type Option ¶ added in v0.6.0
type Option func(*Recorder)
Option configures a Recorder at construction. See WithPalette, WithFrameDelay, and WithFinalHold.
func WithFinalHold ¶ added in v0.6.0
WithFinalHold holds the last frame for the given number of centiseconds before the GIF loops, so a demo lingers on its final state. Zero (the default) keeps every frame at the uniform delay.
func WithFrameDelay ¶ added in v0.6.0
WithFrameDelay overrides the per-frame delay (in centiseconds) that fps otherwise derives, for recordings paced one frame per event rather than by a steady frame rate. A non-positive value is ignored.
func WithFrameDiff ¶ added in v0.7.0
func WithFrameDiff() Option
WithFrameDiff stores each frame as only the rectangle that changed since the previous one, keeping the earlier pixels via GIF frame disposal. For a mostly-static scene — a dashboard, a map beside a panel — this shrinks the file dramatically. It quantises without dithering so unchanged regions stay byte-identical between frames; pair it with WithPalette when the scene's colours are known.
func WithPalette ¶ added in v0.6.0
WithPalette quantises frames to a caller-supplied palette instead of the default web-safe palette.Plan9. A palette tuned to the scene's own colours gives a cleaner GIF than the generic one. An empty palette is ignored.
func WithVideo ¶ added in v0.14.0
func WithVideo() Option
WithVideo makes the recorder keep raw RGBA frames and write an H.264 MP4 from Recorder.Save instead of a GIF. Video stays small where a long GIF would not, and skips palette quantisation entirely, so the palette and frame-diff options no longer apply. It needs ffmpeg on PATH; without it Save returns ErrNoFFmpeg. New applies this automatically when the recording path ends in .mp4.
type Options ¶ added in v0.8.0
type Options struct {
// Path is the output GIF path. An empty path means "do not record".
Path string
// FPS is the recording's playback rate in frames per second.
FPS int
// Scale downscales each captured frame by this integer factor.
Scale int
// Frames caps the recording; zero means unlimited.
Frames int
}
Options bundles the recording settings the family's front-ends expose as flags: where to write the GIF, the playback rate, the downscale factor, and how many frames to capture before exiting. It is the shared shape behind every app's --record flags; Options.AddFlags registers them on a pflag set, Options.AddStdFlags on a standard library one, and New turns the result into a Recorder.
func (*Options) AddFlags ¶ added in v0.8.0
AddFlags registers the standard --record, --record-fps, --record-scale and --record-frames flags on fs, bound to o. A front-end wires them with cmd.Flags() from its own cobra command, so crucible supplies the flags without owning the command tree. Pre-set a field before calling to change that flag's default (e.g. Options{Scale: 2}); a zero field uses the canonical default.
func (*Options) AddPacedFlags ¶ added in v0.9.0
AddPacedFlags registers the --record and --record-frames flags on fs, bound to o, for a recorder whose playback is paced by a fixed per-frame delay (WithFrameDelay) rather than a real-time frame rate. It omits --record-fps and --record-scale, which such a recorder ignores: the frame delay overrides the fps-derived timing, and these event-paced demos capture at full resolution. A zero Frames leaves the cap to the caller (its own default or the whole run); pre-set it to change the flag's default.
func (*Options) AddPacedStdFlags ¶ added in v1.0.0
AddPacedStdFlags registers the same flags as Options.AddPacedFlags on a standard library flag.FlagSet.
func (*Options) AddStdFlags ¶ added in v1.0.0
AddStdFlags registers the same flags as Options.AddFlags on a standard library flag.FlagSet, for a front-end that parses with flag rather than cobra and pflag. The names, defaults and usage strings are the same ones, so every app in the family answers to the same --record contract whichever flag package it is built on.
type Recorder ¶
type Recorder struct {
// contains filtered or unexported fields
}
Recorder accumulates downscaled frames for a demo GIF, or — in video mode, see WithVideo — raw frames for an MP4.
Example ¶
ExampleRecorder captures three frames at 20 fps, half scale, and writes a demo GIF — what a game's --record flag does with each rendered frame.
package main
import (
"fmt"
"image"
"image/color"
"os"
"path/filepath"
"github.com/danielriddell21/crucible/record"
)
func main() {
dir, _ := os.MkdirTemp("", "crucible-record-example")
defer os.RemoveAll(dir)
r := record.NewRecorder(20, 2, 0)
for i := range 3 {
frame := image.NewRGBA(image.Rect(0, 0, 64, 48))
frame.Set(i, i, color.RGBA{R: 255, A: 255})
r.Add(frame)
}
if err := r.Save(filepath.Join(dir, "demo.gif")); err != nil {
fmt.Println("save:", err)
return
}
fmt.Println(r.Len(), "frames")
}
Output: 3 frames
func New ¶ added in v0.8.0
New returns a recorder configured from o. Extra options (WithPalette, WithFrameDiff, …) still apply. When o.Path names an .mp4 the recorder is put in video mode (WithVideo), so a front-end's --record flag chooses GIF or MP4 by file extension alone.
func NewRecorder ¶
NewRecorder returns a recorder that captures at the given frames per second, downscaling each frame by scale. maxFrames caps the recording; zero means unlimited. Out-of-range arguments are clamped to sane values. Options tune the palette and timing.