From 4f74ec90570083b73b81f175a01ee6aaa85846f3 Mon Sep 17 00:00:00 2001 From: anh doan Date: Mon, 23 Mar 2026 16:41:42 +0700 Subject: [PATCH] chore: add util for get effectParams --- .../services/face-mesh/face-mesh-provider.ts | 5 +- packages/effects/src/effects/blush/index.ts | 5 +- .../effects/src/effects/brightness/index.ts | 3 +- .../src/effects/chromatic-aberration/index.ts | 5 +- .../src/effects/color-balance/index.ts | 19 +++---- .../effects/src/effects/contrast/index.ts | 3 +- .../effects/src/effects/exposure/index.ts | 3 +- .../effects/src/effects/eye-enhance/index.ts | 5 +- .../src/effects/face-brighten/index.ts | 3 +- .../effects/src/effects/film-grain/index.ts | 7 +-- packages/effects/src/effects/gamma/index.ts | 3 +- packages/effects/src/effects/glitch/index.ts | 11 ++-- .../effects/src/effects/hue-shift/index.ts | 3 +- .../effects/src/effects/neon-glow/index.ts | 7 +-- .../effects/src/effects/oil-paint/index.ts | 5 +- .../effects/src/effects/pixelate/index.ts | 3 +- .../effects/src/effects/saturation/index.ts | 3 +- packages/effects/src/effects/sharpen/index.ts | 3 +- packages/effects/src/effects/sketch/index.ts | 5 +- .../effects/src/effects/skin-smooth/index.ts | 3 +- .../effects/src/effects/slim-face/index.ts | 3 +- .../effects/src/effects/teeth-whiten/index.ts | 3 +- .../effects/src/effects/temperature/index.ts | 3 +- .../effects/src/effects/vignette/index.ts | 7 +-- packages/effects/src/utils/params.ts | 52 +++++++++++++++++++ 25 files changed, 125 insertions(+), 47 deletions(-) create mode 100644 packages/effects/src/utils/params.ts diff --git a/apps/web/src/services/face-mesh/face-mesh-provider.ts b/apps/web/src/services/face-mesh/face-mesh-provider.ts index d8b56e31..8e7dd8a6 100644 --- a/apps/web/src/services/face-mesh/face-mesh-provider.ts +++ b/apps/web/src/services/face-mesh/face-mesh-provider.ts @@ -19,6 +19,9 @@ let pendingTimeoutId: ReturnType | 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 { 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, diff --git a/packages/effects/src/effects/blush/index.ts b/packages/effects/src/effects/blush/index.ts index fd1bfecd..3dcec30a 100644 --- a/packages/effects/src/effects/blush/index.ts +++ b/packages/effects/src/effects/blush/index.ts @@ -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, diff --git a/packages/effects/src/effects/brightness/index.ts b/packages/effects/src/effects/brightness/index.ts index 4a31c68b..5f8f56be 100644 --- a/packages/effects/src/effects/brightness/index.ts +++ b/packages/effects/src/effects/brightness/index.ts @@ -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, }), }, ], diff --git a/packages/effects/src/effects/chromatic-aberration/index.ts b/packages/effects/src/effects/chromatic-aberration/index.ts index 17a5e49e..24b66947 100644 --- a/packages/effects/src/effects/chromatic-aberration/index.ts +++ b/packages/effects/src/effects/chromatic-aberration/index.ts @@ -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, }), }, ], diff --git a/packages/effects/src/effects/color-balance/index.ts b/packages/effects/src/effects/color-balance/index.ts index 20f1e9d8..b58df709 100644 --- a/packages/effects/src/effects/color-balance/index.ts +++ b/packages/effects/src/effects/color-balance/index.ts @@ -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, ], }), }, diff --git a/packages/effects/src/effects/contrast/index.ts b/packages/effects/src/effects/contrast/index.ts index d0deca2a..79492829 100644 --- a/packages/effects/src/effects/contrast/index.ts +++ b/packages/effects/src/effects/contrast/index.ts @@ -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, }), }, ], diff --git a/packages/effects/src/effects/exposure/index.ts b/packages/effects/src/effects/exposure/index.ts index c5dfc27b..a76ae1b5 100644 --- a/packages/effects/src/effects/exposure/index.ts +++ b/packages/effects/src/effects/exposure/index.ts @@ -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"), }), }, ], diff --git a/packages/effects/src/effects/eye-enhance/index.ts b/packages/effects/src/effects/eye-enhance/index.ts index cd4b89c0..5d64527b 100644 --- a/packages/effects/src/effects/eye-enhance/index.ts +++ b/packages/effects/src/effects/eye-enhance/index.ts @@ -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, }), }, ], diff --git a/packages/effects/src/effects/face-brighten/index.ts b/packages/effects/src/effects/face-brighten/index.ts index b773508a..935db5da 100644 --- a/packages/effects/src/effects/face-brighten/index.ts +++ b/packages/effects/src/effects/face-brighten/index.ts @@ -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, }), }, ], diff --git a/packages/effects/src/effects/film-grain/index.ts b/packages/effects/src/effects/film-grain/index.ts index f1675fbe..d452c536 100644 --- a/packages/effects/src/effects/film-grain/index.ts +++ b/packages/effects/src/effects/film-grain/index.ts @@ -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, }), }, ], diff --git a/packages/effects/src/effects/gamma/index.ts b/packages/effects/src/effects/gamma/index.ts index 80c6db85..1ddbd03a 100644 --- a/packages/effects/src/effects/gamma/index.ts +++ b/packages/effects/src/effects/gamma/index.ts @@ -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), }), }, ], diff --git a/packages/effects/src/effects/glitch/index.ts b/packages/effects/src/effects/glitch/index.ts index bdea6486..78c66e79 100644 --- a/packages/effects/src/effects/glitch/index.ts +++ b/packages/effects/src/effects/glitch/index.ts @@ -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), }), }, ], diff --git a/packages/effects/src/effects/hue-shift/index.ts b/packages/effects/src/effects/hue-shift/index.ts index e2f95603..2329b3e0 100644 --- a/packages/effects/src/effects/hue-shift/index.ts +++ b/packages/effects/src/effects/hue-shift/index.ts @@ -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, }), }, ], diff --git a/packages/effects/src/effects/neon-glow/index.ts b/packages/effects/src/effects/neon-glow/index.ts index e9113ad5..6543094d 100644 --- a/packages/effects/src/effects/neon-glow/index.ts +++ b/packages/effects/src/effects/neon-glow/index.ts @@ -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")), }), }, ], diff --git a/packages/effects/src/effects/oil-paint/index.ts b/packages/effects/src/effects/oil-paint/index.ts index c8f06914..6fdf72b0 100644 --- a/packages/effects/src/effects/oil-paint/index.ts +++ b/packages/effects/src/effects/oil-paint/index.ts @@ -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), }), }, ], diff --git a/packages/effects/src/effects/pixelate/index.ts b/packages/effects/src/effects/pixelate/index.ts index 557dbf8d..374750d0 100644 --- a/packages/effects/src/effects/pixelate/index.ts +++ b/packages/effects/src/effects/pixelate/index.ts @@ -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), }), }, ], diff --git a/packages/effects/src/effects/saturation/index.ts b/packages/effects/src/effects/saturation/index.ts index 6dd9e656..b939b041 100644 --- a/packages/effects/src/effects/saturation/index.ts +++ b/packages/effects/src/effects/saturation/index.ts @@ -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, }), }, ], diff --git a/packages/effects/src/effects/sharpen/index.ts b/packages/effects/src/effects/sharpen/index.ts index 394c5cc7..f0a9be24 100644 --- a/packages/effects/src/effects/sharpen/index.ts +++ b/packages/effects/src/effects/sharpen/index.ts @@ -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, }), }, ], diff --git a/packages/effects/src/effects/sketch/index.ts b/packages/effects/src/effects/sketch/index.ts index 575df940..eca059a1 100644 --- a/packages/effects/src/effects/sketch/index.ts +++ b/packages/effects/src/effects/sketch/index.ts @@ -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, }), }, ], diff --git a/packages/effects/src/effects/skin-smooth/index.ts b/packages/effects/src/effects/skin-smooth/index.ts index 9ad2410b..10ab6b0d 100644 --- a/packages/effects/src/effects/skin-smooth/index.ts +++ b/packages/effects/src/effects/skin-smooth/index.ts @@ -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, }), }, { diff --git a/packages/effects/src/effects/slim-face/index.ts b/packages/effects/src/effects/slim-face/index.ts index 15bf7139..aff7f7e1 100644 --- a/packages/effects/src/effects/slim-face/index.ts +++ b/packages/effects/src/effects/slim-face/index.ts @@ -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], }; }, diff --git a/packages/effects/src/effects/teeth-whiten/index.ts b/packages/effects/src/effects/teeth-whiten/index.ts index c4a0d6bf..c036144b 100644 --- a/packages/effects/src/effects/teeth-whiten/index.ts +++ b/packages/effects/src/effects/teeth-whiten/index.ts @@ -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, }), }, ], diff --git a/packages/effects/src/effects/temperature/index.ts b/packages/effects/src/effects/temperature/index.ts index e1aefa04..4a45c23e 100644 --- a/packages/effects/src/effects/temperature/index.ts +++ b/packages/effects/src/effects/temperature/index.ts @@ -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, }), }, ], diff --git a/packages/effects/src/effects/vignette/index.ts b/packages/effects/src/effects/vignette/index.ts index e16438e6..96c514b3 100644 --- a/packages/effects/src/effects/vignette/index.ts +++ b/packages/effects/src/effects/vignette/index.ts @@ -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, }), }, ], diff --git a/packages/effects/src/utils/params.ts b/packages/effects/src/utils/params.ts new file mode 100644 index 00000000..621dffed --- /dev/null +++ b/packages/effects/src/utils/params.ts @@ -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; +}