Documentation
¶
Overview ¶
Package kinescope draws the picture of an old tube TV for Go games: scanlines, a phosphor mask, glow, a bulging glass — and the moods of a worn set: drifting reception, torn lines, a shiver when the channel changes.
A Setup is a whole TV as data; NewTV builds a TV from it, and the game tells the TV its facts: time with TV.Update, signal levels, episodes. The ebitengine package draws a frame through the TV.
tv, err := kinescope.NewTV(kinescope.Gorizont()) renderer, err := ebitengine.NewRenderer() // Every tick tv.Update(1.0 / 60) // In DrawFinalScreen _ = renderer.Draw(screen, offscreen, tv, geoM)
The lab ¶
The lab, https://shpaker.github.io/kinescope/, shows a setup on a picture and writes it out as Go. A link opens it on a setup written as JSON, by hand or by an agent:
https://shpaker.github.io/kinescope/#j={"preset":"Rubin"}
The format and everything a setup can be made of, effects and their params with ranges, are in https://shpaker.github.io/kinescope/llms.txt.
Index ¶
- func Blend(t float32, a, b map[ParamKey]float32) map[ParamKey]float32
- type Afterglow
- type ApertureMask
- type Convergence
- type Corners
- type Curvature
- type Degauss
- type Drift
- type Drive
- type Effect
- type Envelope
- type Episode
- type Every
- type Flicker
- type Glass
- type Glow
- type Grain
- type Hum
- type Interlace
- type Level
- type Param
- type ParamKey
- type Power
- type Roll
- type Scanlines
- type Setup
- type Signal
- type SlotMask
- type Snow
- type Softness
- type Source
- type Stage
- type TV
- func (tv *TV) Apply(values map[ParamKey]float32)
- func (tv *TV) Dark() bool
- func (tv *TV) Effects() []Effect
- func (tv *TV) Epoch() int
- func (tv *TV) Frame() int
- func (tv *TV) Hold(held bool)
- func (tv *TV) Map(x, y float64, w, h int) (float64, float64)
- func (tv *TV) Params() []Param
- func (tv *TV) Play(e Episode)
- func (tv *TV) PowerOff()
- func (tv *TV) PowerOn()
- func (tv *TV) Reset()
- func (tv *TV) Revision() int
- func (tv *TV) SetEffects(effects ...Effect) error
- func (tv *TV) Signal(name string) (*Level, error)
- func (tv *TV) SourceValue(name string) float32
- func (tv *TV) Time() float64
- func (tv *TV) Update(dt float64)
- func (tv *TV) Value(key ParamKey) float32
- func (tv *TV) Values() map[ParamKey]float32
- type Target
- type Tear
- type Vignette
- type Wave
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Afterglow ¶
type Afterglow struct {
Decay float32 // the share of the glow kept from one frame to the next
}
Afterglow keeps the phosphor glowing after the beam has passed: bright moving things leave a short trail, the blue one longest.
type ApertureMask ¶
type ApertureMask struct {
Strength float32 // how much the stripes show
// MinScale is the screen pixels per frame pixel the mask needs: below
// it the mask fades out.
MinScale float32
}
ApertureMask is the phosphor's red, green and blue stripes, one triad per three screen pixels.
func NewApertureMask ¶
func NewApertureMask() *ApertureMask
NewApertureMask is a faint mask on a big enough screen.
func (*ApertureMask) Name ¶
func (*ApertureMask) Name() string
func (*ApertureMask) Params ¶
func (e *ApertureMask) Params() []Param
func (*ApertureMask) Stage ¶
func (*ApertureMask) Stage() Stage
type Convergence ¶
type Convergence struct {
Amount float32 // the parting at the edges, outwards, in frame pixels
// Offset is the sideways drift, red to the right and blue to the left:
// half of it in the middle, all of it at the edges, in frame pixels.
Offset float32
}
Convergence puts the red and blue guns out of register: their beams part towards the edges of the screen, and on a worn set drift apart sideways all over it.
func NewConvergence ¶
func NewConvergence() *Convergence
NewConvergence is a set a little out of register.
func (*Convergence) Name ¶
func (*Convergence) Name() string
func (*Convergence) Params ¶
func (e *Convergence) Params() []Param
func (*Convergence) Stage ¶
func (*Convergence) Stage() Stage
type Corners ¶
type Corners struct {
Radius float32 // in frame pixels
}
Corners round the picture's corners to the tube's outline.
type Curvature ¶
type Curvature struct {
X float32 // bulge across, the stronger the nearer the top and bottom
Y float32 // bulge down, the stronger the nearer the sides
}
Curvature bulges the glass: the picture bows out towards the tube's corners.
type Degauss ¶ added in v0.2.0
type Degauss struct {
Strength float32
}
Degauss is the degaussing coil shaking the mask: the picture wobbles and settles. Its strength rests at zero and is driven by the Degauss episode.
type Drift ¶
type Drift struct {
Period float32 // seconds between one random level and the next
}
Drift wanders smoothly and at random between 0 and 1, like the reception of a far station: now clearer, now worse.
type Drive ¶
type Drive struct {
From string // a source's name in Setup.Sources
To ParamKey // the param it moves
Weight float32 // how far the param moves at the source's full value
}
Drive lets a source move a param: Weight times the source's value is added to the param's base. A drive to a param of an effect the TV does not have does nothing.
type Effect ¶
type Effect interface {
// Name is the effect's name, the first part of its params' keys.
Name() string
// Stage is where in the picture the effect works.
Stage() Stage
// Params lists the effect's tunable numbers.
Params() []Param
// contains filtered or unexported methods
}
Effect is one part of the look of a set: plain data, its parameters' base values. A TV owns its effects; what changes them over time — signals, drifts, glitches — is set up beside them, in Setup.
The set of effects is closed: every effect is defined in this package, and every backend knows how to draw each of them.
type Envelope ¶
Envelope is the shape of an episode in time, in seconds: the rise to its peak, the stay there and the fall back.
type Episode ¶
Episode is a fault of the set played over a moment: its targets move by their weights, shaped by the envelope. Play one with TV.Play or let a schedule (Every) play it.
func Degaussing ¶ added in v0.2.0
func Degaussing() Episode
Degaussing is the coil shaking the mask: the picture wobbles and settles.
func Jitter ¶
func Jitter() Episode
Jitter tears the lines for a moment, as when the horizontal sync slips.
func Ripple ¶
func Ripple() Episode
Ripple is the signal shivering as a channel is switched: the lines tear a little, the grain thickens and snow flickers, all dying out.
type Every ¶
Every plays one of its episodes now and then. At rate 1 the waits between them are random, from Mean-Spread to Mean+Spread seconds; the schedule's rate (Rate(name)) speeds them up or slows them down, and a drive can move it like any other param.
type Flicker ¶
type Flicker struct {
Strength float32 // the share of brightness the picture trembles by
Frequency float32 // trembles per second
}
Flicker trembles the whole picture's brightness.
type Glass ¶
type Glass struct {
Level float32 // the glass's own light on black
}
Glass is the tube's glass catching the room's light: black is never quite black, and a soft reflection sits in the upper left corner.
type Glow ¶
type Glow struct {
Threshold float32 // the brightness the glow starts at
Strength float32 // how much of the glow is added
Radius float32 // how far it spreads, in frame pixels
}
Glow bleeds the light of bright areas around them.
type Grain ¶
type Grain struct {
Strength float32
}
Grain is the signal's snow: fine noise, new every frame, seen on black too.
type Hum ¶
type Hum struct {
Strength float32 // how much brighter the bar is; below zero, darker
Period float32 // seconds the bar takes to cross the picture
Width float32 // the bar's width, in the picture's heights
}
Hum is the mains hum: a bar rolling slowly down the picture, light or dark.
type Interlace ¶ added in v0.2.0
type Interlace struct {
Strength float32
// MinScale is the screen pixels per frame pixel the fields need: below
// it they fade out.
MinScale float32
}
Interlace draws the lines in two fields taking turns, frame by frame: the lines of the field not drawn fade, and the picture shimmers.
type Level ¶
type Level struct {
// contains filtered or unexported fields
}
Level is the live level of a signal. The game sets it whenever it likes — in Update or in Draw — and the TV's values follow at once.
type Param ¶
Param is one tunable number: its key, its range and where its base value lives. Value points into the effect (or the TV, for a schedule's rate), so writing through it changes the base the modulation is added to.
type ParamKey ¶
type ParamKey string
ParamKey names a tunable number of a TV: a parameter of one of its effects ("tear.strength") or the rate of one of its schedules ("rate.glitches"). Values, Apply, drives and episode targets all speak these keys.
const ( PowerWidth ParamKey = "power.width" PowerHeight ParamKey = "power.height" PowerFlash ParamKey = "power.flash" CurvatureX ParamKey = "curvature.x" CurvatureY ParamKey = "curvature.y" DegaussStrength ParamKey = "degauss.strength" RollStrength ParamKey = "roll.strength" TearStrength ParamKey = "tear.strength" TearAmplitude ParamKey = "tear.amplitude" TearBands ParamKey = "tear.bands" )
Keys of the geometry effects' params.
const ( AfterglowDecay ParamKey = "afterglow.decay" ConvergenceAmount ParamKey = "convergence.amount" ConvergenceOffset ParamKey = "convergence.offset" GlowThreshold ParamKey = "glow.threshold" GlowStrength ParamKey = "glow.strength" GlowRadius ParamKey = "glow.radius" GlassLevel ParamKey = "glass.level" ScanlinesDepth ParamKey = "scanlines.depth" ScanlinesMinScale ParamKey = "scanlines.min_scale" ApertureMaskStrength ParamKey = "aperture_mask.strength" ApertureMaskMinScale ParamKey = "aperture_mask.min_scale" SoftnessAmount ParamKey = "softness.amount" InterlaceStrength ParamKey = "interlace.strength" InterlaceMinScale ParamKey = "interlace.min_scale" SlotMaskStrength ParamKey = "slot_mask.strength" SlotMaskMinScale ParamKey = "slot_mask.min_scale" )
Keys of the picture effects' params: the phosphor, the guns, the light and the beam.
const ( GrainStrength ParamKey = "grain.strength" FlickerStrength ParamKey = "flicker.strength" FlickerFrequency ParamKey = "flicker.frequency" HumStrength ParamKey = "hum.strength" HumPeriod ParamKey = "hum.period" HumWidth ParamKey = "hum.width" SnowStrength ParamKey = "snow.strength" VignetteStrength ParamKey = "vignette.strength" CornersRadius ParamKey = "corners.radius" )
Keys of the signal and tube effects' params.
type Power ¶ added in v0.2.0
type Power struct {
Width float32 // the raster's width, 1 whole
Height float32 // the raster's height, 1 whole
Flash float32 // the beam's flash added to the picture
}
Power squeezes the raster as the tube warms up or dies — a dot, a line, the picture — and flashes the beam. The TV drives it on PowerOn and PowerOff; at rest it is the whole picture.
type Roll ¶ added in v0.2.0
type Roll struct {
Strength float32
}
Roll slips the picture down as the vertical sync is lost: Strength is the share of the height it has slipped, the blanking bar crossing with it. It rests at zero and is driven by the Roll episode.
type Scanlines ¶
type Scanlines struct {
Depth float32 // how dark the gaps get
// MinScale is the screen pixels per frame pixel the lines need: below
// it they fade out, as too few pixels turn them into moiré.
MinScale float32
}
Scanlines are the beam's lines, one per frame row: dark gaps between them, narrower where the beam is bright and wide.
func NewScanlines ¶
func NewScanlines() *Scanlines
NewScanlines are clear lines on a big enough screen.
type Setup ¶
type Setup struct {
// Seed makes the TV's randomness its own: two TVs with one seed, fed
// the same Update steps, show the same.
Seed uint64
// Effects are the look of the set, at most one of each kind.
Effects []Effect
// Sources are named values in time: signals the game sets, drifts and
// waves.
Sources map[string]Source
// Drives connect sources to params.
Drives []Drive
// Schedules play episodes now and then, by name; Rate(name) is the key
// of each one's rate.
Schedules map[string]Every
}
Setup is a whole TV as data: what it looks like and how it misbehaves. A preset is a function returning a Setup; NewTV builds a TV from one.
func Gorizont ¶
func Gorizont() Setup
Gorizont is a Minsk color set of the eighties, well kept: a slightly bulging tube with clear scanlines, a faint mask, glowing highlights and a short afterglow. It has no moods of its own; add sources, drives and schedules to the returned setup to give it some.
type Signal ¶
type Signal struct{}
Signal is a level the game sets, frame by frame: a fact of the game, such as the set being shaken. Get its Level with TV.Signal.
type SlotMask ¶ added in v0.2.0
type SlotMask struct {
Strength float32
// MinScale is the screen pixels per frame pixel the mask needs: below
// it the mask fades out.
MinScale float32
}
SlotMask is the phosphor of a shadow-mask set: red, green and blue stripes cut by slots, each column of triads half a slot below the last.
func NewSlotMask ¶ added in v0.2.0
func NewSlotMask() *SlotMask
NewSlotMask is a mask that shows on a big enough screen.
type Snow ¶ added in v0.2.0
type Snow struct {
Strength float32
}
Snow is the screen drowning in snow, as when the signal is lost. Its strength rests at zero and is driven by the Snow episode.
type Softness ¶ added in v0.2.0
type Softness struct {
Amount float32
}
Softness spreads the beam between neighboring pixels of a line: 0 keeps them square, 1 blends them smoothly. It shows on a screen scaled by a fraction, where square pixels come out uneven.
func NewSoftness ¶ added in v0.2.0
func NewSoftness() *Softness
NewSoftness is a beam a little soft.
type Source ¶
type Source interface {
// contains filtered or unexported methods
}
Source is a value that changes in time, from 0 to 1, and drives params through Drives. Sources are named in Setup.Sources.
type Stage ¶
type Stage int
Stage is where in the picture an effect works. Stages run in this order, which is the order the light of a real set goes through; within a stage, effects run in the order they are listed.
const ( // StagePrepass effects work on whole frames before the picture is // drawn: the afterglow of the phosphor. StagePrepass Stage = iota // StageGeometry effects move the point of the frame a screen point shows. StageGeometry // StageRead effects change how one point of the frame is read: the // beam's softness between neighboring pixels. A TV has at most one. StageRead // StageSample effects change how the picture is gathered at that point // from the frame: the guns out of register. A TV has at most one. StageSample // StageLight effects add light before the beam draws it: glow, glass. StageLight // StageBeam effects shape the beam: scanlines. StageBeam // StageMask effects are the phosphor mask on the screen's own pixels. StageMask // StagePost effects are the signal's noise and the tube's falloff. StagePost // StageFrame effects cut the picture to the tube's outline. StageFrame )
type TV ¶
type TV struct {
// contains filtered or unexported fields
}
TV is a set at work: its effects, its clock and its moods. The game talks to it in facts — a signal's level, an episode to play — and the TV works out what each effect shows. A backend draws it.
A TV is not safe for concurrent use.
func NewTV ¶
NewTV builds a TV from a setup. The TV takes copies of the setup's effects, so the setup can be reused. It fails on a setup that does not hold together: a drive from a source that is not there, a schedule with no episodes and the like.
func (*TV) Apply ¶
Apply sets the base values of the params it names, kept in range. Keys the TV does not have are left alone.
func (*TV) Dark ¶ added in v0.2.0
Dark reports the tube gone dark after PowerOff — the moment a game that lets its picture fold away can quit.
func (*TV) Effects ¶
Effects are the TV's effects in stage order. They belong to the TV: change them through Params or Apply.
func (*TV) Epoch ¶
Epoch changes on every Reset: a backend clears what it keeps between frames when it sees a new one.
func (*TV) Hold ¶
Hold keeps the schedules' episodes waiting while held is true — say, while the player drags something.
func (*TV) Map ¶
Map is the point of a w×h frame that the TV shows at the point x, y — where it would be without the bend of the glass and the tear of the lines. Use it for a pointer or a touch: map where the player pressed, hit what they see there. The result can fall outside the frame.
func (*TV) Params ¶
Params are all the TV's tunable numbers, the effects' first, then the schedules' rates. Writing through a param's Value sets its base.
func (*TV) PowerOff ¶ added in v0.2.0
func (tv *TV) PowerOff()
PowerOff switches the set off: the picture folds to a line and a dot and fades; Dark reports it gone. Calling it again while dying changes nothing.
func (*TV) PowerOn ¶ added in v0.2.0
func (tv *TV) PowerOn()
PowerOn switches the set on: the picture grows from a dot over half a second. The Power effect shows it.
func (*TV) Reset ¶
func (tv *TV) Reset()
Reset starts the set afresh: no episode playing and, for the backend, no afterglow left on the phosphor. Call it when the effects come back on.
func (*TV) Revision ¶
Revision changes whenever the set of effects does: a backend rebuilds its shaders when it sees a new one.
func (*TV) SetEffects ¶
SetEffects replaces the TV's effects, keeping its sources, drives and schedules. A backend redraws the TV's shaders on the next frame, which may take a moment: change the set in a menu, not in play.
func (*TV) Signal ¶
Signal is the level of the named signal, for the game to set. It fails if the setup has no signal by that name: better at start than a dead knob in play.
func (*TV) SourceValue ¶ added in v0.4.0
SourceValue is the named source's value now, from 0 to 1: the reception a drift has wandered to, say, for the game to show. It is 0 for a source the setup does not have.
func (*TV) Update ¶
Update moves the TV on by dt seconds: sources, episodes and schedules. Call it once per game tick; the TV has no clock of its own.
type Tear ¶
type Tear struct {
Strength float32 // 0 calm, 1 fully torn
Amplitude float32 // the wave's shift of a line at full strength, in frame pixels
// Bands is the shift of the bands torn at random, in frame pixels. They
// last a moment, so Map leaves them out.
Bands float32
}
Tear shifts the lines sideways, as when the set is knocked or the horizontal sync slips: in a running wave, and in bands of lines torn at random. Its strength usually rests at zero and is driven: by a signal such as a shake, or by a glitch.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
kinescope-lab
command
Command kinescope-lab is a lab for kinescope, built for the browser: make a setup — effects, sources, drives, schedules — watch a test card, a moving scene or a dropped picture through it, tell the TV the game's facts, and take the setup away as Go.
|
Command kinescope-lab is a lab for kinescope, built for the browser: make a setup — effects, sources, drives, schedules — watch a test card, a moving scene or a dropped picture through it, tell the TV the game's facts, and take the setup away as Go. |
|
kinescope-lab/internal/lab
Package lab is the kinescope lab's model: a setup being made, kept as the lists the page shows, the TV built from it, its Go code and its state for the page's address.
|
Package lab is the kinescope lab's model: a setup being made, kept as the lists the page shows, the TV built from it, its Go code and its state for the page's address. |
|
Package ebitengine draws kinescope TVs with Ebitengine: each TV's effects are composed into one picture shader, with a prepass or two at the frame's size for the effects that need whole frames (glow, afterglow).
|
Package ebitengine draws kinescope TVs with Ebitengine: each TV's effects are composed into one picture shader, with a prepass or two at the frame's size for the effects that need whole frames (glow, afterglow). |