Make footage look like a CRT, a worn VHS tape, a thermal camera or a 1-bit screen.

Draws <PopArt> <Blobs> <HalftonePoster> <Fragments> <Reticle>

$npm install @kinetographdev/vj

What it does

VJ makes a picture look like it came from a screen, a tape or a sensor. Brightness stands in for heat and depth, so these are looks, not measurements. It also draws tracking marks on whatever moves, cuts a person into a pop-art poster and builds a camera fly-through of clips.

Screens and tapes

A CRT with curved glass that switches off, a worn VHS tape, a 1-bit screen, and a pixel magnifier that resolves into red, green and blue stripes.

A CRT tube switching off, on archive film.

Thermal and depth

Brightness becomes a thermal-camera palette or a depth-map look.

A thermal palette over a parade.

Flash looks

Acid heat, night vision, screen glow and grainy black and white, to cut on the beat.

Flash looks on a song, each held for a second and a half.

PopArt

Footage of a person cuts to an anime poster of them: blue tones, ink lines and rim light over a halftone. It needs a matte of the person, which a bundled tool makes once per clip.

Fred Ott cut to an anime poster and back.

Tracking

A tracker runs once and saves where things moved. Blobs draws boxes and links on every frame. Reticle marks one point.

Blob tracking over a 1-bit picture.

Fragments

Clips show only through windows: boxes round the people and animals in them, tiles of sky, round holes. Each clip sits on its own plane at its own depth, and a camera flies through so near pieces slide past faster than far ones. Boxes carry name tags with a flickering confidence figure. Whoever edits the video names the boxes; no detection model runs.

Demos

Studio panels

Ready-made scenes for the Hexed, Paper, VJ and caption panels in Studio. Edit a value and the preview redraws.

Compositions HexedLook PaperMatchCut PaperCutOut PaperScrapline PaperFoldOut TypeCaptions VjLook

VJ looks and tracking

Blob tracking over a 1-bit picture and over a thermal camera, a CRT switching off and a VHS tape, on archive film.

Compositions Blobs Thermal Crt Vhs PopArt

PopArt: Fred Ott cut to an anime poster and back.
Blobs: tracking over a 1-bit picture.
Thermal: a parade in thermal colour.
Crt: a tube switching off.

Reference

Exports, props and examples, for wiring it into a project.

Ships with

Studio panelSkill

What it exports

Components

Drawn as JSX inside a composition.

<PopArt />

The pop-art cut-in on any clip of a person.

Place it in a <Sequence> to start the clip later.

PropWhat it does
srcthe clip of the person
matteits person matte (white = person), from tools/matte.mjs
track?where the person is on every frame, from tools/matte.mjs --track; without it the rays start mid-frame
rate?the clip's playback rate
cuts?when to cut to the poster; without cuts the poster is on throughout
flash?frames that flash to a single yellow card
title?the three title rows; null for none
chest?how far below the person's centre the rays and shapes start, px (1920x1080 space)
id?a prefix for the layer ids, unique per <PopArt> on screen
seed?string

<Blobs />

Boxes, labels and links on a tracked clip's blobs.

Put it over the clip, the same size.

PropWhat it does
trackBlobTrack
from?The composition frame the tracked clip starts on. Default 0.
width?The overlay's size: the clip's picture, filling it. Default the composition's.
height?number
box?How each blob is marked: a full box, the box's corners, a cross on its centre, or nothing. Default frame.
label?The text beside each box: its id, its centre as 0..1 coordinates, both, or nothing. Default both.
links?BlobLinks
reach?For links="all": how far apart two blobs may be and still be linked, as a fraction of the diagonal.
invert?0..1: the share of blobs (picked by id) filled solid in difference blending, inverting the picture under them.
min?Blobs smaller than this fraction of the frame are left out.
max?The biggest this many are kept.
color?string
blend?How the boxes, lines and labels sit on the picture. difference keeps them readable on white and black alike (a 1-bit picture); normal keeps color as it is. Default normal.
stroke?Line width, px.
fontSize?number
id?Prefix of the layer ids.

<HalftonePoster />

A clip printed as a halftone poster: panels of ink-on-paper dots, the person over flat ground, an off-register shadow and a title.

