Which to use

Blur, grain, music, and a clip's fade each have more than one route in Kinetic. This page starts from what you want, gives the route for it, and says which route is the default where there is one.

Each table links to the route's own section, which has its options and errors. The examples put the routes side by side, so the difference between them is on the screen.

Blur

Kinetic blurs six different things, so start from what should be soft: one element, a part of the frame, a cut between two clips, whatever is away from the focal plane, single letters, or the whole frame.

What you wantThe route
An element that blurs in or outA blur track in keyframes, in px: blur: { at: [0, 0.6], to: [12, 0] } (A layer with keyframes).
A part of the frame blurred, such as tilt-shift focus or a soft round patchblur(element, { scene: this, radius, marks }) on an empty element over it (Blur where the marks paint).
A cut from one clip to the next through a blurdata-clip-transition="blur" on the incoming clip, or blur with a length in data-clip-enter and data-clip-exit (The kinds).
Depth of field: the farther from the focal plane, the softerfocus(z, plane, { range, max }), which returns the px for a filter: blur() (focus()).
Single letters of a title, each blurred by its own amounttext()'s per-letter blur, in px, from letter(i, ch) (Lines and letters).
The whole frame a little soft, more toward its edgesThe finish's soften: config({ finish: { soften: 4 } }) (The finish).

Blur from movement is motion blur, which a render's shutter gives, with smear() for the preview (Motion blur). The per-letter blur draws from a font's baked outlines, so its example is on Type with a weight per letter.

<div id="stage" data-composition-id="blurs" data-start="0" data-duration="6" data-width="1280" data-height="720" data-fps="30">
    <p class="label a">An element<code>a blur track</code></p>
    <p class="label b">A region<code>blur(el, { marks })</code></p>
    <p class="label c">A cut<code>clip transition: blur</code></p>

    <div class="panel a" data-component="word" data-start="0" data-duration="6">
        <h1 data-bind-style="word">Hello</h1>
    </div>

    <div class="panel b" data-component="region" data-start="0" data-duration="6">
        <img src="media/daylily.jpg" alt="">
        <div class="over"></div>
    </div>

    <div class="panel c">
        <div id="one" class="card" data-start="0" data-duration="3.5"><img src="media/daylily.jpg" alt=""></div>
        <div class="card two" data-start="one - 1" data-duration="3.5" data-clip-transition="blur">Two</div>
    </div>
</div>
const { scene, blur } = wildflower.kinetic;

// An element: a blur track, sharp between 1 and 4.5 s.
scene('word', {
    keyframes: {
        word: { blur: { at: [0, 1, 4.5, 5.5], to: [28, 0, 0, 28], ease: 'power2.inOut' } }
    }
});

// A region: two bands blur the top and the foot of the picture, and leave a strip across the middle sharp.
scene('region', {
    init() {
        blur(this.element.querySelector('.over'), { scene: this, radius: 20, marks: (m) => m
            .band({ from: [0, 0], to: [380, 0], width: 220, side: 'right', falloff: 'smooth' })
            .band({ from: [380, 540], to: [0, 540], width: 220, side: 'right', falloff: 'smooth' }) });
    }
});

