app
JST Connector Studio: manufacturer 3D mate editor
Public Unreviewedby John Lauer
Interactive Babylon 9.5 studio for JST wire-to-board connectors: load a system (PH/XH/SH/GH/ZH), see the JST manufacturer housing+wire+ds2sf footprint mate in a looping animation next to the KiCad hou
#!/usr/bin/env node
// jst-studio - Adom app: JST connector mating 3D studio (Babylon 9.5).
// CLI: serve | open | set | export-config | install
const http=require('http'),fs=require('fs'),path=require('path'),url=require('url');
const ROOT=path.join(__dirname,'..','public');
const STATE=path.join(__dirname,'..','state.json'); // AI-writable overrides, surfaced to the UI
const MIME={'.html':'text/html','.js':'text/javascript','.mjs':'text/javascript','.json':'application/json','.glb':'model/gltf-binary','.svg':'image/svg+xml','.png':'image/png','.css':'text/css','.map':'application/json'};
function readState(){ try{return JSON.parse(fs.readFileSync(STATE,'utf8'));}catch{return {};} }
function writeState(s){ fs.writeFileSync(STATE,JSON.stringify(s,null,1)); }
function serve(port){
const srv=http.createServer((req,res)=>{
const u=url.parse(req.url,true); let p=decodeURIComponent(u.pathname);
if(p==='/api/state'){ res.setHeader('content-type','application/json'); return res.end(JSON.stringify(readState())); }
if(p==='/api/set'&&req.method==='POST'){ let b=''; req.on('data',d=>b+=d); req.on('end',()=>{ try{const j=JSON.parse(b||'{}');const s=readState();s[j.sys]=Object.assign(s[j.sys]||{},j.patch||{});writeState(s);res.setHeader('content-type','application/json');res.end(JSON.stringify({ok:true,state:s}));}catch(e){res.statusCode=400;res.end(JSON.stringify({ok:false,error:String(e)}));} }); return; }
if(p==='/api/export'){ res.setHeader('content-type','application/json'); return res.end(JSON.stringify(readState(),null,1)); }
if(p==='/') p='/index.html';
const f=path.join(ROOT,p);
if(!f.startsWith(ROOT)||!fs.existsSync(f)){ res.statusCode=404; return res.end('not found'); }
res.setHeader('content-type',MIME[path.extname(f)]||'application/octet-stream');
res.setHeader('access-control-allow-origin','*');
fs.createReadStream(f).pipe(res);
});
srv.listen(port,()=>console.log(`OK: jst-studio serving http://localhost:${port} (Hydrogen webview)`));
}
const [cmd,...rest]=process.argv.slice(2);
const arg=(k,d)=>{const i=rest.indexOf(k);return i>=0?rest[i+1]:d;};
if(cmd==='serve'){ serve(+arg('--port','8791')); }
else if(cmd==='set'){ // set <sys> <key> <value>
const [sys,key,val]=rest; const s=readState(); s[sys]=s[sys]||{}; s[sys][key]=(val==='true'?true:val==='false'?false:isNaN(+val)?val:+val); writeState(s);
console.log(`OK: ${sys}.${key} = ${s[sys][key]}`);
}
else if(cmd==='export-config'){ console.log(JSON.stringify(readState(),null,1)); }
else if(cmd==='open'){ console.log('Hint: start `jst-studio serve` then open the URL in a Hydrogen webview panel.'); }
else if(cmd==='install'){ console.log('OK: jst-studio installed.'); }
else { console.log('jst-studio <serve|open|set|export-config|install>\n serve --port 8791 run the app server (Hydrogen webview)\n set <sys> <key> <val> AI: override a per-system variable\n export-config print the tuned config (feeds the GLB build)'); }