PropWhat it does
srcstring
matte?The person's matte (white = person), timed as src. Without it the whole picture is printed.
width?number
height?number
rate?number
trimBefore?number
panels?Side by side; default one panel, blue on yellow.
changes?Panel sets that cut in on composition frames, as a poster series flicking over.
size?number
angle?number
punch?number
bias?number
shape?'circle' | 'line' | 'square'
offset?With a matte: the person's silhouette in each panel's shadow colour, this many px off. Without a matte: a second print of the picture in shadow ink, multiplied over, this far off.
backdrop?With a matte: the ground flat, or the clip behind the person faintly in the panel's ink. Default flat.
title?PosterTitle
steps?Drawings a second; the picture holds between them. 0 for every frame. Default 12.
id?string

<Fragments />

Clips seen through windows on planes at different depths, with a camera moving through them.

PropWhat it does
piecesPiece[]
camera?Keys the camera eases between (x, y in px, z in depth units), or a function of the frame. Default: a slow push from z 0 to 0.5 over the composition.
colors?Colours of the tags by name; other names get one from a set, the same each time.
fontSize?Tag text size, clip px. Default 22.
fog?0..1: how much a piece dims per unit of depth past 1. Default 0.25.
inspect?Show piece inspect flat, whole and filling the frame, at its clip's own frame (its from ignored), with every box's id, every spot's name and a grid in clip pixels: render stills of it to name the ids and place spots.
id?string

<Reticle />

A box with corner ticks and a label, on the tracked point.

PropWhat it does
trackPointTrack
from?number
width?number
height?number
size?The box's side, px.
label?The text under the box. A confidence figure flickers beside it.
color?string
jitter?px the box shakes by each frame, as a lock that is never quite still.
Effects (9)

Layer effects: put them in a layer's effects.

acid()

Brightness to hue: from hue (degrees) round the colour wheel cycles times (negative runs the other way) as the picture brightens, gamma under 1 spending more of the turn on the shadows, at full saturation, the brightest parts washed to white: the acid heat camera.

adaptiveCut()

A hard black and white cut that follows the footage: each pixel is cut against the mean brightness of a wide patch round it (reach, a fraction of the frame height), times bias, so bright footage and dark footage both split into big black and white shapes instead of going all white or all black.

acidHeat()

Acid heat camera.

1 and 4 soft blobs, folded; 2 sharp, warm shadows; 3 sharp, teal shadows.

fold()

One half folded onto the other. axis 0: left onto right, 1: top onto bottom. box is the picture on the canvas ([x, y, w, h], px); without it, the whole canvas.

grainyBW()

Grainy black and white.

1 soft and high-key, 5 high-key with grain; 2-4 a hard cut that follows the footage's brightness (3 and 4 folded), 6 the cut smeared down.

nightVision()

Night vision: lime phosphor with lifted blacks, a little noise.

1-5 smeared by the camera's move, 6 still.

screenGlow()

Screen glow: the picture's own colours pushed bright and blue-cyan into a big bloom.

1-3 bright (3 soft), 7 deep blue and crushed, 8 nearly clean, a little cool; 4-6 are 1 with room for an overlay (FLASH_OVERLAY).

streak()

A blur along one direction (degrees), as a fast pan or a shake smears it.

halftonePoster()

The halftone look as layer effects: the layer printed as ink dots on paper.

Functions (12)

crt()

A colour tube: curved glass, scanlines, aperture grille, misconvergence, a rolling bar, static and dark corners.

PropWhat it does
cx?The tube face's centre and half-size on the canvas, px. The default is the whole layer.
cy?number
hw?number
hh?number
curve?How far the glass bends. 0 is flat.
pitch?Source pixels per scanline.
scan?0..1: how dark between the lines.
grille?Screen pixels per grille stripe.
mask?0..1: how strong the grille is.
conv?Pixels the red and blue guns land off green.
noise?number
glass?number
offx?1 is on. Switching off: offy falls to 0 first (a line), then offx (a dot).
offy?number

depthLook()

A depth map's look: near is white, far is black, smooth, no texture.

Brightness stands in for nearness.

lookEffects()

The effects for a vjLookSchema value (from the Studio panel): <Layer effects={lookEffects(look)}>.

oneBit()

One bit a pixel: grey, hard contrast, an ordered dither in cells of size px, printed in ink on paper.

pixels()

A magnifier: blocks, then red, green and blue subpixel stripes as the zoom grows.

switchOff()

The tube switching off over t 0..1, as crt()'s offx and offy: the picture folds to a bright line over the first 60%, and the line to a dot over the rest.

Spread it into the options: crt({ ...switchOff(t) }).

thermal()

A thermal camera's palette on the picture's brightness, a little soft.

vhs()

A worn tape: line wobble, late smeared colour, a head-switch tear, a drifting tracking band, snow and dropouts.

