small size update with tons of rendering modes, palettes and keybindings

This commit is contained in:
2025-07-07 21:40:19 +02:00
parent 6d5aa9f0f5
commit fb2d5c1b4c
12 changed files with 737 additions and 91 deletions

View File

@ -9,7 +9,7 @@ import { WelcomePopup } from './WelcomePopup';
import { ShaderCanvas } from './ShaderCanvas';
import { PerformanceWarning } from './PerformanceWarning';
import { uiState, showUI } from '../stores/ui';
import { $appSettings } from '../stores/appSettings';
import { $appSettings, updateAppSettings, cycleValueMode, cycleRenderMode, handleTapTempo } from '../stores/appSettings';
import { $shader } from '../stores/shader';
import { loadShaders } from '../stores/library';
import { Storage } from '../Storage';
@ -43,6 +43,82 @@ export function App() {
);
}, [settings.uiOpacity]);
// Keyboard controls for hue shift and value mode when editor not focused
useEffect(() => {
let lastKeyTime = 0;
const DEBOUNCE_DELAY = 150; // ms between key presses
const handleKeyDown = (e: KeyboardEvent) => {
// Only activate if editor is not focused and no control/meta/alt keys are pressed
const editorElement = document.getElementById('editor') as HTMLTextAreaElement;
const isEditorFocused = editorElement && document.activeElement === editorElement;
if (isEditorFocused || e.ctrlKey || e.metaKey || e.altKey) {
return;
}
// Debounce rapid key repeats
const now = Date.now();
if (now - lastKeyTime < DEBOUNCE_DELAY) {
e.preventDefault();
return;
}
lastKeyTime = now;
switch (e.key) {
case 'ArrowLeft':
e.preventDefault();
// Decrease hue shift by 10 degrees (wrapping at 0)
const currentHue = settings.hueShift ?? 0;
const newHueLeft = currentHue - 10;
updateAppSettings({ hueShift: newHueLeft < 0 ? 360 + newHueLeft : newHueLeft });
break;
case 'ArrowRight':
e.preventDefault();
// Increase hue shift by 10 degrees (wrapping at 360)
const currentHueRight = settings.hueShift ?? 0;
const newHueRight = (currentHueRight + 10) % 360;
updateAppSettings({ hueShift: newHueRight });
break;
case 'ArrowUp':
e.preventDefault();
if (e.shiftKey) {
// Shift + Up: Cycle to previous render mode (color palette)
cycleRenderMode('backward');
} else {
// Up: Cycle to previous value mode
cycleValueMode('backward');
}
break;
case 'ArrowDown':
e.preventDefault();
if (e.shiftKey) {
// Shift + Down: Cycle to next render mode (color palette)
cycleRenderMode('forward');
} else {
// Down: Cycle to next value mode
cycleValueMode('forward');
}
break;
case ' ':
e.preventDefault();
// Spacebar: Tap tempo to control time speed
handleTapTempo();
break;
}
};
document.addEventListener('keydown', handleKeyDown);
return () => {
document.removeEventListener('keydown', handleKeyDown);
};
}, [settings.hueShift]);
// Save settings changes to localStorage
useEffect(() => {
Storage.saveSettings({
@ -51,6 +127,8 @@ export function App() {
renderMode: settings.renderMode,
valueMode: settings.valueMode,
uiOpacity: settings.uiOpacity,
hueShift: settings.hueShift,
timeSpeed: settings.timeSpeed,
lastShaderCode: shader.code,
});
}, [settings, shader.code]);