new features

This commit is contained in:
2025-07-05 00:55:57 +00:00
parent 083abb53d4
commit 9090ea4c10
5 changed files with 242 additions and 10 deletions

View File

@ -6,6 +6,7 @@ interface WorkerMessage {
width?: number;
height?: number;
time?: number;
renderMode?: string;
}
interface WorkerResponse {
@ -33,7 +34,7 @@ class ShaderWorker {
this.compileShader(message.id, message.code!);
break;
case 'render':
this.renderShader(message.id, message.width!, message.height!, message.time!);
this.renderShader(message.id, message.width!, message.height!, message.time!, message.renderMode || 'classic');
break;
}
} catch (error) {
@ -75,7 +76,7 @@ class ShaderWorker {
}
}
private renderShader(id: string, width: number, height: number, time: number): void {
private renderShader(id: string, width: number, height: number, time: number, renderMode: string): void {
if (!this.compiledFunction) {
this.postError(id, 'No compiled shader');
return;
@ -110,12 +111,12 @@ class ShaderWorker {
try {
const value = this.compiledFunction(x, y, time, pixelIndex);
const safeValue = isFinite(value) ? value : 0;
const color = Math.abs(safeValue) % 256;
const [r, g, b] = this.calculateColor(safeValue, renderMode);
data[i] = color; // R
data[i + 1] = (color * 2) % 256; // G
data[i + 2] = (color * 3) % 256; // B
data[i + 3] = 255; // A
data[i] = r; // R
data[i + 1] = g; // G
data[i + 2] = b; // B
data[i + 3] = 255; // A
} catch (error) {
data[i] = 0; // R
data[i + 1] = 0; // G
@ -131,6 +132,93 @@ class ShaderWorker {
}
}
private calculateColor(value: number, renderMode: string): [number, number, number] {
const absValue = Math.abs(value) % 256;
switch (renderMode) {
case 'classic':
return [
absValue,
(absValue * 2) % 256,
(absValue * 3) % 256
];
case 'grayscale':
return [absValue, absValue, absValue];
case 'red':
return [absValue, 0, 0];
case 'green':
return [0, absValue, 0];
case 'blue':
return [0, 0, absValue];
case 'rgb':
return [
(absValue * 255 / 256) | 0,
((absValue * 2) % 256 * 255 / 256) | 0,
((absValue * 3) % 256 * 255 / 256) | 0
];
case 'hsv':
return this.hsvToRgb(absValue / 255.0, 1.0, 1.0);
case 'rainbow':
return this.rainbowColor(absValue);
default:
return [absValue, absValue, absValue];
}
}
private hsvToRgb(h: number, s: number, v: number): [number, number, number] {
const c = v * s;
const x = c * (1 - Math.abs((h * 6) % 2 - 1));
const m = v - c;
let r = 0, g = 0, b = 0;
if (h < 1/6) {
r = c; g = x; b = 0;
} else if (h < 2/6) {
r = x; g = c; b = 0;
} else if (h < 3/6) {
r = 0; g = c; b = x;
} else if (h < 4/6) {
r = 0; g = x; b = c;
} else if (h < 5/6) {
r = x; g = 0; b = c;
} else {
r = c; g = 0; b = x;
}
return [
Math.round((r + m) * 255),
Math.round((g + m) * 255),
Math.round((b + m) * 255)
];
}
private rainbowColor(value: number): [number, number, number] {
const phase = (value / 255.0) * 6;
const segment = Math.floor(phase);
const remainder = phase - segment;
const t = remainder;
const q = 1 - t;
switch (segment % 6) {
case 0: return [255, Math.round(t * 255), 0];
case 1: return [Math.round(q * 255), 255, 0];
case 2: return [0, 255, Math.round(t * 255)];
case 3: return [0, Math.round(q * 255), 255];
case 4: return [Math.round(t * 255), 0, 255];
case 5: return [255, 0, Math.round(q * 255)];
default: return [255, 255, 255];
}
}
private sanitizeCode(code: string): string {
// Strict whitelist approach
const allowedPattern = /^[0-9a-zA-Z\s\+\-\*\/\%\^\&\|\(\)\<\>\~\?:,\.xyti]+$/;