A camera push and a fly-through
A sphere of 600 purple beads bursts outward from its center as the camera pushes in, and at the end the beads fly out past the camera. It uses Trillium, the three.js connector for WildflowerJS (Using Trillium covers views and bindings).
A Trillium view whose canvas sits inside a scene is drawn once after every seek, so seek(local) can move the camera directly.
The formation comes from a function of the clip's time, beadsAt(t), bound with view.instanced(() => this.beads, mesh, spec).
<div id="stage" data-composition-id="space" data-start="0" data-duration="5" data-width="1280" data-height="720" data-fps="30">
<div class="layer" data-component="space" data-start="0" data-duration="5">
<canvas width="1280" height="720"></canvas>
</div>
</div>
import * as THREE from 'three';
const { scene, spring, ramp, mix, ease } = wildflower.kinetic;
wildflower.three.use(THREE);
const inOut = ease('power3.inOut'), flyIn = ease('power3.in');
const BEADS = 600;
const golden = Math.PI * (3 - Math.sqrt(5));
const SPHERE = Array.from({ length: BEADS }, (_, i) => {
const y = 1 - 2 * (i + 0.5) / BEADS, r = Math.sqrt(1 - y * y), a = i * golden;
return [Math.cos(a) * r * 2.2, y * 2.2, Math.sin(a) * r * 2.2];
});
// The beads at t: bursting out from the center on a spring, then flying out past the camera.
function beadsAt(t) {
const out = spring(t, { stiffness: 120, damping: 11 });
const fly = 1 + 7 * ramp(t, 4.3, 5, flyIn);
return SPHERE.map((p, i) => ({ id: i, x: p[0] * out * fly, y: p[1] * out * fly, z: p[2] * out * fly, scale: 0.06, colour: 0xaa3de6 }));
}
const camera = new THREE.PerspectiveCamera(40, 1280 / 720, 0.05, 100);
scene('space', {
computed: {
beads() { return beadsAt(this.local); },
},
init() {
const renderer = new THREE.WebGLRenderer({ canvas: this.element.querySelector('canvas'), antialias: true, preserveDrawingBuffer: true });
renderer.setSize(1280, 720, false);
const world = new THREE.Scene();
const mesh = new THREE.InstancedMesh(new THREE.SphereGeometry(1, 20, 14), new THREE.MeshBasicMaterial(), BEADS);
world.add(mesh);
const view = wildflower.three.view('space-view', { renderer, scene: world, camera, render: 'change' });
view.instanced(() => this.beads, mesh, { position: ['x', 'y', 'z'], scale: 'scale', color: 'colour', pickable: false });
renderer.compile(world, camera);
},
seek(local) {
camera.position.set(0, 0, mix(9.5, 5.9, ramp(local, 0, 4.6, inOut)));
camera.lookAt(0, 0, 0);
},
});
html, body { margin: 0; background: #0a0b10; }
#stage { position: relative; overflow: hidden; background: #07060d; }
.layer { position: absolute; inset: 0; }
canvas { display: block; width: 1280px; height: 720px; }
[data-composition-id]:not([data-kinetic-ready]) { visibility: hidden; }
A camera push and a fly-through
- The renderer is created with
preserveDrawingBuffer: trueso the canvas still holds the frame when it is captured, and development builds warn without it (KN-190). renderer.compile()builds the shaders ininit(), so no seek has to build them.
The space scene of the Showreel demo has the same shape, and sets its camera from a computed in the view's before callback.
A push over flat HTML needs no three.js: A camera push over layers does it with Kinetic's own camera().