← Commit history

demo: the library card now proves all three artifacts (symbol + footprint + 3D), one screenshot each, and only 3/3 passes

John Lauer ·dad2a9eb50 ·2mo ago ·parent 9487b12
1 file changed +86−1
web-control-demo.html+86−1
@@ -1550,6 +1550,90 @@ for (const w of mine) {   // arg (0.9.108) installs the .step into 3dmodels/Adom and WIRES the   // footprint's (model ...) reference itself — the page's old hand-splice is   // retired; the bridge owns model wiring now.+  // A LIBRARY is a symbol PLUS a footprint PLUS a 3D model, so the proof that a+  // library works is all three of those opening - not a picture of the library+  // tree. The old card showed whatever the Symbol Editor happened to be holding+  // (ADOM_MECHANICAL_PIN, which sorts first), which proved nothing and looked+  // like the wrong part had loaded. Measured across a 10-part run: this card's+  // shot was byte-identical for 8 of the 10 parts.+  //+  // John, 2026-08-20: "a library is all 3 of those items".+  function appendPicked(c, d, pickTitle, label) {+    var shots = findShots(d).filter(function (s) { return s && (s.image || s.base64 || s.png); });+    if (!shots.length) return false;+    var want = (pickTitle || "").toLowerCase();+    var picked = want ? shots.filter(function (s) {+      return ((s.title || s.label || "") + "").toLowerCase().indexOf(want) >= 0;+    }) : shots;+    if (!picked.length) picked = [shots[shots.length - 1]];+    var s0 = picked[0];+    addShot(c.card, s0.image || s0.base64 || s0.png, label + " - " + (s0.title || s0.label || "window"));+    return true;+  }++  function showLibraryProof(c) {+    c.btn.disabled = true;+    cardLog(c.card).textContent = "";+    var sb = c.card.querySelector("div.shots"); if (sb) sb.innerHTML = "";+    setAwaiting(c.res, "asking permission (choose “Allow 1 hr”) ...",+      "on " + esc(selfLabel()) + " - opens the symbol, the footprint and the 3D model as proof",+      "on " + esc(selfLabel()) + " - opens the symbol, the footprint and the 3D model as proof");+    clog(c, "Target machine: " + selfLabel());+    startSurfaceProgress(c, "kicad_show_library");+    var results = [];+    stageKicadPart(c).then(function () {+      // Browse mode WITH symbolName actually loads the part into the canvas -+      // the bridge says so in its own hint: "To load a part into the canvas,+      // call again with symbolName too."+      clog(c, "Opening the '" + PART.kicadLib + "' library at " + (PART.kicadSymbolName || PART.name) + " ...");+      return postVerb("kicad_show_library", {+        libraryName: PART.kicadLib,+        symbolName: PART.kicadSymbolName || PART.name+      });+    }).then(function () {+      var steps = [+        { cmd: "kicad_show_symbol", label: "symbol", pick: "symbol editor",+          args: function () { return { symbolName: PART.kicadSymbolName || PART.name, library: PART.kicadLib }; } },+        { cmd: "kicad_show_footprint", label: "footprint", pick: "footprint editor",+          args: function () { return { footprintName: PART.kicadFootprintName || PART.name, library: PART.kicadLib }; } },+        { cmd: "kicad_show_3d_chip", label: "3D model", pick: "3d viewer",+          args: function () { return { footprintName: PART.kicadFootprintName || PART.name, library: PART.kicadLib }; } }+      ];+      return steps.reduce(function (chain, st) {+        return chain.then(function () {+          clog(c, "Proving the " + st.label + " ...");+          return postVerb(st.cmd, st.args()).then(function (r) {+            var jj = r.j || {};+            var ok = r.s === 200 && jj.success !== false && !jj.errorCode &&+              !(typeof jj.error === "string" && jj.error.trim() !== "");+            results.push({ label: st.label, ok: ok });+            if (!ok) {+              clog(c, "  " + st.label + " FAILED: " + (jj.error || jj.errorCode || ("HTTP " + r.s)));+              return;+            }+            return settleThenCapture(c, "kicad_state").then(function (sr) {+              if (!(sr.s === 200 && sr.j && appendPicked(c, sr.j, st.pick, st.label)))+                clog(c, "  (" + st.label + " opened but no capture came back)");+            });+          });+        });+      }, Promise.resolve());+    }).then(function () {+      finishSurfaceBar(c);+      var good = results.filter(function (r) { return r.ok; }).length;+      var missing = results.filter(function (r) { return !r.ok; }).map(function (r) { return r.label; });+      if (good === 3) setRes(c.res, "ok", "Done - all 3 library artifacts opened",+        "symbol + footprint + 3D model, each captured below");+      else setRes(c.res, "err", good + "/3 library artifacts opened",+        "missing: " + missing.join(", ") + " - a library is only proven when all three open");+      c.btn.disabled = false;+    }).catch(function (e) {+      finishSurfaceBar(c);+      setRes(c.res, "err", "library proof failed", (e && e.message) || String(e));+      c.btn.disabled = false;+    });+  }+   var _kicadPart = null;   function stageKicadPart(c) {     if (_kicadPart) { clog(c, "Part already staged this session (reusing)."); return _kicadPart; }@@ -1635,7 +1719,7 @@ for (const w of mine) {     { label: function () { return "Symbol (" + PART.name + ")"; }, cmd: "kicad_show_symbol", args: function () { return { symbolName: PART.kicadSymbolName || PART.name, libraryName: PART.kicadLib }; }, stage: stageKicadPart, pick: "symbol editor", note: "installs the part from its wiki page, then shows JUST the symbol" },     { label: function () { return "Footprint (" + PART.name + ")"; }, cmd: "kicad_show_footprint", args: function () { return { footprintName: PART.kicadFootprintName || PART.name, library: PART.kicadLib }; }, stage: stageKicadPart, pick: "footprint editor", note: "just the land pattern: pads + courtyard" },     { label: function () { return "3D chip (" + PART.name + ")"; }, cmd: "kicad_show_3d_chip", args: function () { return { footprintName: PART.kicadFootprintName || PART.name, library: PART.kicadLib }; }, stage: stageKicadPart, pick: "3d viewer", note: "the part's STEP model on its footprint" },-    { label: function () { return "Library tree ('" + PART.kicadLib + "') - loads no part"; }, cmd: "kicad_show_library", args: function () { return { libraryName: PART.kicadLib }; }, stage: stageKicadPart, pick: "symbol editor", note: "EXPECT A DIFFERENT PART IN THE SHOT BELOW. This verb browses the library TREE and by design loads NO part, so the editor keeps showing whatever symbol it already had (usually ADOM_MECHANICAL_PIN, which sorts first). Measured across a 10-part run: the symbol, footprint and 3D shots are all 10/10 unique, while this one is byte-identical for 8 of 10 parts. That is the verb behaving correctly, not a stale file - which is why the label no longer names the part." },+    { label: function () { return "Library (" + PART.name + " in '" + PART.kicadLib + "') - proves all 3"; }, cmd: "kicad_show_library", proof: true, stage: stageKicadPart, note: "a library IS a symbol + a footprint + a 3D model, so this opens all three and captures one screenshot of each. It reports N/3, and only 3/3 is a pass - a library with a symbol but no 3D model is not a working library." },     { label: function () { return "Schematic (just the " + PART.name + ")"; }, cmd: "kicad_show_schematic", args: function () { return { filePath: (PART.kicadProject || {}).schPath }; }, stage: stageKicadProject, pick: "schematic editor", note: "the generated single-component schematic (kicad_make_part_project)" },     { label: "2D board (part placed, tight edge cuts)", cmd: "kicad_show_2d_board", args: function () { return { filePath: (PART.kicadProject || {}).pcbPath }; }, stage: stageKicadProject, pick: "pcb editor", note: "the part-dominant board" },     { label: "3D board (real 3D body on the board)", cmd: "kicad_show_3d_board", args: function () { return { filePath: (PART.kicadProject || {}).pcbPath }; }, stage: stageKicadProject, pick: "3d viewer", note: "the populated board in 3D - the whole ladder underneath it" },@@ -1643,6 +1727,7 @@ for (const w of mine) {   ].forEach(function (s) {     var cc = card("grp-kicad", "verb", labelOf(s));     PART_CARDS.push({ cc: cc, label: labelFnOf(s) });+    if (s.proof) { cc.btn.onclick = function () { showLibraryProof(cc); }; return; }     cc.btn.onclick = function () {       showSurface(cc, {         showCmd: s.cmd,