ghostyles/uv-stripes.jsjavascript
/**
* ==Ghostyle==
* @name UV Stripes
* @version 0.3.0
* @author edne
* @release_date 2026-05-04
* @description Strisce/chevron oblique disegnate sul volto in spazio UV canonico.
* ==/Ghostyle==
*/
export const params = [
{ name: 'angle', type: 'range', label: 'Angolo (rad)', min: 0, max: Math.PI, step: 0.01, default: 0.37 },
{ name: 'width', type: 'range', label: 'Larghezza (UV%)', min: 3, max: 60, step: 0.5, default: 21 },
{ name: 'nColors', type: 'range', label: 'N° colori', min: 2, max: 4, step: 1, default: 3 },
{ name: 'alpha', type: 'range', label: 'Opacità', min: 0, max: 1, step: 0.01, default: 0.4 },
{ name: 'gap', type: 'bool', label: 'Gap trasparente', default: true },
{ name: 'mode', type: 'select', label: 'Modalità', options: ['stripe', 'chevron'], default: 'chevron' },
{ name: 'color1', type: 'color', label: 'Colore 1', default: '#ffffff' },
{ name: 'color2', type: 'color', label: 'Colore 2', default: '#0000dc' },
{ name: 'color3', type: 'color', label: 'Colore 3', default: '#00ffff' },
{ name: 'color4', type: 'color', label: 'Colore 4', default: '#ffdc3c' }
];
export const region = {
include: 'skin'
};
function sampleStripe(u, v, params, palette) {
const period = Math.max(0.005, params.width / 100);
const cu = u - 0.5;
const cv = v - 0.5;
const projU = params.mode === 'chevron' ? Math.abs(cu) : cu;
const proj = projU * Math.cos(params.angle) + cv * Math.sin(params.angle);
let phase = (proj / period) % 1;
if (phase < 0) phase += 1;
const total = params.gap ? params.nColors + 1 : params.nColors;
const idx = Math.floor(phase * total);
if (params.gap && idx === params.nColors) return null;
return palette[idx % params.nColors];
}
export function paintUV(ctx, params) {
const w = ctx.canvas.width;
const h = ctx.canvas.height;
const palette = [params.color1, params.color2, params.color3, params.color4];
const aByte = Math.round(params.alpha * 255);
const img = ctx.createImageData(w, h);
const data = img.data;
for (let py = 0; py < h; py++) {
const v = (py + 0.5) / h;
for (let px = 0; px < w; px++) {
const u = (px + 0.5) / w;
const col = sampleStripe(u, v, params, palette);
const idx = (py * w + px) * 4;
if (col) {
data[idx] = col[0];
data[idx + 1] = col[1];
data[idx + 2] = col[2];
data[idx + 3] = aByte;
} else {
data[idx + 3] = 0;
}
}
}
ctx.putImageData(img, 0, 0);
}