export type FrameTime = { milliseconds: number, seconds: number, frames: number } export type InitConfig = { isPreview: boolean } export abstract class Video { public constructor(public canvas: HTMLCanvasElement) { }; public abstract renderFrame(time: FrameTime): Promise | void; /** (re-)Initializes the Video object. Also called on window resizes. */ public abstract init(config: InitConfig): void | Promise; private _isInit = false; /** The frames per second to render at */ public abstract get fps(): number; /** Length in frames */ public abstract get length(): number; /** A URL (and matching filename) to an ffmpeg-compatible audio file */ public audioUrl?: readonly [filename: string, fileUrl: string]; /** Resizes the canvas to a predetermined render resolution - must only be called in init() - do not overwrite */ public resize(x: number, y: number) { if (!this._isInit) throw new Error('Must only call resize() in init.') this.canvas.width = x; this.canvas.height = y; const parentW = this.canvas.parentElement!.clientWidth, parentH = this.canvas.parentElement!.clientHeight if (x <= parentW && y <= parentH) { this.canvas.style.width = `${x}px`; this.canvas.style.height = `${y}px`; } else if (x <= parentW && y > parentH) { this.canvas.style.width = `${x / y * parentH}px`; this.canvas.style.height = `${parentH}px`; } else if (y <= parentH && x > parentW) { this.canvas.style.width = `${parentW}px`; this.canvas.style.height = `${y / x * parentW}px`; } else { if ((parentW / x) * y > parentH) { this.canvas.style.width = `${(parentH / y) * x}px` this.canvas.style.height = `${parentH}px` } else { this.canvas.style.width = `${parentW}px` this.canvas.style.height = `${(parentW / x) * y}px` } } } /** The width of the video, in pixels */ public get w() { return this.canvas.width; } /** The height of the video, in pixels */ public get h() { return this.canvas.height; } /** Use to cleanup any mess you made - do not remove the canvas, it may be reused. */ public cleanup() { }; } export type VideoConstructor = new (...params: ConstructorParameters) => Video