timeline.ts
examples/film/timeline.ts · raw · all examples · site home
Exports: tempoclamp01lerpsmootheaseInOuteaseOuteaseInexpoOutspanwindowrandomShot
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
// Time in the film: seconds, and the bars of the score (100 BPM, 4/4), so
// cuts, captions and music line up. A shot is a span of bars with its own
// scene and camera; the film draws the one under the playhead. The other
// films (film2/, film3/) take their own tempo from tempo().
import type * as THREE from "three";
// Beats and 4/4 bars at `bpm`, in seconds
export function tempo(bpm: number) {
const BEAT = 60 / bpm;
const BAR = BEAT * 4;
return { BPM: bpm, BEAT, BAR, bars: (n: number) => n * BAR, beats: (n: number) => n * BEAT };
}
export const { BPM, BEAT, BAR, bars, beats } = tempo(100);
export const clamp01 = (x: number) => Math.min(1, Math.max(0, x));
export const lerp = (a: number, b: number, t: number) => a + (b - a) * t;
export const smooth = (t: number) => {
const x = clamp01(t);
return x * x * (3 - 2 * x);
};
export const easeInOut = (t: number) => {
const x = clamp01(t);
return x < 0.5 ? 4 * x * x * x : 1 - (-2 * x + 2) ** 3 / 2;
};
export const easeOut = (t: number) => 1 - (1 - clamp01(t)) ** 3;
export const easeIn = (t: number) => clamp01(t) ** 3;
export const expoOut = (t: number) => (t >= 1 ? 1 : 1 - 2 ** (-10 * clamp01(t)));
// 0 -> 1 over [a, b]
export const span = (t: number, a: number, b: number) => clamp01((t - a) / (b - a));
// Rises over [a, a + fade], holds, falls over [b - fade, b]
export const window = (t: number, a: number, b: number, fade: number) => Math.min(smooth((t - a) / fade), smooth((b - t) / fade));
// Deterministic randomness: one stream per seed
export function random(seed: number) {
let s = seed >>> 0;
return () => {
s = (s + 0x6d2b79f5) >>> 0;
let t = s;
t = Math.imul(t ^ (t >>> 15), t | 1);
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
export interface Shot {
name: string;
// Bars from the film's start
from: number;
to: number;
// Before the first frame of the shot (each time the playhead enters it),
// and when the playhead leaves it
enter?(): void;
exit?(): void;
// Seconds into the shot, the shot's length, and seconds into the film
frame(local: number, length: number, time: number): void;
// The draw: the scene from the camera unless the shot draws itself
scene?: THREE.Scene;
camera?: THREE.PerspectiveCamera;
render?(): void;
}