// Engine: the settings every installed module has volunteered, by category. import { composer as c } from "../../composer/composer.js"; import { settingRow, whenSatisfied } from "./field.js"; const CATEGORIES = [["continuity", "Continuity"], ["guidance", "Guidance"], ["conditioning", "Conditioning"], ["sampling", "Sampling"], ["post", "Post"], ["system", "System"], ["", "Other"]]; export const engine = (app) => function mount() { const ps = app.pipeline; const page = c.region.stack({ gap: "md" }); let category = null; function draw() { if (ps.loading()) return page.set([c.hint.default({ text: "Loading…" })]); if (ps.loadError()) return page.set([c.banner.warn({ text: `Could not load Engine settings: ${ps.loadError()}` })]); if (ps.allOff()) return page.set([c.banner.info({ text: "All enhancements are disabled for this project, so there is nothing to set. Turn them back on in Settings ▸ Modules." })]); const ok = ps.usefulness(), withSettings = ps.activeModules().filter((m) => Object.values(m.settings || {}).some((spec) => spec.home !== "project") && ok(m)); // nothing would read the rest const cats = CATEGORIES.filter(([k]) => withSettings.some((m) => (m.category || "") === k)); const gOff = ps.guidanceOff(); if (!cats.length) return page.set([c.emptyState.default({ icon: "⚡", title: "Nothing to set", hint: "No installed module exposes a setting for this pipeline." })]); if (!cats.some(([k]) => k === category)) category = cats[0][0]; const values = ps.currentValues(), notes = ps.saveNotes(); const change = async (id, name, value) => { await ps.setModuleValue(id, name, value); draw(); }; page.set([ c.segmented.sm({ label: "Category", value: category, options: cats.map(([value, label]) => ({ value, label })), onChange: (v) => { category = v; draw(); } }), notes.length ? c.banner.info({ text: notes.join(" ") }) : null, category === "guidance" ? c.toggle.default({ label: "Disable all guidance enhancements", hint: "Every guidance module sits out of the run. Your choices are kept, switch it back off to restore them.", checked: gOff, onChange: (on) => ps.setGuidanceOff(on).then(draw) }) : null, category === "conditioning" && ps.modulesById()["conditioning_shot_camera"] ? c.toggle.default({ label: "Disable all automated camera prompt enhancement", hint: "Stops Shot camera adding cuts, views, camera moves and liked details to your prompt. Your choices are kept.", checked: ps.cameraOff(), onChange: (on) => ps.setCameraOff(on).then(draw) }) : null, ...(category === "guidance" && gOff ? [c.hint.default({ text: "Guidance enhancements are disabled for this project. Their settings are hidden, not lost." })] : withSettings.filter((m) => (m.category || "") === category).flatMap((m) => [c.label.section({ text: m.title || m.id }), ...Object.entries(m.settings).filter(([, spec]) => spec.home !== "project" && whenSatisfied(values, m.id, spec.when)).map(([name, spec]) => settingRow(m.id, name, spec, values, change, ps.blocks?.()))])), ].filter(Boolean)); } draw(); ps.ensureLoaded().then(() => ps.reloadModules()).then(draw); const typing = () => app.dom.typingIn(page.node); page.node.addEventListener("focusout", () => setTimeout(() => { if (!typing()) draw(); })); const off = ps.subscribe(() => { if (!typing()) draw(); }); return { node: page.node, destroy: () => { off(); page.node.remove(); } }; };