import {Pane} from "tweakpane"; import {STATES, BUTTON_CONFIG} from "../config/constants.js"; export class UIController { constructor({params, callbacks}) { this.params = params; this.callbacks = callbacks; this.pane = new Pane(); this.folders = {}; this.actionButton = null; this.init(); } init() { this.createGridFolder(); this.createVisualFolder(); this.createPhysicsFolder(); this.createControlsFolder(); this.createActionButton(); } createGridFolder() { const f = this.pane.addFolder({title: "Box"}); f.addBinding(this.params, "gridCols", {label: "Column", min: 10, max: 100, step: 1}).on("change", this.callbacks.onRebuild); f.addBinding(this.params, "gridSpacing", {label: "Space", min: 1.0, max: 2.0, step: 0.1}).on("change", this.callbacks.onRebuild); f.addBinding(this.params, "shape", {label: "Shape", options: {Cube: "cube", RandomBox: "random"}}).on("change", (e) => { this.callbacks.onUpdateUniform("uUseRandomDepth", e.value === "random" ? 1.0 : 0.0); this.callbacks.onRebuild(); }); f.addBinding(this.params, "gridCount", {readonly: true, label: "Count"}); this.folders.grid = f; } createVisualFolder() { const f = this.pane.addFolder({title: "Visual"}); f.addBinding(this.params, "baseDuration", {label: "Duration", min: 0.5, max: 5.0, step: 0.1}); f.addBinding(this.params, "organicMode", {label: "Organic"}).on("change", (e) => this.callbacks.onUpdateUniform("uOrganicMode", e.value ? 1.0 : 0.0)); f.addBinding(this.params, "usePixelate", {label: "Pixelate"}).on("change", (e) => this.callbacks.onUpdateUniform("uUsePixelate", e.value ? 1.0 : 0.0)); f.addBinding(this.params, "useRGBShift", {label: "RGBShift"}).on("change", (e) => this.callbacks.onUpdateUniform("uUseRGBShift", e.value ? 1.0 : 0.0)); f.addBinding(this.params, "effectSpread", {label: "Spread", min: 0.0, max: 0.5, step: 0.05}).on("change", (e) => this.callbacks.onUpdateUniform("uEffectSpread", e.value)); f.addBinding(this.params, "effectDepth", {label: "Depth", min: 1.0, max: 3.0, step: 0.05}).on("change", (e) => this.callbacks.onUpdateUniform("uEffectDepth", e.value)); f.addBinding(this.params, "highlightColor", {label: "Color"}).on("change", (e) => this.callbacks.onUpdateUniform("uHighlightColor", e.value)); f.addBinding(this.params, "highlightIntensity", {label: "ColorInt", min: 0.0, max: 1.0, step: 0.05}).on("change", (e) => this.callbacks.onUpdateUniform("uHighlightIntensity", e.value) ); this.folders.visual = f; } createPhysicsFolder() { const f = this.pane.addFolder({title: "Physics"}); f.addBinding(this.params, "dropDelay", {min: 0, max: 3, step: 0.1, label: "DropDelay"}); f.addBinding(this.params, "isDancing", {label: "Dance"}).on("change", this.callbacks.onUpdatePhysics); f.addBinding(this.params, "dancingLevel", {min: 0, max: 10, step: 1, label: "DanceLV"}).on("change", this.callbacks.onUpdatePhysics); this.folders.physics = f; } createControlsFolder() { const f = this.pane.addFolder({title: "Controls"}); f.addBinding(this.params, "manualMode", {label: "Manual"}).on("change", this.callbacks.onManualChange); this.folders.controls = f; } createActionButton() { const config = BUTTON_CONFIG[STATES.LOADING](); this.actionButton = this.pane.addButton({ title: config.title, disabled: config.disabled, }); this.actionButton.on("click", this.callbacks.onAction); } updateState(state, manualMode) { if (!this.actionButton) return; const isDefault = state === STATES.DEFAULT; const isCollapsed = state === STATES.COLLAPSED; this.folders.grid.disabled = !isDefault; this.folders.visual.disabled = !isDefault; this.folders.controls.disabled = !isDefault; this.folders.physics.disabled = !(isDefault || isCollapsed); const getConfig = BUTTON_CONFIG[state] || BUTTON_CONFIG[STATES.LOADING]; const {title, disabled} = getConfig(manualMode); this.actionButton.title = title; this.actionButton.disabled = disabled; this.pane.refresh(); } dispose() { this.pane.dispose(); } }