85 lines
2.4 KiB
JavaScript
85 lines
2.4 KiB
JavaScript
import { ButtonEffect } from '../effect-base.js';
|
|
|
|
/**
|
|
* RGB Split / Chromatic Aberration effect
|
|
* Separates color channels for a glitchy chromatic aberration look
|
|
*/
|
|
export class RgbSplitEffect extends ButtonEffect {
|
|
constructor() {
|
|
super({
|
|
id: 'rgb-split',
|
|
name: 'RGB Split',
|
|
type: 'general',
|
|
category: 'Visual Effects',
|
|
renderOrder: 85
|
|
});
|
|
}
|
|
|
|
defineControls() {
|
|
return [
|
|
{
|
|
id: 'animate-rgb-split',
|
|
type: 'checkbox',
|
|
label: 'RGB Split',
|
|
defaultValue: false,
|
|
description: 'Chromatic aberration effect'
|
|
},
|
|
{
|
|
id: 'rgb-split-intensity',
|
|
type: 'range',
|
|
label: 'Split Intensity',
|
|
defaultValue: 2,
|
|
min: 1,
|
|
max: 10,
|
|
step: 0.5,
|
|
showWhen: 'animate-rgb-split',
|
|
description: 'Pixel offset for color channels'
|
|
}
|
|
];
|
|
}
|
|
|
|
isEnabled(controlValues) {
|
|
return controlValues['animate-rgb-split'] === true;
|
|
}
|
|
|
|
apply(context, controlValues, animState, renderData) {
|
|
if (!animState) return;
|
|
|
|
const intensity = controlValues['rgb-split-intensity'] || 2;
|
|
const imageData = context.getImageData(0, 0, renderData.width, renderData.height);
|
|
const result = context.createImageData(renderData.width, renderData.height);
|
|
|
|
// Oscillating offset
|
|
const phase = Math.sin(animState.getPhase(1.0));
|
|
const offsetX = Math.round(phase * intensity);
|
|
|
|
for (let y = 0; y < renderData.height; y++) {
|
|
for (let x = 0; x < renderData.width; x++) {
|
|
const idx = (y * renderData.width + x) * 4;
|
|
|
|
// Red channel - shift left
|
|
const redX = Math.max(0, Math.min(renderData.width - 1, x - offsetX));
|
|
const redIdx = (y * renderData.width + redX) * 4;
|
|
result.data[idx] = imageData.data[redIdx];
|
|
|
|
// Green channel - no shift
|
|
result.data[idx + 1] = imageData.data[idx + 1];
|
|
|
|
// Blue channel - shift right
|
|
const blueX = Math.max(0, Math.min(renderData.width - 1, x + offsetX));
|
|
const blueIdx = (y * renderData.width + blueX) * 4;
|
|
result.data[idx + 2] = imageData.data[blueIdx + 2];
|
|
|
|
// Alpha channel
|
|
result.data[idx + 3] = imageData.data[idx + 3];
|
|
}
|
|
}
|
|
|
|
context.putImageData(result, 0, 0);
|
|
}
|
|
}
|
|
|
|
// Auto-register effect
|
|
export function register(generator) {
|
|
generator.registerEffect(new RgbSplitEffect());
|
|
}
|