switching
This commit is contained in:
72
src/utils/LRUCache.ts
Normal file
72
src/utils/LRUCache.ts
Normal file
@ -0,0 +1,72 @@
|
||||
export class LRUCache<K, V> {
|
||||
private maxSize: number;
|
||||
private cache: Map<K, V>;
|
||||
private accessOrder: K[];
|
||||
|
||||
constructor(maxSize: number) {
|
||||
this.maxSize = maxSize;
|
||||
this.cache = new Map();
|
||||
this.accessOrder = [];
|
||||
}
|
||||
|
||||
get(key: K): V | undefined {
|
||||
const value = this.cache.get(key);
|
||||
if (value !== undefined) {
|
||||
this.markAsUsed(key);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
set(key: K, value: V): void {
|
||||
if (this.cache.has(key)) {
|
||||
this.cache.set(key, value);
|
||||
this.markAsUsed(key);
|
||||
} else {
|
||||
if (this.cache.size >= this.maxSize) {
|
||||
this.evictLeastUsed();
|
||||
}
|
||||
this.cache.set(key, value);
|
||||
this.accessOrder.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
has(key: K): boolean {
|
||||
return this.cache.has(key);
|
||||
}
|
||||
|
||||
delete(key: K): boolean {
|
||||
if (this.cache.delete(key)) {
|
||||
this.removeFromAccessOrder(key);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.cache.clear();
|
||||
this.accessOrder = [];
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
return this.cache.size;
|
||||
}
|
||||
|
||||
private markAsUsed(key: K): void {
|
||||
this.removeFromAccessOrder(key);
|
||||
this.accessOrder.push(key);
|
||||
}
|
||||
|
||||
private removeFromAccessOrder(key: K): void {
|
||||
const index = this.accessOrder.indexOf(key);
|
||||
if (index > -1) {
|
||||
this.accessOrder.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private evictLeastUsed(): void {
|
||||
if (this.accessOrder.length > 0) {
|
||||
const leastUsed = this.accessOrder.shift()!;
|
||||
this.cache.delete(leastUsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
205
src/utils/colorModes.ts
Normal file
205
src/utils/colorModes.ts
Normal file
@ -0,0 +1,205 @@
|
||||
export function 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),
|
||||
];
|
||||
}
|
||||
|
||||
export function 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];
|
||||
}
|
||||
}
|
||||
|
||||
export function thermalColor(value: number): [number, number, number] {
|
||||
const t = value / 255.0;
|
||||
if (t < 0.25) {
|
||||
return [0, 0, Math.round(t * 4 * 255)];
|
||||
} else if (t < 0.5) {
|
||||
return [0, Math.round((t - 0.25) * 4 * 255), 255];
|
||||
} else if (t < 0.75) {
|
||||
return [
|
||||
Math.round((t - 0.5) * 4 * 255),
|
||||
255,
|
||||
Math.round((0.75 - t) * 4 * 255),
|
||||
];
|
||||
} else {
|
||||
return [255, 255, Math.round((t - 0.75) * 4 * 255)];
|
||||
}
|
||||
}
|
||||
|
||||
export function neonColor(value: number): [number, number, number] {
|
||||
const t = value / 255.0;
|
||||
const intensity = Math.pow(Math.sin(t * Math.PI), 2);
|
||||
const glow = Math.pow(intensity, 0.5);
|
||||
return [
|
||||
Math.round(glow * 255),
|
||||
Math.round(intensity * 255),
|
||||
Math.round(Math.pow(intensity, 2) * 255),
|
||||
];
|
||||
}
|
||||
|
||||
export function cyberpunkColor(value: number): [number, number, number] {
|
||||
const t = value / 255.0;
|
||||
const phase = (t * 3) % 1;
|
||||
if (phase < 0.33) {
|
||||
return [
|
||||
Math.round(255 * (1 - phase * 3)),
|
||||
0,
|
||||
Math.round(255 * phase * 3),
|
||||
];
|
||||
} else if (phase < 0.67) {
|
||||
const p = (phase - 0.33) * 3;
|
||||
return [0, Math.round(255 * p), Math.round(255 * (1 - p))];
|
||||
} else {
|
||||
const p = (phase - 0.67) * 3;
|
||||
return [Math.round(255 * p), Math.round(255 * (1 - p)), 255];
|
||||
}
|
||||
}
|
||||
|
||||
export function vaporwaveColor(value: number): [number, number, number] {
|
||||
const t = value / 255.0;
|
||||
const pink = Math.sin(t * Math.PI);
|
||||
const purple = Math.sin(t * Math.PI * 0.7 + Math.PI / 3);
|
||||
const blue = Math.sin(t * Math.PI * 0.5 + Math.PI / 2);
|
||||
return [
|
||||
Math.round(255 * (0.8 + 0.2 * pink)),
|
||||
Math.round(255 * (0.3 + 0.7 * purple)),
|
||||
Math.round(255 * (0.6 + 0.4 * blue)),
|
||||
];
|
||||
}
|
||||
|
||||
export function ditheredColor(value: number): [number, number, number] {
|
||||
const levels = 4;
|
||||
const step = 255 / (levels - 1);
|
||||
const quantized = Math.round(value / step) * step;
|
||||
const error = value - quantized;
|
||||
const dither = (Math.random() - 0.5) * 32;
|
||||
const final = Math.max(0, Math.min(255, quantized + error + dither));
|
||||
return [final, final, final];
|
||||
}
|
||||
|
||||
export function paletteColor(value: number): [number, number, number] {
|
||||
const palette = [
|
||||
[0, 0, 0],
|
||||
[87, 29, 149],
|
||||
[191, 82, 177],
|
||||
[249, 162, 162],
|
||||
[255, 241, 165],
|
||||
[134, 227, 206],
|
||||
[29, 161, 242],
|
||||
[255, 255, 255],
|
||||
];
|
||||
const index = Math.floor((value / 255.0) * (palette.length - 1));
|
||||
return palette[index] as [number, number, number];
|
||||
}
|
||||
|
||||
export function calculateColorDirect(
|
||||
absValue: number,
|
||||
renderMode: string
|
||||
): [number, number, number] {
|
||||
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 hsvToRgb(absValue / 255.0, 1.0, 1.0);
|
||||
|
||||
case 'rainbow':
|
||||
return rainbowColor(absValue);
|
||||
|
||||
case 'thermal':
|
||||
return thermalColor(absValue);
|
||||
|
||||
case 'neon':
|
||||
return neonColor(absValue);
|
||||
|
||||
case 'cyberpunk':
|
||||
return cyberpunkColor(absValue);
|
||||
|
||||
case 'vaporwave':
|
||||
return vaporwaveColor(absValue);
|
||||
|
||||
case 'dithered':
|
||||
return ditheredColor(absValue);
|
||||
|
||||
case 'palette':
|
||||
return paletteColor(absValue);
|
||||
|
||||
default:
|
||||
return [absValue, absValue, absValue];
|
||||
}
|
||||
}
|
||||
52
src/utils/constants.ts
Normal file
52
src/utils/constants.ts
Normal file
@ -0,0 +1,52 @@
|
||||
// UI Layout Constants
|
||||
export const UI_HEIGHTS = {
|
||||
TOP_BAR: 40,
|
||||
EDITOR_PANEL: 140,
|
||||
TOTAL_UI_HEIGHT: 180, // TOP_BAR + EDITOR_PANEL
|
||||
} as const;
|
||||
|
||||
// Performance Constants
|
||||
export const PERFORMANCE = {
|
||||
DEFAULT_TILE_SIZE: 64,
|
||||
MAX_RENDER_TIME_MS: 50,
|
||||
MAX_SHADER_TIMEOUT_MS: 5,
|
||||
TIMEOUT_CHECK_INTERVAL: 1000,
|
||||
MAX_SAVED_SHADERS: 50,
|
||||
IMAGE_DATA_CACHE_SIZE: 5,
|
||||
COMPILATION_CACHE_SIZE: 20,
|
||||
} as const;
|
||||
|
||||
// Color Constants
|
||||
export const COLOR_TABLE_SIZE = 256;
|
||||
|
||||
// Storage Keys
|
||||
export const STORAGE_KEYS = {
|
||||
SHADERS: 'bitfielder_shaders',
|
||||
SETTINGS: 'bitfielder_settings',
|
||||
} as const;
|
||||
|
||||
// Value Modes
|
||||
export const VALUE_MODES = [
|
||||
'integer',
|
||||
'float',
|
||||
'polar',
|
||||
'distance',
|
||||
'wave',
|
||||
'fractal',
|
||||
'cellular',
|
||||
'noise',
|
||||
'warp',
|
||||
'flow'
|
||||
] as const;
|
||||
|
||||
export type ValueMode = typeof VALUE_MODES[number];
|
||||
|
||||
// Default Values
|
||||
export const DEFAULTS = {
|
||||
RESOLUTION: 1,
|
||||
FPS: 30,
|
||||
RENDER_MODE: 'classic',
|
||||
VALUE_MODE: 'integer' as ValueMode,
|
||||
UI_OPACITY: 0.3,
|
||||
SHADER_CODE: 'x^y',
|
||||
} as const;
|
||||
Reference in New Issue
Block a user