app
AI Flow: Reverse Engineering
Public Made by Adomby adom
Photos of a PCB to a tagged KiCad copy: parts placed, copper and nets with their evidence, a schematic, a measured confidence score, bench tests and a video of the run.
main
Caleb
Add the method and status docs, and how the process video was made
77ea994
const p=require(process.env.HOME+'/.cache/hero-studio/node_modules/puppeteer-core');
const sleep=ms=>new Promise(r=>setTimeout(r,ms));
const U='http://localhost:8891/';
(async()=>{const b=await p.launch({headless:'new',executablePath:process.env.HOME+'/.cache/puppeteer/chrome/linux-150.0.7871.24/chrome-linux64/chrome',args:['--no-sandbox','--disable-gpu'],protocolTimeout:600000});
// ---- flow window, 1x
let pg=await b.newPage();await pg.setViewport({width:1920,height:1080});await pg.goto(U,{waitUntil:'load'});await sleep(6000);
const clickN=async n=>{await pg.evaluate(n=>{const s=[...document.querySelectorAll('.n')].find(e=>e.textContent.trim()==='#'+n);let e=s;for(let i=0;i<3&&e.parentElement&&!e.onclick&&e.tagName!=='BUTTON';i++)e=e.parentElement;(s.closest('button,[data-n],.rec,.item,li')||e).scrollIntoView({block:'center'});(s.closest('button,[data-n],.rec,.item,li')||e).click()},n)};
const tab=async t=>{await pg.evaluate(t=>{[...document.querySelectorAll('button')].find(e=>e.textContent.trim()===t).click()},t)};
for(const n of [6,10,15,73,81,96,97,98,101]){await clickN(n);await sleep(n>=76?12000:7000);await pg.screenshot({path:`shots/f/rec${n}.png`});console.log('rec',n)}
await tab('Schematic');await sleep(14000);await pg.screenshot({path:'shots/f/sch101.png'});
await clickN(110);await sleep(3000);await tab('Findings');await sleep(2500);await pg.screenshot({path:'shots/f/findings.png'});
await pg.close();
// ---- pcb viewer, 2x, layer states
const shots=[
['101-mimic','top',{side:'Top',on:/Copper · Top|Silk · Top|Board edge/}],
['101-mimic','bot',{side:'Bottom',on:/Copper · Bot|Silk · Bot|Board edge/}],
['101-mimic','all',{side:'Top',on:/Copper|Silk · Top|Board edge/}],
['073-mimic','top',{side:'Top',on:/Copper · Top|Silk · Top|Board edge/}],
['073-mimic','bot',{side:'Bottom',on:/Copper · Bot|Silk · Bot|Board edge/}],
['096-connect','inner',{side:'Top',on:/Copper · In|Board edge/}],
['097-connect','inner',{side:'Top',on:/Copper · In|Board edge/}],
['098-connect','inner',{side:'Top',on:/Copper · In|Board edge/}],
['096-connect','all',{side:'Top',on:/Copper|Board edge/}],
['097-connect','all',{side:'Top',on:/Copper|Board edge/}],
['098-connect','all',{side:'Top',on:/Copper|Board edge/}],
['082-connect','all',{side:'Top',on:/Copper|Board edge/}],
];
for(const [v,name,o] of shots){pg=await b.newPage();await pg.setViewport({width:1920,height:1080,deviceScaleFactor:2});
await pg.goto(`${U}files/views/${v}-pcb.html`,{waitUntil:'load',timeout:180000});await sleep(9000);
await pg.evaluate(o=>{[...document.querySelectorAll('button')].find(e=>e.textContent.trim()===o.side)?.click();
const re=new RegExp(o.on);document.querySelectorAll('.lyr').forEach(l=>{const c=l.querySelector('input');const want=re.test(l.querySelector('.lyr-name').textContent);if(c.checked!==want)c.click()});
document.querySelectorAll('.panel').forEach(x=>x.style.display='none');
[...document.querySelectorAll('button')].find(e=>e.textContent.trim()==='Fit')?.click();window.AdomPcb?.fit?.()},{side:o.side,on:o.on.source});
await sleep(5000);await pg.screenshot({path:`shots/p/${v.slice(0,3)}-${name}.png`});console.log(v,name,await pg.evaluate(()=>[...document.querySelectorAll('.lyr-name')].length));await pg.close();}
// schematic 2x
pg=await b.newPage();await pg.setViewport({width:1920,height:1080,deviceScaleFactor:2});await pg.goto(U+'files/views/101-mimic-sch.html',{waitUntil:'load',timeout:180000});await sleep(10000);await pg.screenshot({path:'shots/p/101-sch.png'});
console.log(await pg.evaluate(()=>[...document.querySelectorAll('select option')].map(e=>e.textContent).slice(0,20)));
await b.close()})().catch(e=>{console.error(e);process.exit(1)});