PropWhat it does
jitter?number
wobble?number
trackAt?0..1: where the tracking band is, top to bottom.
trackW?Half-height of the band, px.
track?0..1: how bad the tracking is.
bleed?How wide the colour smears, px, and how late it lands.
delay?number
sat?number
snow?number
drops?0..1: chance per line per frame of a dropout.

blobsAt()

The blobs on composition frame frame (at fps) of a clip that starts on frame from, scaled to width x height.

The track may run at another rate than the composition: it is read by time. Past the clip's end: none.

linksOf()

cameraAt()

The camera on frame: eased between the keys, held before the first and after the last.

PropWhat it does
piecesPiece[]
camera?Keys the camera eases between (x, y in px, z in depth units), or a function of the frame. Default: a slow push from z 0 to 0.5 over the composition.
colors?Colours of the tags by name; other names get one from a set, the same each time.
fontSize?Tag text size, clip px. Default 22.
fog?0..1: how much a piece dims per unit of depth past 1. Default 0.25.
inspect?Show piece inspect flat, whole and filling the frame, at its clip's own frame (its from ignored), with every box's id, every spot's name and a grid in clip pixels: render stills of it to name the ids and place spots.
id?string

pointAt()

The tracked point on composition frame frame (at fps) of a clip that starts on from, scaled to width x height; held at the first or last point outside the clip.

Constants (7)

IRON

A thermal camera's palette (iron: cold violet through red to white-hot), a little soft as such sensors are.

RAINBOW

The other common one: cold blue through green to hot red and white.

FLASH_OVERLAY

Which screen-glow variants lay an overlay on (screen blend), and how strongly.

The overlay is the caller's.

LOOK_KINDS

The looks lookEffects knows, none included.

blobStyleSchema

How <Blobs> marks the blobs: its props other than the track.

Spread it into <Blobs>.

vjLookSchema

One look and the settings of each, so switching looks keeps what was set on the others.

MONO

Looks

The look kinds the Studio panel can switch between, and the export that draws each.

none
No look.
crt crt
A colour tube: curved glass, scanlines, aperture grille, misconvergence, a rolling bar, static and dark corners.
vhs vhs
A worn tape: line wobble, late smeared colour, a head-switch tear, a drifting tracking band, snow and dropouts.
oneBit oneBit
One bit a pixel: grey, hard contrast, an ordered dither in cells of size px, printed in ink on paper.
thermal thermal
A thermal camera's palette on the picture's brightness, a little soft.
depth depthLook
A depth map's look: near is white, far is black, smooth, no texture.
pixels pixels
A magnifier: blocks, then red, green and blue subpixel stripes as the zoom grows.
glow screenGlow
Screen glow: the picture's own colours pushed bright and blue-cyan into a big bloom.
acid acidHeat
Acid heat camera.
night nightVision
Night vision: lime phosphor with lifted blacks, a little noise.
grainy grainyBW
Grainy black and white.
halftone halftonePoster
The halftone look as layer effects: the layer printed as ink dots on paper.

Examples

A look and tracked boxes over a clip
import { Blobs, thermal, type BlobTrack } from '@kinetographdev/vj';
import track from './track/clip-blobs.json' with { type: 'json' };

<Layer id="clip" effects={thermal()}>
  <Video src={staticFile('clip.mp4')} width={1920} height={1080} fit="cover" muted />
</Layer>
<Blobs track={track as BlobTrack} box="corners" links="chain" />
Track once, offline, then draw
# finds what moved since the last frame; --debug writes every 10th frame with its boxes
node plugins/vj/tools/blobs.mjs --in public/clip.mp4 --out track/clip-blobs.json --debug out/blobs

# follows one patch (x, y, w, h on the first frame)
node plugins/vj/tools/track.mjs --in public/clip.mp4 --box 900,300,120,120 --out track/clip-point.json

In Studio

Panel

Studio gets a VJ panel with a card for each look and that look's own sliders and colours. Switching looks keeps the settings of the others. On the preview you drag and resize the CRT screen and drag the magnifier's centre. A second panel sets how the tracking marks look: box style, labels, links, blend, how many blobs to show, line width and colour.

Tracking runs on your own machine ahead of time, so the panel only styles the result. The plugin adds no agent tools. The skill walks an agent through tracking a clip, checking the debug images, tuning the tracker and rendering a still to check. For Fragments it has the agent name the boxes from stills of each clip.

It is a package in the source repository. Its skill comes with it, so an agent can use it without being taught.