chore: add util for get effectParams
This commit is contained in:
parent
04c3eed7e0
commit
4f74ec9057
|
|
@ -19,6 +19,9 @@ let pendingTimeoutId: ReturnType<typeof setTimeout> | null = null;
|
|||
/** Detection timeout in milliseconds */
|
||||
const DETECTION_TIMEOUT_MS = 5000;
|
||||
|
||||
/** MediaPipe Face Mesh version — must match package.json dependency */
|
||||
const MEDIAPIPE_VERSION = "0.4.1657299874";
|
||||
|
||||
/** Types that MediaPipe FaceMesh accepts */
|
||||
type MediaPipeImageSource =
|
||||
| HTMLImageElement
|
||||
|
|
@ -80,7 +83,7 @@ async function loadFaceMesh(): Promise<FaceMeshType | null> {
|
|||
const { FaceMesh } = await import("@mediapipe/face_mesh");
|
||||
const fm = new FaceMesh({
|
||||
locateFile: (file: string) =>
|
||||
`https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh/${file}`,
|
||||
`https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh@${MEDIAPIPE_VERSION}/${file}`,
|
||||
});
|
||||
fm.setOptions({
|
||||
maxNumFaces: 1,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { hexToRgb } from "../../utils/color";
|
||||
import { getNumberParam, getStringParam } from "../../utils/params";
|
||||
import fragmentShader from "./blush.frag.glsl";
|
||||
|
||||
/** Blush — soft color blend at cheek positions from face landmarks */
|
||||
|
|
@ -19,8 +20,8 @@ export const blushEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader,
|
||||
uniforms: ({ effectParams, context }) => ({
|
||||
u_intensity: (effectParams.intensity as number) / 100,
|
||||
u_color: hexToRgb(effectParams.color as string),
|
||||
u_intensity: getNumberParam(effectParams, "intensity") / 100,
|
||||
u_color: hexToRgb(getStringParam(effectParams, "color", "#ff9999")),
|
||||
u_cheekLeft: context?.cheekLeft ?? [0.35, 0.55],
|
||||
u_cheekRight: context?.cheekRight ?? [0.65, 0.55],
|
||||
u_cheekRadius: context?.cheekRadius ?? 0.08,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import fragmentShader from "./brightness.frag.glsl";
|
||||
|
||||
export const brightnessEffectDefinition: EffectDefinition = {
|
||||
|
|
@ -24,7 +25,7 @@ export const brightnessEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_intensity: (effectParams.intensity as number) / 100,
|
||||
u_intensity: getNumberParam(effectParams, "intensity") / 100,
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import fragmentShader from "./chromatic-aberration.frag.glsl";
|
||||
|
||||
export const chromaticAberrationEffectDefinition: EffectDefinition = {
|
||||
|
|
@ -17,8 +18,8 @@ export const chromaticAberrationEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_intensity: (effectParams.intensity as number) / 10,
|
||||
u_angle: ((effectParams.angle as number) * Math.PI) / 180,
|
||||
u_intensity: getNumberParam(effectParams, "intensity") / 10,
|
||||
u_angle: (getNumberParam(effectParams, "angle") * Math.PI) / 180,
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import fragmentShader from "./color-balance.frag.glsl";
|
||||
|
||||
/** 3-way color grading: shadows, midtones, highlights */
|
||||
|
|
@ -26,19 +27,19 @@ export const colorBalanceEffectDefinition: EffectDefinition = {
|
|||
fragmentShader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_shadows: [
|
||||
(effectParams.shadowsRed as number) / 200,
|
||||
(effectParams.shadowsGreen as number) / 200,
|
||||
(effectParams.shadowsBlue as number) / 200,
|
||||
getNumberParam(effectParams, "shadowsRed") / 200,
|
||||
getNumberParam(effectParams, "shadowsGreen") / 200,
|
||||
getNumberParam(effectParams, "shadowsBlue") / 200,
|
||||
],
|
||||
u_midtones: [
|
||||
(effectParams.midtonesRed as number) / 200,
|
||||
(effectParams.midtonesGreen as number) / 200,
|
||||
(effectParams.midtonesBlue as number) / 200,
|
||||
getNumberParam(effectParams, "midtonesRed") / 200,
|
||||
getNumberParam(effectParams, "midtonesGreen") / 200,
|
||||
getNumberParam(effectParams, "midtonesBlue") / 200,
|
||||
],
|
||||
u_highlights: [
|
||||
(effectParams.highlightsRed as number) / 200,
|
||||
(effectParams.highlightsGreen as number) / 200,
|
||||
(effectParams.highlightsBlue as number) / 200,
|
||||
getNumberParam(effectParams, "highlightsRed") / 200,
|
||||
getNumberParam(effectParams, "highlightsGreen") / 200,
|
||||
getNumberParam(effectParams, "highlightsBlue") / 200,
|
||||
],
|
||||
}),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import fragmentShader from "./contrast.frag.glsl";
|
||||
|
||||
export const contrastEffectDefinition: EffectDefinition = {
|
||||
|
|
@ -25,7 +26,7 @@ export const contrastEffectDefinition: EffectDefinition = {
|
|||
fragmentShader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
// Map -100..100 → 0..2 (0 = no contrast, 1 = normal, 2 = max)
|
||||
u_contrast: 1 + (effectParams.intensity as number) / 100,
|
||||
u_contrast: 1 + getNumberParam(effectParams, "intensity") / 100,
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import fragmentShader from "./exposure.frag.glsl";
|
||||
|
||||
export const exposureEffectDefinition: EffectDefinition = {
|
||||
|
|
@ -24,7 +25,7 @@ export const exposureEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_exposure: effectParams.stops as number,
|
||||
u_exposure: getNumberParam(effectParams, "stops"),
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import fragmentShader from "./eye-enhance.frag.glsl";
|
||||
|
||||
/** Eye enhance — brighten and sharpen eye regions */
|
||||
|
|
@ -18,8 +19,8 @@ export const eyeEnhanceEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_brightness: (effectParams.brightness as number) / 400,
|
||||
u_contrast: 1 + (effectParams.contrast as number) / 200,
|
||||
u_brightness: getNumberParam(effectParams, "brightness") / 400,
|
||||
u_contrast: 1 + getNumberParam(effectParams, "contrast") / 200,
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import fragmentShader from "./face-brighten.frag.glsl";
|
||||
|
||||
/** Face brighten — soft light blend, optionally masked to face region */
|
||||
|
|
@ -17,7 +18,7 @@ export const faceBrightenEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_intensity: (effectParams.intensity as number) / 200,
|
||||
u_intensity: getNumberParam(effectParams, "intensity") / 200,
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam, getBooleanParam } from "../../utils/params";
|
||||
import fragmentShader from "./film-grain.frag.glsl";
|
||||
|
||||
export const filmGrainEffectDefinition: EffectDefinition = {
|
||||
|
|
@ -18,9 +19,9 @@ export const filmGrainEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader,
|
||||
uniforms: ({ effectParams, time }) => ({
|
||||
u_intensity: (effectParams.intensity as number) / 400,
|
||||
u_grainSize: effectParams.size as number,
|
||||
u_time: effectParams.animated ? (time ?? 0) : 0,
|
||||
u_intensity: getNumberParam(effectParams, "intensity") / 400,
|
||||
u_grainSize: getNumberParam(effectParams, "size", 2),
|
||||
u_time: getBooleanParam(effectParams, "animated", true) ? (time ?? 0) : 0,
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import fragmentShader from "./gamma.frag.glsl";
|
||||
|
||||
export const gammaEffectDefinition: EffectDefinition = {
|
||||
|
|
@ -24,7 +25,7 @@ export const gammaEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_gamma: effectParams.value as number,
|
||||
u_gamma: getNumberParam(effectParams, "value", 1.0),
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import pass1Shader from "./glitch-pass1.frag.glsl";
|
||||
import pass2Shader from "./glitch-pass2.frag.glsl";
|
||||
|
||||
|
|
@ -20,16 +21,16 @@ export const glitchEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader: pass1Shader,
|
||||
uniforms: ({ effectParams, width, time }) => ({
|
||||
u_intensity: (effectParams.intensity as number) / 1000,
|
||||
u_colorSplit: (effectParams.colorSplit as number) / (width * 10),
|
||||
u_time: (time ?? 0) * ((effectParams.speed as number) / 50),
|
||||
u_intensity: getNumberParam(effectParams, "intensity") / 1000,
|
||||
u_colorSplit: getNumberParam(effectParams, "colorSplit") / (width * 10),
|
||||
u_time: (time ?? 0) * (getNumberParam(effectParams, "speed", 50) / 50),
|
||||
}),
|
||||
},
|
||||
{
|
||||
fragmentShader: pass2Shader,
|
||||
uniforms: ({ effectParams, time }) => ({
|
||||
u_intensity: (effectParams.intensity as number) / 100,
|
||||
u_time: (time ?? 0) * ((effectParams.speed as number) / 50),
|
||||
u_intensity: getNumberParam(effectParams, "intensity") / 100,
|
||||
u_time: (time ?? 0) * (getNumberParam(effectParams, "speed", 50) / 50),
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import fragmentShader from "./hue-shift.frag.glsl";
|
||||
|
||||
export const hueShiftEffectDefinition: EffectDefinition = {
|
||||
|
|
@ -25,7 +26,7 @@ export const hueShiftEffectDefinition: EffectDefinition = {
|
|||
fragmentShader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
// Convert degrees to 0..1 range for HSL rotation
|
||||
u_hueShift: (effectParams.degrees as number) / 360,
|
||||
u_hueShift: getNumberParam(effectParams, "degrees") / 360,
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { hexToRgb } from "../../utils/color";
|
||||
import { getNumberParam, getStringParam } from "../../utils/params";
|
||||
import pass1Shader from "./neon-glow-pass1.frag.glsl";
|
||||
import pass2Shader from "./neon-glow-pass2.frag.glsl";
|
||||
|
||||
|
|
@ -21,14 +22,14 @@ export const neonGlowEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader: pass1Shader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_threshold: (effectParams.threshold as number) / 100,
|
||||
u_threshold: getNumberParam(effectParams, "threshold") / 100,
|
||||
}),
|
||||
},
|
||||
{
|
||||
fragmentShader: pass2Shader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_intensity: (effectParams.intensity as number) / 50,
|
||||
u_glowColor: hexToRgb(effectParams.color as string),
|
||||
u_intensity: getNumberParam(effectParams, "intensity") / 50,
|
||||
u_glowColor: hexToRgb(getStringParam(effectParams, "color", "#00ff88")),
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import pass1Shader from "./oil-paint-pass1.frag.glsl";
|
||||
import pass2Shader from "./oil-paint-pass2.frag.glsl";
|
||||
|
||||
|
|
@ -19,13 +20,13 @@ export const oilPaintEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader: pass1Shader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_levels: effectParams.levels as number,
|
||||
u_levels: getNumberParam(effectParams, "levels", 8),
|
||||
}),
|
||||
},
|
||||
{
|
||||
fragmentShader: pass2Shader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_radius: effectParams.radius as number,
|
||||
u_radius: getNumberParam(effectParams, "radius", 4),
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import fragmentShader from "./pixelate.frag.glsl";
|
||||
|
||||
export const pixelateEffectDefinition: EffectDefinition = {
|
||||
|
|
@ -16,7 +17,7 @@ export const pixelateEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_blockSize: effectParams.blockSize as number,
|
||||
u_blockSize: getNumberParam(effectParams, "blockSize", 10),
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import fragmentShader from "./saturation.frag.glsl";
|
||||
|
||||
export const saturationEffectDefinition: EffectDefinition = {
|
||||
|
|
@ -25,7 +26,7 @@ export const saturationEffectDefinition: EffectDefinition = {
|
|||
fragmentShader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
// Map -100..100 → 0..2 (0 = grayscale, 1 = normal, 2 = oversaturated)
|
||||
u_saturation: 1 + (effectParams.intensity as number) / 100,
|
||||
u_saturation: 1 + getNumberParam(effectParams, "intensity") / 100,
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import fragmentShader from "./sharpen.frag.glsl";
|
||||
|
||||
export const sharpenEffectDefinition: EffectDefinition = {
|
||||
|
|
@ -16,7 +17,7 @@ export const sharpenEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_intensity: (effectParams.intensity as number) / 100,
|
||||
u_intensity: getNumberParam(effectParams, "intensity") / 100,
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import pass1Shader from "./sketch-pass1.frag.glsl";
|
||||
import pass2Shader from "./sketch-pass2.frag.glsl";
|
||||
|
||||
|
|
@ -19,13 +20,13 @@ export const sketchEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader: pass1Shader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_lineWidth: effectParams.lineWidth as number,
|
||||
u_lineWidth: getNumberParam(effectParams, "lineWidth", 1),
|
||||
}),
|
||||
},
|
||||
{
|
||||
fragmentShader: pass2Shader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_threshold: (effectParams.threshold as number) / 100,
|
||||
u_threshold: getNumberParam(effectParams, "threshold") / 100,
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import pass1Shader from "./skin-smooth-pass1.frag.glsl";
|
||||
import pass2Shader from "./skin-smooth-pass2.frag.glsl";
|
||||
|
||||
|
|
@ -18,7 +19,7 @@ export const skinSmoothEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader: pass1Shader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_intensity: ((effectParams.intensity as number) / 100) * 3,
|
||||
u_intensity: (getNumberParam(effectParams, "intensity") / 100) * 3,
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import fragmentShader from "./slim-face.frag.glsl";
|
||||
|
||||
/** Slim face — pinch warp along jawline for face slimming */
|
||||
|
|
@ -24,7 +25,7 @@ export const slimFaceEffectDefinition: EffectDefinition = {
|
|||
|
||||
return {
|
||||
// No-op when jaw landmarks are missing to avoid warping arbitrary content
|
||||
u_intensity: jawCenter ? (effectParams.intensity as number) / 100 : 0,
|
||||
u_intensity: jawCenter ? getNumberParam(effectParams, "intensity") / 100 : 0,
|
||||
u_jawCenter: jawCenter ?? [0.5, 0.6],
|
||||
};
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import fragmentShader from "./teeth-whiten.frag.glsl";
|
||||
|
||||
/** Teeth whiten — desaturate + brighten, ideally masked to mouth region */
|
||||
|
|
@ -17,7 +18,7 @@ export const teethWhitenEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_intensity: (effectParams.intensity as number) / 200,
|
||||
u_intensity: getNumberParam(effectParams, "intensity") / 200,
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import fragmentShader from "./temperature.frag.glsl";
|
||||
|
||||
export const temperatureEffectDefinition: EffectDefinition = {
|
||||
|
|
@ -24,7 +25,7 @@ export const temperatureEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_temperature: (effectParams.warmth as number) / 400,
|
||||
u_temperature: getNumberParam(effectParams, "warmth") / 400,
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { EffectDefinition } from "../../types";
|
||||
import { EffectCategory } from "../../categories";
|
||||
import { getNumberParam } from "../../utils/params";
|
||||
import fragmentShader from "./vignette.frag.glsl";
|
||||
|
||||
export const vignetteEffectDefinition: EffectDefinition = {
|
||||
|
|
@ -18,9 +19,9 @@ export const vignetteEffectDefinition: EffectDefinition = {
|
|||
{
|
||||
fragmentShader,
|
||||
uniforms: ({ effectParams }) => ({
|
||||
u_intensity: (effectParams.intensity as number) / 100,
|
||||
u_radius: (effectParams.radius as number) / 100 * 0.707,
|
||||
u_softness: (effectParams.softness as number) / 100 * 0.5,
|
||||
u_intensity: getNumberParam(effectParams, "intensity") / 100,
|
||||
u_radius: getNumberParam(effectParams, "radius") / 100 * 0.707,
|
||||
u_softness: getNumberParam(effectParams, "softness") / 100 * 0.5,
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
import type { EffectParamValues } from "../types";
|
||||
|
||||
/**
|
||||
* Type-safe parameter getters for effect uniforms.
|
||||
* These eliminate the need for `as number` / `as string` casts throughout effect definitions.
|
||||
*/
|
||||
|
||||
/** Get a number parameter with fallback default */
|
||||
export function getNumberParam(
|
||||
params: EffectParamValues,
|
||||
key: string,
|
||||
defaultValue = 0,
|
||||
): number {
|
||||
const value = params[key];
|
||||
if (typeof value === "number") {
|
||||
return value;
|
||||
}
|
||||
if (typeof value === "string") {
|
||||
const parsed = Number.parseFloat(value);
|
||||
return Number.isFinite(parsed) ? parsed : defaultValue;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/** Get a string parameter with fallback default */
|
||||
export function getStringParam(
|
||||
params: EffectParamValues,
|
||||
key: string,
|
||||
defaultValue = "",
|
||||
): string {
|
||||
const value = params[key];
|
||||
if (typeof value === "string") {
|
||||
return value;
|
||||
}
|
||||
if (typeof value === "number" || typeof value === "boolean") {
|
||||
return String(value);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/** Get a boolean parameter with fallback default */
|
||||
export function getBooleanParam(
|
||||
params: EffectParamValues,
|
||||
key: string,
|
||||
defaultValue = false,
|
||||
): boolean {
|
||||
const value = params[key];
|
||||
if (typeof value === "boolean") {
|
||||
return value;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
Loading…
Reference in New Issue