ritual.sh/static/js/button-generator/effects/glitch.js

93 lines
2.3 KiB
JavaScript

import { ButtonEffect } from '../effect-base.js';
/**
* Glitch effect
* Creates horizontal scanline displacement for a glitchy look
*/
export class GlitchEffect extends ButtonEffect {
constructor() {
super({
id: 'glitch',
name: 'Glitch',
type: 'general',
category: 'Visual Effects',
renderOrder: 80
});
}
defineControls() {
return [
{
id: 'animate-glitch',
type: 'checkbox',
label: 'Glitch Effect',
defaultValue: false
},
{
id: 'glitch-intensity',
type: 'range',
label: 'Glitch Intensity',
defaultValue: 5,
min: 1,
max: 20,
step: 1,
showWhen: 'animate-glitch',
description: 'Maximum pixel offset for glitch'
}
];
}
isEnabled(controlValues) {
return controlValues['animate-glitch'] === true;
}
apply(context, controlValues, animState, renderData) {
if (!animState) return;
const intensity = controlValues['glitch-intensity'] || 5;
const imageData = context.getImageData(0, 0, renderData.width, renderData.height);
// Randomly glitch ~10% of scanlines per frame
const glitchProbability = 0.1;
const maxOffset = intensity;
for (let y = 0; y < renderData.height; y++) {
if (Math.random() < glitchProbability) {
const offset = Math.floor((Math.random() - 0.5) * maxOffset * 2);
this.shiftScanline(imageData, y, offset, renderData.width);
}
}
context.putImageData(imageData, 0, 0);
}
/**
* Shift a horizontal scanline by offset pixels (with wrapping)
*/
shiftScanline(imageData, y, offset, width) {
const rowStart = y * width * 4;
const rowData = new Uint8ClampedArray(width * 4);
// Copy row
for (let i = 0; i < width * 4; i++) {
rowData[i] = imageData.data[rowStart + i];
}
// Shift and wrap
for (let x = 0; x < width; x++) {
let sourceX = (x - offset + width) % width;
let destIdx = rowStart + x * 4;
let srcIdx = sourceX * 4;
imageData.data[destIdx] = rowData[srcIdx];
imageData.data[destIdx + 1] = rowData[srcIdx + 1];
imageData.data[destIdx + 2] = rowData[srcIdx + 2];
imageData.data[destIdx + 3] = rowData[srcIdx + 3];
}
}
}
// Auto-register effect
export function register(generator) {
generator.registerEffect(new GlitchEffect());
}