diff --git a/templates/editor.html b/templates/editor.html
index a7f45bb..b59d04b 100644
--- a/templates/editor.html
+++ b/templates/editor.html
@@ -183,7 +183,10 @@ body{font-family:'Segoe UI',system-ui,sans-serif;background:var(--bg);color:var(
-
+
@@ -568,112 +571,191 @@ function exportLayout() {
function toggleHelp() { document.getElementById('help-panel').classList.toggle('open'); }
// ══════════════════════════════════════════════════════
-// MACHINE SCHEMATIC (SVG)
+// MACHINE SCHEMATIC — data-driven, editable
// ══════════════════════════════════════════════════════
+const defaultEquipment = [
+ {id:'eq_loading', label:'Loading', shape:'rect', x:40, y:160, w:90, h:80, anim:null, link:null},
+ {id:'eq_drum', label:'Dryer Drum', shape:'rect', x:200, y:130, w:140, h:140, anim:null, link:null},
+ {id:'eq_burner', label:'Burner', shape:'circle', x:200, y:200, r:20, anim:'burner', link:'burner_0'},
+ {id:'eq_fan', label:'Fan', shape:'circle', x:340, y:150, r:22, anim:'fan', link:'motor_0'},
+ {id:'eq_conveyor', label:'Conveyor', shape:'rect', x:410, y:180, w:130, h:40, anim:'conveyor', link:'motor_1'},
+ {id:'eq_agit1', label:'A1', shape:'circle', x:440, y:170, r:12, anim:'agitator', link:'motor_3'},
+ {id:'eq_agit2', label:'A2', shape:'circle', x:510, y:170, r:12, anim:'agitator', link:'motor_4'},
+ {id:'eq_spinner', label:'Spin', shape:'circle', x:475, y:155, r:14, anim:'fan', link:'motor_2'},
+ {id:'eq_discharge',label:'Discharge', shape:'rect', x:580, y:160, w:80, h:60, anim:null, link:null},
+ {id:'eq_mill', label:'Mill', shape:'rect', x:580, y:250, w:70, h:50, anim:null, link:'output_4'},
+ {id:'eq_shaker', label:'Shaker Sep.',shape:'rect', x:670, y:250, w:90, h:50, anim:null, link:'output_5'},
+ {id:'eq_brush', label:'Brush', shape:'rect', x:670, y:160, w:60, h:40, anim:null, link:'output_1'},
+];
+
+let simEditMode = false;
+let dragEquip = null, dragOffset = {x:0, y:0};
+
+function getEquipment() {
+ return layout.equipment || JSON.parse(JSON.stringify(defaultEquipment));
+}
+
+function toggleSimEdit() {
+ simEditMode = !simEditMode;
+ const btn = document.getElementById('btn-sim-edit');
+ btn.textContent = simEditMode ? 'DONE EDITING' : 'EDIT LAYOUT';
+ btn.style.background = simEditMode ? 'var(--amber)' : 'var(--card)';
+ btn.style.color = simEditMode ? '#000' : 'var(--text2)';
+ renderSchematic();
+}
+
function renderSchematic() {
- document.getElementById('sim-container').innerHTML = `
-
`;
+function startDragEquip(e, eq) {
+ if (!simEditMode) return;
+ dragEquip = eq;
+ const svg = document.getElementById('sim-svg');
+ const pt = svg.createSVGPoint();
+ pt.x = e.clientX; pt.y = e.clientY;
+ const svgPt = pt.matrixTransform(svg.getScreenCTM().inverse());
+ dragOffset.x = svgPt.x - eq.x;
+ dragOffset.y = svgPt.y - eq.y;
+ e.preventDefault();
+}
+
+function moveDragEquip(e) {
+ if (!dragEquip) return;
+ const svg = document.getElementById('sim-svg');
+ const pt = svg.createSVGPoint();
+ pt.x = e.clientX; pt.y = e.clientY;
+ const svgPt = pt.matrixTransform(svg.getScreenCTM().inverse());
+ dragEquip.x = Math.round(svgPt.x - dragOffset.x);
+ dragEquip.y = Math.round(svgPt.y - dragOffset.y);
+ // Save to layout
+ layout.equipment = getEquipment();
+ const eq = layout.equipment.find(e => e.id === dragEquip.id);
+ if (eq) { eq.x = dragEquip.x; eq.y = dragEquip.y; }
+ renderSchematic();
+}
+
+function stopDragEquip() { dragEquip = null; }
+
+function renameEquip(eq) {
+ const name = prompt('Rename equipment:', eq.label);
+ if (!name) return;
+ eq.label = name;
+ if (!layout.equipment) layout.equipment = getEquipment();
+ const e = layout.equipment.find(x => x.id === eq.id);
+ if (e) e.label = name;
+ renderSchematic();
}
function updateSchematicAnimations() {
- // Map card IDs to SVG animation elements
- const map = {
- 'motor_0': 'sim-fan', 'burner_0': 'sim-burner',
- 'motor_1': 'sim-conveyor', 'motor_2': 'sim-spinner',
- 'motor_3': 'sim-agit1', 'motor_4': 'sim-agit2'
- };
- Object.entries(map).forEach(([cardId, svgId]) => {
- const el = document.getElementById(svgId);
+ const equip = getEquipment();
+ equip.forEach(eq => {
+ if (!eq.link || !eq.anim) return;
+ const el = document.getElementById('sim-' + eq.id);
if (!el) return;
- const s = simState[cardId];
+ const s = simState[eq.link];
el.classList.toggle('active', s && s.on);
});
}