better eval mechanism and transparency
This commit is contained in:
@ -11,6 +11,7 @@ interface AppSettings {
|
||||
fps: number;
|
||||
lastShaderCode: string;
|
||||
renderMode: string;
|
||||
uiOpacity?: number;
|
||||
}
|
||||
|
||||
export class Storage {
|
||||
@ -97,7 +98,8 @@ export class Storage {
|
||||
resolution: 1,
|
||||
fps: 30,
|
||||
lastShaderCode: 'x^y',
|
||||
renderMode: 'classic'
|
||||
renderMode: 'classic',
|
||||
uiOpacity: 0.3
|
||||
};
|
||||
return stored ? { ...defaults, ...JSON.parse(stored) } : defaults;
|
||||
} catch (error) {
|
||||
@ -106,7 +108,8 @@ export class Storage {
|
||||
resolution: 1,
|
||||
fps: 30,
|
||||
lastShaderCode: 'x^y',
|
||||
renderMode: 'classic'
|
||||
renderMode: 'classic',
|
||||
uiOpacity: 0.3
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
32
src/main.ts
32
src/main.ts
@ -58,6 +58,9 @@ class BitfielderApp {
|
||||
const resolutionSelect = document.getElementById('resolution-select') as HTMLSelectElement;
|
||||
const fpsSelect = document.getElementById('fps-select') as HTMLSelectElement;
|
||||
const renderModeSelect = document.getElementById('render-mode-select') as HTMLSelectElement;
|
||||
const opacitySlider = document.getElementById('opacity-slider') as HTMLInputElement;
|
||||
const opacityValue = document.getElementById('opacity-value')!;
|
||||
const evalBtn = document.getElementById('eval-btn')!;
|
||||
const helpPopup = document.getElementById('help-popup')!;
|
||||
const closeBtn = helpPopup.querySelector('.close-btn')!;
|
||||
|
||||
@ -76,6 +79,8 @@ class BitfielderApp {
|
||||
resolutionSelect.addEventListener('change', () => this.updateResolution());
|
||||
fpsSelect.addEventListener('change', () => this.updateFPS());
|
||||
renderModeSelect.addEventListener('change', () => this.updateRenderMode());
|
||||
opacitySlider.addEventListener('input', () => this.updateUIOpacity());
|
||||
evalBtn.addEventListener('click', () => this.evalShader());
|
||||
closeBtn.addEventListener('click', () => this.hideHelp());
|
||||
|
||||
// Library events
|
||||
@ -175,6 +180,7 @@ class BitfielderApp {
|
||||
const topbar = document.getElementById('topbar')!;
|
||||
const editorPanel = document.getElementById('editor-panel')!;
|
||||
const editor = document.getElementById('editor')!;
|
||||
const evalBtn = document.getElementById('eval-btn')!;
|
||||
const showUiBtn = document.getElementById('show-ui-btn')!;
|
||||
|
||||
if (this.uiVisible) {
|
||||
@ -182,12 +188,14 @@ class BitfielderApp {
|
||||
topbar.classList.remove('hidden');
|
||||
editorPanel.classList.remove('minimal');
|
||||
editor.classList.remove('minimal');
|
||||
evalBtn.classList.remove('minimal');
|
||||
showUiBtn.style.display = 'none';
|
||||
} else {
|
||||
// Hide topbar, make editor minimal
|
||||
topbar.classList.add('hidden');
|
||||
editorPanel.classList.add('minimal');
|
||||
editor.classList.add('minimal');
|
||||
evalBtn.classList.add('minimal');
|
||||
showUiBtn.style.display = 'block';
|
||||
}
|
||||
|
||||
@ -200,11 +208,13 @@ class BitfielderApp {
|
||||
const topbar = document.getElementById('topbar')!;
|
||||
const editorPanel = document.getElementById('editor-panel')!;
|
||||
const editor = document.getElementById('editor')!;
|
||||
const evalBtn = document.getElementById('eval-btn')!;
|
||||
const showUiBtn = document.getElementById('show-ui-btn')!;
|
||||
|
||||
topbar.classList.remove('hidden');
|
||||
editorPanel.classList.remove('minimal');
|
||||
editor.classList.remove('minimal');
|
||||
evalBtn.classList.remove('minimal');
|
||||
showUiBtn.style.display = 'none';
|
||||
|
||||
// Recalculate canvas size when UI is shown
|
||||
@ -272,6 +282,22 @@ class BitfielderApp {
|
||||
Storage.saveSettings({ renderMode });
|
||||
}
|
||||
|
||||
private updateUIOpacity(): void {
|
||||
const opacitySlider = document.getElementById('opacity-slider') as HTMLInputElement;
|
||||
const opacityValue = document.getElementById('opacity-value')!;
|
||||
const opacity = parseInt(opacitySlider.value) / 100;
|
||||
|
||||
document.documentElement.style.setProperty('--ui-opacity', opacity.toString());
|
||||
opacityValue.textContent = `${opacitySlider.value}%`;
|
||||
|
||||
Storage.saveSettings({ uiOpacity: opacity });
|
||||
}
|
||||
|
||||
private evalShader(): void {
|
||||
this.shader.setCode(this.editor.value);
|
||||
this.render();
|
||||
}
|
||||
|
||||
private exportPNG(): void {
|
||||
const link = document.createElement('a');
|
||||
link.download = `bitfielder-${Date.now()}.png`;
|
||||
@ -289,6 +315,12 @@ class BitfielderApp {
|
||||
(document.getElementById('fps-select') as HTMLSelectElement).value = settings.fps.toString();
|
||||
(document.getElementById('render-mode-select') as HTMLSelectElement).value = settings.renderMode || 'classic';
|
||||
|
||||
// Apply UI opacity
|
||||
const opacity = settings.uiOpacity ?? 0.3;
|
||||
document.documentElement.style.setProperty('--ui-opacity', opacity.toString());
|
||||
(document.getElementById('opacity-slider') as HTMLInputElement).value = (opacity * 100).toString();
|
||||
document.getElementById('opacity-value')!.textContent = `${Math.round(opacity * 100)}%`;
|
||||
|
||||
// Load last shader code if no URL hash
|
||||
if (!window.location.hash) {
|
||||
this.editor.value = settings.lastShaderCode;
|
||||
|
||||
Reference in New Issue
Block a user