diff --git a/src/main.js b/src/main.js index 8d4b875..28b068e 100644 --- a/src/main.js +++ b/src/main.js @@ -158,8 +158,89 @@ const defaultSettings = { baseModel: 'stabilityai/stable-diffusion-xl-base-1.0', vaeModel: 'madebyollin/sdxl-vae-fp16-fix', }; +const settingsStorageKey = 'skymap-gen:generation-settings:v1'; let currentSettings = { ...defaultSettings }; +function clamp(value, min, max) { + return Math.max(min, Math.min(max, value)); +} + +function normalizeNumberSetting(value, fallback, { min, max, integer = false } = {}) { + const parsed = Number(value); + if (!Number.isFinite(parsed)) return fallback; + const rounded = integer ? Math.trunc(parsed) : parsed; + return clamp(rounded, min, max); +} + +function selectHasValue(input, value) { + return Array.from(input.options).some(option => option.value === value); +} + +function normalizeSelectSetting(value, input, fallback) { + return selectHasValue(input, value) ? value : fallback; +} + +function normalizeTextSetting(value, fallback) { + return typeof value === 'string' && value.trim() ? value.trim() : fallback; +} + +function normalizeSettings(settings = {}) { + return { + steps: normalizeNumberSetting(settings.steps, defaultSettings.steps, { min: 1, max: 80, integer: true }), + guidance: normalizeNumberSetting(settings.guidance, defaultSettings.guidance, { min: 0, max: 20 }), + width: normalizeNumberSetting(settings.width, defaultSettings.width, { min: 256, max: 4096, integer: true }), + height: normalizeNumberSetting(settings.height, defaultSettings.height, { min: 256, max: 4096, integer: true }), + scheduler: normalizeSelectSetting(settings.scheduler, schedulerInput, defaultSettings.scheduler), + upscale: normalizeSelectSetting(settings.upscale, upscaleInput, defaultSettings.upscale), + seamInpaint: settings.seamInpaint === true, + modelPath: normalizeTextSetting(settings.modelPath, defaultSettings.modelPath), + baseModel: normalizeTextSetting(settings.baseModel, defaultSettings.baseModel), + vaeModel: normalizeTextSetting(settings.vaeModel, defaultSettings.vaeModel), + }; +} + +function readSettingsFromInputs() { + return normalizeSettings({ + steps: stepsInput.value, + guidance: guidanceInput.value, + width: widthInput.value, + height: heightInput.value, + scheduler: schedulerInput.value, + upscale: upscaleInput.value, + seamInpaint: seamInpaintInput.checked, + modelPath: modelPathInput.value, + baseModel: baseModelInput.value, + vaeModel: vaeModelInput.value, + }); +} + +function loadSavedSettings() { + try { + const raw = localStorage.getItem(settingsStorageKey); + if (!raw) return null; + const parsed = JSON.parse(raw); + return parsed && typeof parsed === 'object' ? normalizeSettings(parsed) : null; + } catch (err) { + console.warn('Failed to load saved generation settings', err); + return null; + } +} + +function saveSettings(settings) { + const normalized = normalizeSettings(settings); + currentSettings = normalized; + try { + localStorage.setItem(settingsStorageKey, JSON.stringify(normalized)); + } catch (err) { + console.warn('Failed to save generation settings', err); + } + return normalized; +} + +function persistSettingsFromInputs() { + saveSettings(readSettingsFromInputs()); +} + function setStatus(msg) { statusEl.textContent = msg || ''; statusEl.style.opacity = msg ? '0.98' : '0';