// A cut: the markup's data-clip-transition does it, with no scene code.
html, body { margin: 0; background: #0a0b10; }

#stage { position: relative; overflow: hidden; background: #0b0f1a; }

.label { position: absolute; top: 28px; width: 380px; margin: 0; font: 700 32px system-ui, sans-serif; color: #fff; }
.label code { display: block; margin-top: 8px; font: 500 24px ui-monospace, monospace; color: #b8a6ff; }

.panel { position: absolute; top: 140px; width: 380px; height: 540px; overflow: hidden; border-radius: 16px; background: #161b2c; }
.a { left: 30px; }
.b { left: 450px; }
.c { left: 870px; }

.panel h1 { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; margin: 0; font: 800 110px system-ui, sans-serif; color: #fff; }
img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.over { position: absolute; inset: 0; }

.card { position: absolute; inset: 0; }
.two { display: flex; align-items: center; justify-content: center; background: #2c5a46; font: 800 110px system-ui, sans-serif; color: #fff; }

[data-composition-id]:not([data-kinetic-ready]) { visibility: hidden; }
An element, a region, and a cut

The word blurs as a whole, by its own track. The picture stays sharp across the middle and soft at the top and the foot, and the strip holds still. The cut is markup only: the second clip starts a second before the first ends, and the overlap is the blur.

<div id="stage" data-composition-id="depth" data-start="0" data-duration="6" data-width="1280" data-height="720" data-fps="30">
    <p class="label a">Depth of field<code>focus(z, plane)</code></p>
    <p class="label b">The whole frame<code>finish: { soften: 8 }</code></p>

    <div class="panel a" data-component="depth" data-start="0" data-duration="6">
        <p class="plane" data-bind="planeText"></p>
        <div class="row" data-list="discs" data-key="key">
            <template><div class="disc" data-bind-style="style"><span data-bind="z"></span></div></template>
        </div>
    </div>

    <div class="panel b" data-finish>
        <img src="media/daylily.jpg" alt="">
    </div>
</div>
const { scene, focus, styleAt } = wildflower.kinetic;

// The whole frame: the finish's soften, on the element marked data-finish.
wildflower.kinetic.config({ finish: { soften: 8 } });

const DEPTHS = [0, -200, -400, -600, -800];

// Depth of field: the focal plane moves back to -800 and returns, and each disc is blurred by its distance from it.
scene('depth', {
    keyframes: {
        plane: { at: [0.5, 2.5, 3.5, 5.5], to: [0, -800, -800, 0], ease: 'power2.inOut' }
    },
    computed: {
        planeText() { return 'plane ' + Math.round(this.plane); },
        discs() {
            return DEPTHS.map((z, i) => ({
                key: i,
                z: String(z),
                style: styleAt(this.local, { scale: 1000 / (1000 - z), blur: focus(z, this.plane, { range: 200, max: 12 }) })
            }));
        }
    }
});
html, body { margin: 0; background: #0a0b10; }

#stage { position: relative; overflow: hidden; background: #0b0f1a; }

.label { position: absolute; top: 28px; width: 580px; margin: 0; font: 700 32px system-ui, sans-serif; color: #fff; }
.label code { display: block; margin-top: 8px; font: 500 24px ui-monospace, monospace; color: #b8a6ff; }

.panel { position: absolute; top: 140px; width: 580px; height: 540px; overflow: hidden; border-radius: 16px; background: #161b2c; }
.a { left: 40px; }
.b { left: 660px; }

.plane { position: absolute; left: 24px; top: 16px; margin: 0; font: 500 26px ui-monospace, monospace; color: #c9c9dc; }
.row { position: absolute; inset: 0; display: flex; align-items: center; justify-content: space-evenly; }
.disc { display: flex; align-items: center; justify-content: center; width: 100px; height: 100px; border-radius: 50%; background: #d99a2b; font: 700 24px system-ui, sans-serif; color: #1b1406; }

img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

[data-composition-id]:not([data-kinetic-ready]) { visibility: hidden; }
Depth of field and the whole frame

Each disc is sharp while the focal plane is at its depth and softens as the plane moves away from it. The picture is soft all over, by the finish, which a render applies to every frame of the file.

Grain

Grain over the whole frame is the finish's grain, and it is the default. It stays still unless its fps is set, and at the frame rate it is film grain. shade() with kind: 'grain' is for grain that varies across the frame, and the finish's dust is specks rather than grain.

What you wantThe route
Grain over the whole frame (the default)The finish's grain: config({ finish: { grain: 0.3 } }), still, a paper's tooth (The finish).
Film grain that changes every frameThe finish's grain with fps at the frame rate: config({ finish: { grain: { amount: 0.3, fps: 30 } } }) (The finish).
Grain heavier in some places, such as toward the edgesshade(canvas, { scene: this, kind: 'grain', fps: 30, marks }), as strong as the marks' field (Light, grain and blending).
Specks of dust that come and goThe finish's dust: config({ finish: { dust: 0.4 } }) (The finish).

The finish is one setting for the composition, so the page shows it on one element: the root, or the element in it marked data-finish. That is why the grain and the dust below are two examples.

<div id="stage" data-composition-id="grain" data-start="0" data-duration="6" data-width="1280" data-height="720" data-fps="30">
    <p class="label a">Over the frame<code>finish: { grain }</code></p>
    <p class="label b">Heavier at the edges<code>shade(canvas, { kind: 'grain' })</code></p>

    <div class="panel a" data-finish>
        <img src="media/daylily.jpg" alt="">
    </div>

    <div class="panel b" data-component="edges-grain" data-start="0" data-duration="6">
        <img src="media/daylily.jpg" alt="">
        <canvas></canvas>
    </div>
</div>
const { scene, shade } = wildflower.kinetic;

// Over the frame: the finish's grain, on the element marked data-finish.
wildflower.kinetic.config({ finish: { grain: { amount: 0.6, size: 2 } } });

// Heavier at the edges: a glow with invert: true is empty at its center and full past its radius.
scene('edges-grain', {
    init() {
        shade(this.element.querySelector('canvas'), { scene: this, kind: 'grain', fps: 30, scale: 2, marks: (m) => m
            .glow({ at: [290, 270], radius: 400, invert: true, falloff: 'power2.in' }) });
    }
});
html, body { margin: 0; background: #0a0b10; }

#stage { position: relative; overflow: hidden; background: #0b0f1a; }

.label { position: absolute; top: 28px; width: 580px; margin: 0; font: 700 32px system-ui, sans-serif; color: #fff; }
.label code { display: block; margin-top: 8px; font: 500 24px ui-monospace, monospace; color: #b8a6ff; }

.panel { position: absolute; top: 140px; width: 580px; height: 540px; overflow: hidden; border-radius: 16px; background: #161b2c; }
.a { left: 40px; }
.b { left: 660px; }

img, canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
img { object-fit: cover; }

[data-composition-id]:not([data-kinetic-ready]) { visibility: hidden; }
Grain over the frame and grain at the edges

The finish's grain is even over the whole picture, and still. The shaded grain changes 30 times a second, and it is clean at the flower's center and heaviest in the corners, where the glow's field is full.

<div id="stage" data-composition-id="dust" data-start="0" data-duration="6" data-width="1280" data-height="720" data-fps="30">
    <p class="label">Dust<code>finish: { dust }</code></p>

    <div class="panel" data-finish>
        <img src="media/daylily.jpg" alt="">
    </div>
</div>
// Dust: sparse light specks, new on every frame. The picture between them stays clean.
wildflower.kinetic.config({ finish: { dust: { amount: 1, size: 2 } } });
html, body { margin: 0; background: #0a0b10; }

#stage { position: relative; overflow: hidden; background: #0b0f1a; }

.label { position: absolute; left: 350px; top: 28px; width: 580px; margin: 0; font: 700 32px system-ui, sans-serif; color: #fff; }
.label code { display: block; margin-top: 8px; font: 500 24px ui-monospace, monospace; color: #b8a6ff; }

.panel { position: absolute; left: 350px; top: 140px; width: 580px; height: 540px; overflow: hidden; border-radius: 16px; background: #161b2c; }

img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

[data-composition-id]:not([data-kinetic-ready]) { visibility: hidden; }
Dust

Dust is a few light specks in new places on every frame, with the picture clean between them, where grain covers every pixel.

Music

The beat of steady music, which is most music made in a DAW, is a tempo on the audio clip, read with tempo(), and that is the default. A beat file read by beat() is for music whose tempo drifts. Loudness and named moments each have a route of their own.

What you wantThe route
Cuts and moves on the beat of steady music (the default)data-tempo, data-downbeat, and data-meter on the audio clip, read with tempo(): tempo().at(n) is beat n's time, and tempo().of(t) the beat at t. scripts/beatgrid.cjs finds the three values (Markers and tempo).
The beats of music whose tempo drifts, such as live playing or an old recordingA beat file, which lists each beat's time, read by beat(t, beats) as a pulse from 0 to 1; HyperFrames' beat detection writes one (beat()).
Something that follows how loud the music islevel(t, band) for a band's level, or spectrum(t, bins) for levels from low to high (level() and spectrum()).
A named moment, such as the dropdata-markers="{ drop: 14.28 }" on the audio clip, in the file's seconds, and timeOf('drop') for its composition time (Markers and tempo).

A tempo is one number for the whole file, so it stays on the beat only while the music does. A beat file gives every beat its own time, which follows a tempo that drifts.

The default: the grid the clip's data-tempo, data-downbeat, and data-meter describe, a tick per beat with the beat now lit, and the disc swelling on each beat. The speaker turns the sound on, and a click pauses.
A beat file: beat() reads the beats' times and strengths and scales the disc. A click on the stage pauses.

Fading a clip

The default is the clip attributes, which are markup only, with no scene code: data-clip-enter and data-clip-exit fade one clip in and out, and data-clip-transition fades from one clip into the next. edges and presence are for a scene whose own code needs to know how far in or out it is.

What you wantThe route
A clip that fades in, out, or both (the default)data-clip-enter="fade 0.5" and data-clip-exit="fade 0.5" on the clip, with a length in seconds or frames (The attributes).
A fade from one clip into the nextThe clips overlap, and the incoming one carries data-clip-transition="fade"; the overlap is the fade's length (Transitions).
A scene whose code needs to know how far in or out it is, such as to stagger its children by itedges: { enter, exit }, then this.enter, this.exit, and this.presence, each 0 to 1 (Edges).
A fade that comes with a move or a scale on one elementAn opacity track in keyframes beside the move (A layer with keyframes).
A fade on an element inside a scene that is no clipramp(t, from, to, ease) as its opacity, or transition('fade', p) bound with data-bind-style (ramp(), transition()).
<div id="stage" data-composition-id="fades" data-start="0" data-duration="6" data-width="1280" data-height="720" data-fps="30">
    <p class="label a">By attribute<code>data-clip-enter, data-clip-exit</code></p>
    <p class="label b">By presence<code>edges, this.presence</code></p>

    <div class="panel a" data-start="0.5" data-duration="5" data-clip-enter="fade 0.6" data-clip-exit="fade 0.6">
        <h1>Fade</h1>
    </div>

    <div class="panel b" data-component="rows" data-start="0.5" data-duration="5">
        <div class="list" data-list="rows" data-key="key">
            <template><div class="bar" data-bind-style="style"></div></template>
        </div>
    </div>
</div>
const { scene, ramp, styleAt } = wildflower.kinetic;

// By attribute: the markup fades the clip, with no scene code.

// By presence: each bar takes its own part of the scene's presence, so the bars come in one after another and leave in the reverse order.
scene('rows', {
    edges: { enter: 1, exit: 1 },
    computed: {
        rows() {
            const out = [];
            for (let i = 0; i < 6; i++) {
                const p = ramp(this.presence, i * 0.1, i * 0.1 + 0.5, 'power2.out');
                out.push({ key: i, style: styleAt(this.local, { opacity: p, translateX: (1 - p) * -60 }) });
            }
            return out;
        }
    }
});
html, body { margin: 0; background: #0a0b10; }

#stage { position: relative; overflow: hidden; background: #0b0f1a; }

.label { position: absolute; top: 28px; width: 580px; margin: 0; font: 700 32px system-ui, sans-serif; color: #fff; }
.label code { display: block; margin-top: 8px; font: 500 24px ui-monospace, monospace; color: #b8a6ff; }

.panel { position: absolute; top: 140px; width: 580px; height: 540px; overflow: hidden; border-radius: 16px; background: #161b2c; }
.a { left: 40px; }
.b { left: 660px; }

.panel h1 { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; margin: 0; font: 800 120px system-ui, sans-serif; color: #fff; }

.list { position: absolute; inset: 60px; display: flex; flex-direction: column; justify-content: space-between; }
.bar { height: 60px; border-radius: 12px; background: #9d7bff; }

[data-composition-id]:not([data-kinetic-ready]) { visibility: hidden; }
By attribute and by presence

The left panel fades as one clip, by its two attributes. The right panel needs to know how far in the scene is to stagger its bars, so it reads presence; a fade that needs no such value stays with the attributes.