summaryrefslogtreecommitdiff
path: root/apps/web/src/effects/definitions/motion-blur.ts
blob: b20e6c263d0850c4eec622230b5d152a7be13ebd (plain) (blame)
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
62
63
64
65
66
67
import type { EffectDefinition } from "@/effects/types";
import { GAUSSIAN_BLUR_SHADER, intensityToSigma } from "./blur";

const MAX_SINGLE_PASS_SIGMA = 10;
const MIN_SIGMA = 0.001;

function parseNumericParam({
	effectParams,
	key,
}: {
	effectParams: Record<string, unknown>;
	key: string;
}): number {
	const raw = effectParams[key];
	return typeof raw === "number" ? raw : Number.parseFloat(String(raw));
}

export const motionBlurEffectDefinition: EffectDefinition = {
	type: "motion-blur",
	name: "Motion Blur",
	keywords: ["motion blur", "smear", "directional", "speed", "streak"],
	category: "lens",
	params: [
		{
			key: "amount",
			label: "Amount",
			type: "number",
			default: 40,
			min: 0,
			max: 100,
			step: 1,
		},
		{
			key: "angle",
			label: "Angle",
			type: "number",
			default: 0,
			min: -180,
			max: 180,
			step: 1,
		},
	],
	renderer: {
		passes: [],
		buildPasses: ({ effectParams, width }) => {
			const sigma = intensityToSigma({
				intensity: parseNumericParam({ effectParams, key: "amount" }),
				resolution: width,
				reference: 1920,
			});
			if (sigma < MIN_SIGMA) return [];

			const angleRad =
				(parseNumericParam({ effectParams, key: "angle" }) * Math.PI) / 180;
			return [
				{
					shader: GAUSSIAN_BLUR_SHADER,
					uniforms: {
						u_sigma: Math.min(sigma, MAX_SINGLE_PASS_SIGMA),
						u_step: Math.max(1, sigma / MAX_SINGLE_PASS_SIGMA),
						u_direction: [Math.cos(angleRad), Math.sin(angleRad)],
					},
				},
			];
		},
	},
};