Bokeh particles with no filter
Three hundred points of light sit at different depths, and as the focal plane moves, each one out of focus becomes a growing soft disc, as a lens draws it.
focus() with max: 1 returns the defocus, 0 on the plane and close to 1 far from it, and seek() writes each light's style from it through one static pool.
- The disc is a radial gradient whose hard edge moves inward and whose size grows with the blur, so the softness comes from the gradient.
- The pool writes 300 styles per seek, and none sets a filter.
The same pattern fits dust, stars, rain and city lights.
For a filter that blurs a few bands at once, see Depth bands for hundreds of elements.
The stylesheet needs .light { position: absolute; left: 0; top: 0; border-radius: 50%; }.
<div id="stage" data-composition-id="bokeh" data-start="0" data-duration="5" data-width="1280" data-height="720" data-fps="30">
<div class="layer" data-component="bokeh" data-start="0" data-duration="5">
<div data-pool="lights" data-key="id"><template><i class="light" data-bind-style="style"></i></template></div>
</div>
</div>
const { scene, random, focus, styleAt } = wildflower.kinetic;
const COUNT = 300;
scene('bokeh', {
pools: { lights: {} },
keyframes: {
plane: { at: [0.5, 4.5], to: [-1000, 0], ease: 'power2.inOut' },
},
init() {
const rnd = random(23);
for (let i = 0; i < COUNT; i++) {
this.pools.lights.add({ id: i, x: rnd() * 1280, y: rnd() * 720, z: -rnd() * 1000, base: 3 + rnd() * 3, hue: 30 + rnd() * 40, style: {} });
}
},
seek(local) {
const plane = this.plane;
this.pools.lights.forEach((l) => {
const blur = focus(l.z, plane, { range: 250, max: 1 }); // 0 sharp, 1 fully out of focus
const size = l.base * (1 + 6 * blur); // the disc grows with the blur
const edge = 100 - 70 * blur; // and its edge softens
this.pools.lights.update(l.id, {
style: {
width: size.toFixed(1) + 'px',
height: size.toFixed(1) + 'px',
...styleAt(local, { translateX: l.x - size / 2, translateY: l.y - size / 2 }),
opacity: (1 - 0.6 * blur).toFixed(3),
background: 'radial-gradient(circle, hsl(' + l.hue.toFixed(0) + ' 90% 70%) ' + (edge - 30).toFixed(0) + '%, transparent ' + edge.toFixed(0) + '%)',
},
});
});
},
});
html, body { margin: 0; background: #0a0b10; }
#stage { position: relative; overflow: hidden; background: #0b0a14; }
.layer { position: absolute; inset: 0; }
.light { position: absolute; left: 0; top: 0; border-radius: 50%; }
[data-composition-id]:not([data-kinetic-ready]) { visibility: hidden; }
Bokeh particles with no filter
The Showreel demo's focus scene drifts its bokeh lights behind the phrases this way.