Files
Pien-Studio/apps/web/lib/effects/registry.ts
T
2026-05-24 21:05:21 +07:00

47 lines
1.5 KiB
TypeScript

import type { LayerEffect } from "@pien-studio/types";
import type { EffectRenderer, EffectRenderContext } from "./types";
import { faceBlurRenderer } from "./face-blur";
const renderers: EffectRenderer[] = [faceBlurRenderer];
const effectRendererRegistry = new Map<string, EffectRenderer>(
renderers.map((r) => [r.kind, r]),
);
export function getEffectRenderer(kind: string): EffectRenderer | undefined {
return effectRendererRegistry.get(kind);
}
/** Draws a layer image applying all its effects in order. */
export function renderLayerWithEffects(
ctx: CanvasRenderingContext2D,
image: HTMLImageElement,
effects: LayerEffect[],
targetWidth: number,
targetHeight: number,
): void {
const activeEffects = effects.filter((e) => {
if (e.enabled === false) return false;
return effectRendererRegistry.get(e.kind) !== undefined;
});
if (activeEffects.length === 0) {
ctx.drawImage(image, 0, 0, targetWidth, targetHeight);
return;
}
const context: EffectRenderContext = { ctx, image, targetWidth, targetHeight };
// The first effect owns the full layer render (draws base image + applies itself)
const first = activeEffects[0];
const firstRenderer = effectRendererRegistry.get(first.kind);
firstRenderer?.renderLayer(context, first);
// Subsequent effects render on top (overlay only, no re-draw of base)
for (let i = 1; i < activeEffects.length; i++) {
const effect = activeEffects[i];
const renderer = effectRendererRegistry.get(effect.kind);
renderer?.render(context, effect);
}
}