Seedbox v0.1 + firmware, generic kit/synth, ROOT/SCALE pages
Some checks failed
check / check (push) Has been cancelled

First commit of the repo. Contents beyond the v0.1 simulator and layout:

- Full Pico 2 W firmware (firmware/app, drivers, engine port, host test).
- BANK page and 404 mode A/B removed; learned pads play exactly what was learned.
- 404/MiniFreak renamed to KIT/SYNTH throughout (jacks, code, sim, docs,
  layout labels; wiring rebuilt).
- ROLL returns to page select after a re-roll; a freshly learned track turns on.
- LCD contrast 66.
- ROOT and SCALE pages: 21 scales, AUTO = the seed picks; global and sticky.

Intended music change: the scale table grew from 8 to 21 and AUTO picks from
all of them, so every seed's scale changed. Vectors regenerated with
npm run vectors, plus new key-override cases. Flash record is now version 2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-11 20:39:36 +03:00
commit 2196633ed5
77 changed files with 52207 additions and 0 deletions

246
tools/wiring-src/render.js Normal file
View File

@@ -0,0 +1,246 @@
(function(){
var L=LAYOUT, NS='http://www.w3.org/2000/svg';
function css(n){ return getComputedStyle(document.documentElement).getPropertyValue(n).trim(); }
function el(tag,a,p,txt){ var e=document.createElementNS(NS,tag); for(var k in a) e.setAttribute(k,a[k]); if(txt!=null) e.textContent=txt; p.appendChild(e); return e; }
function rowName(r){ return r<26 ? String.fromCharCode(65+r) : 'A'+String.fromCharCode(65+r-26); }
function pos(h){ return rowName(h[1])+(h[0]+1); }
function H(p){ return /^P\d+$/.test(p) ? pos(L.wires[+p.slice(1)-1].h) : p; }
var COL={red:'--w-red',black:'--w-black',yellow:'--w-yellow',green:'--w-green',blue:'--w-blue'};
var cutKey={}; L.cuts.forEach(function(c){ cutKey[c[0]+','+c[1]]=1; });
function strips(svg,X,C,strong){
for(var r=0;r<L.H;r++){
var start=0;
for(var c=0;c<=L.W;c++){
if(c===L.W || cutKey[c+','+r]){
if(c>start){ var x0=Math.min(X(start),X(c-1))-0.42, x1=Math.max(X(start),X(c-1))+0.42;
el('rect',{x:x0,y:r-0.36,width:x1-x0,height:0.72,rx:0.2,fill:C.copper,opacity:strong?1:0.28},svg); }
start=c+1;
}
}
}
}
function holes(svg,X,C){ for(var r=0;r<L.H;r++) for(var c=0;c<L.W;c++) el('circle',{cx:X(c),cy:r,r:0.16,fill:C.hole},svg); }
function labels(svg,X,C,flip){
var g=el('g',{'font-family':css('--f-mono'),'font-size':'0.55',fill:C.muted},svg);
for(var c=0;c<L.W;c++) if(c%2===0 || c===L.W-1){ el('text',{x:X(c),y:-1.75,'text-anchor':'middle'},g,String(c+1)); el('text',{x:X(c),y:L.H+0.9,'text-anchor':'middle'},g,String(c+1)); }
for(var r=0;r<L.H;r++){ el('text',{x:-1.3,y:r+0.2,'text-anchor':'middle'},g,rowName(r)); el('text',{x:L.W+0.3,y:r+0.2,'text-anchor':'middle'},g,rowName(r)); }
}
function frame(svg){ svg.setAttribute('viewBox','-2.4 -2.6 '+(L.W+3.8)+' '+(L.H+4.0)); }
var U1label=(L.parts.filter(function(p){ return p.id==='U1'; })[0]||{}).label||'';
function drawTop(){
var svg=document.getElementById('top'); svg.innerHTML=''; frame(svg);
var C={copper:css('--copper'),hole:css('--hole'),muted:css('--muted'),part:css('--part'),pink:css('--part-ink'),link:css('--link'),warn:css('--warn'),board:css('--board'),edge:css('--board-edge'),ink:css('--ink')};
var X=function(c){ return c; };
el('rect',{x:-0.8,y:-0.5,width:L.W+0.6,height:L.H+0.3,rx:0.4,fill:C.board,stroke:C.edge,'stroke-width':0.12},svg);
strips(svg,X,C,false); holes(svg,X,C); labels(svg,X,C);
L.cuts.forEach(function(c){ var g={stroke:C.warn,'stroke-width':0.1,opacity:0.7}; el('line',Object.assign({x1:c[0]-0.22,y1:c[1]-0.22,x2:c[0]+0.22,y2:c[1]+0.22},g),svg); el('line',Object.assign({x1:c[0]-0.22,y1:c[1]+0.22,x2:c[0]+0.22,y2:c[1]-0.22},g),svg); });
var f=css('--f-mono');
L.parts.forEach(function(p){
if(p.kind==='pico'){
el('rect',{x:11.3,y:-0.55,width:8.4,height:20.1,rx:0.4,fill:C.part,opacity:0.92},svg);
el('rect',{x:14.3,y:-1.35,width:2.4,height:1.35,rx:0.2,fill:'#9AA3AD'},svg); el('text',{x:15.5,y:-0.55,'text-anchor':'middle','font-family':f,'font-size':'0.42',fill:'#111'},svg,'USB');
el('text',{x:15.5,y:1.6,'text-anchor':'middle','font-family':f,'font-size':'0.62',fill:C.pink},svg,'PICO 2W');
p.pins.forEach(function(pp){ var left=pp.h[0]===12;
el('rect',{x:pp.h[0]-0.32,y:pp.h[1]-0.32,width:0.64,height:0.64,fill:'#111',stroke:'#D4AF37','stroke-width':0.08},svg);
el('text',{x:left?pp.h[0]+0.55:pp.h[0]-0.55,y:pp.h[1]+0.16,'text-anchor':left?'start':'end','font-family':f,'font-size':'0.42',fill:C.pink},svg,pp.n); });
} else if(p.kind==='dip8'){
el('rect',{x:4.25,y:19.55,width:2.5,height:3.9,rx:0.15,fill:C.part},svg);
el('path',{d:'M 5 19.55 a 0.5 0.5 0 0 0 1 0',fill:'#555'},svg);
el('text',{x:5.5,y:21.7,'text-anchor':'middle','font-family':f,'font-size':'0.42',fill:C.pink,transform:'rotate(90 5.5 21.6)'},svg,U1label);
p.pins.forEach(function(pp){ el('rect',{x:pp.h[0]-0.25,y:pp.h[1]-0.18,width:0.5,height:0.36,fill:'#BFC6CD'},svg); });
el('text',{x:3.55,y:20.15,'text-anchor':'end','font-family':f,'font-size':'0.4',fill:C.ink},svg,'1');
} else {
var a=p.pins[0].h, b=p.pins[1].h, horiz=a[1]===b[1], mx=(a[0]+b[0])/2, my=(a[1]+b[1])/2, len=horiz?Math.abs(b[0]-a[0]):Math.abs(b[1]-a[1]);
el('line',{x1:a[0],y1:a[1],x2:b[0],y2:b[1],stroke:'#9AA3AD','stroke-width':0.12},svg);
var bw=p.kind==='cap'?0.7:0.62, bh=Math.min(len-0.5,p.kind==='diode'?0.7:2.2);
var body=p.kind==='res'?'#C9A26B':p.kind==='diode'?'#D9663A':'#3D7BC9';
if(horiz){ el('rect',{x:mx-bh/2,y:my-bw/2,width:bh,height:bw,rx:0.25,fill:body,stroke:'#00000055','stroke-width':0.05},svg);
el('text',{x:mx,y:my-0.5,'text-anchor':'middle','font-family':f,'font-size':'0.42',fill:C.ink},svg,p.id); }
else el('rect',{x:a[0]-bw/2,y:my-bh/2,width:bw,height:bh,rx:0.25,fill:body,stroke:'#00000055','stroke-width':0.05,'stroke-dasharray':p.opt?'0.2 0.12':''},svg);
if(p.kind==='diode'){ var ky=p.pins[0].n==='K'?p.pins[0].h[1]:p.pins[1].h[1]; el('rect',{x:a[0]-bw/2,y:(ky<my?my-bh/2:my+bh/2-0.16),width:bw,height:0.16,fill:'#111'},svg); }
if(!horiz) el('text',{x:a[0]+0.48,y:my+0.15,'font-family':f,'font-size':'0.42',fill:C.ink},svg,p.id+(p.opt?'*':''));
}
p.pins.forEach(function(pp){ if(p.kind!=='pico') el('circle',{cx:pp.h[0],cy:pp.h[1],r:0.13,fill:'#D4AF37'},svg); });
});
L.jumpers.forEach(function(j){
el('line',{x1:j.a[0],y1:j.a[1],x2:j.b[0],y2:j.b[1],stroke:C.link,'stroke-width':0.2,'stroke-linecap':'round',opacity:0.9},svg);
[j.a,j.b].forEach(function(h){ el('circle',{cx:h[0],cy:h[1],r:0.2,fill:C.link},svg); });
});
L.wires.forEach(function(w,i){
var col=css(COL[w.col]);
el('circle',{cx:w.h[0],cy:w.h[1],r:0.3,fill:col,stroke:'#fff','stroke-width':0.07},svg);
var right=w.h[0]>=20, tx=w.h[0]+(right?0.42:-0.42);
el('text',{x:tx,y:w.h[1]-0.3,'text-anchor':right?'start':'end','font-family':f,'font-size':'0.48','font-weight':'700',fill:C.ink},svg,'P'+(i+1));
});
var rails=[[25,'5 V'],[26,'GND'],[27,'3V3']];
rails.forEach(function(r){ el('text',{x:L.W+1.15,y:r[0]+0.2,'font-family':f,'font-size':'0.45',fill:C.warn},svg,r[1]); });
}
function drawBottom(){
var svg=document.getElementById('bottom'); svg.innerHTML=''; frame(svg);
var C={copper:css('--copper'),hole:css('--hole'),muted:css('--muted'),warn:css('--warn'),board:css('--board'),edge:css('--board-edge'),part:css('--part')};
var X=function(c){ return L.W-1-c; };
el('rect',{x:-0.8,y:-0.5,width:L.W+0.6,height:L.H+0.3,rx:0.4,fill:C.board,stroke:C.edge,'stroke-width':0.12},svg);
strips(svg,X,C,true); holes(svg,X,C); labels(svg,X,C);
el('rect',{x:X(19)-0.5,y:-0.55,width:8.4,height:20.1,rx:0.4,fill:'none',stroke:C.muted,'stroke-width':0.08,'stroke-dasharray':'0.3 0.2'},svg);
el('text',{x:X(15.5),y:-0.85,'text-anchor':'middle','font-family':css('--f-mono'),'font-size':'0.42',fill:C.muted},svg,'Pico outline (other side), USB at this edge');
L.cuts.forEach(function(c){ var x=X(c[0]);
el('rect',{x:x-0.45,y:c[1]-0.45,width:0.9,height:0.9,rx:0.15,fill:C.board},svg);
el('circle',{cx:x,cy:c[1],r:0.34,fill:'none',stroke:C.warn,'stroke-width':0.14},svg); });
var cl=document.getElementById('cutlist'); cl.innerHTML='';
var groups={}; L.cuts.forEach(function(c){ (groups[c[0]]=groups[c[0]]||[]).push(c[1]); });
Object.keys(groups).forEach(function(k){ var rs=groups[k].sort(function(a,b){return a-b;}); var li=document.createElement('li');
li.textContent='Hole '+(+k+1)+(rs.length>1?' on strips '+rowName(rs[0])+' to '+rowName(rs[rs.length-1])+' ('+rs.length+' cuts)':' on strip '+rowName(rs[0])+' (1 cut)'); cl.appendChild(li); });
}
function tables(){
var pl=document.getElementById('partlist'); pl.innerHTML='';
function row(tb,cells,mcols){ var tr=document.createElement('tr'); cells.forEach(function(c,i){ var td=document.createElement('td'); if(mcols.indexOf(i)>=0) td.className='m'; if(c && c.nodeType) td.appendChild(c); else td.textContent=c; tr.appendChild(td); }); tb.appendChild(tr); }
var notes={U1:'6N137 in a DIP-8 socket. Notch toward strip U, pin 1 at hole U5. Pin 7 (enable) is tied to pin 8 by the U10–V10 link.',R1:'MIDI IN current limit. 3-hole span: stand it upright, or use a small ⅛ W part flat. If learning ever misses notes, use 150 Ω.',D1:'Band (cathode) on V4, the opto LED anode side. Stands upright (1-hole span).',R2:'Opto output pull-up to 3.3 V',C1:'6N137 supply bypass, right beside the chip: U11 is its 5 V (pin 8) strip, X11 its GND (pin 5) strip. Required. Fit it after the beep test.',R4:'MIDI OUT KIT, TX line (RC). Lies flat along strip X, across the cut at X23 (4-hole span, ¼ W fits). SEED hangs right above it.',R5:'MIDI OUT KIT, 3.3 V line (RA). ½ W: a mono plug in the jack shorts it to ground.',R6:'MIDI OUT SYNTH, TX line (RC)',R7:'MIDI OUT SYNTH, 3.3 V line (RA). ½ W, same reason as R5.'};
row(pl,['Pico 2W','2 × 20-pin female header','A13–T13 and A20–T20 (pins 1–20 down the left, 40–21 down the right)','USB end flush with the top edge of the board, past strip A'],[2]);
L.parts.forEach(function(p){ if(p.kind==='pico') return;
row(pl,[p.id,p.label,p.kind==='dip8'?'U5–X5, U8–X8':p.pins.map(function(pp){ return pos(pp.h); }).join(' – '),notes[p.id]||''],[2]); });
L.jumpers.forEach(function(j){ row(pl,['Link','wire',pos(j.a)+' – '+pos(j.b),j.n],[2]); });
var picoAt={}; L.parts[0].pins.forEach(function(pp){ picoAt[pp.h[1]+(pp.h[0]===12?'L':'R')]=pp.n; });
function pinFor(h){ var r=h[1]; if(r>=0 && r<=19) return picoAt[r+(h[0]<15?'L':'R')]; if(r===25) return '5 V strip'; if(r===26) return 'GND strip'; if(r===27) return '3V3 strip';
return {'0,24':'via R1 to opto','0,22':'opto cathode','25,23':'via R4 (10 Ω) from GP0','21,21':'via R5 (33 Ω) from 3V3','30,20':'via R6 (10 Ω) from GP4','30,21':'via R7 (33 Ω) from 3V3'}[h[0]+','+h[1]]||''; }
var wl=document.getElementById('wirelist'); wl.innerHTML='';
L.wires.forEach(function(w,i){ var s=document.createElement('span'); var sw=document.createElement('span'); sw.className='sw'; sw.style.background='var('+COL[w.col]+')'; s.appendChild(sw); s.appendChild(document.createTextNode(w.col));
row(wl,['P'+(i+1),pos(w.h),s,pinFor(w.h),w.to],[0,1]); });
}
function drawMatrix(){ // drawn from the BACK (lug side), so the columns are mirrored: col 4 on the left, KICK top-right
var svg=document.getElementById('matrix'); svg.innerHTML=''; svg.setAttribute('viewBox','0 0 700 330');
var C={y:css('--w-yellow'),g:css('--w-green'),ink:css('--ink'),muted:css('--muted'),part:css('--part'),line:css('--line')}, f=css('--f-mono');
var names=[['KICK','KICK 2','SNARE',null],['HAT','HAT 16','PERC','GHOST'],['BASS','MEL A','MEL B','PAD']];
var x0=110, dx=118, y0=84, dy=80, rowEnd=560;
function bxOf(c){ return x0+(3-c)*dx; }
for(var c=0;c<4;c++){ var cx=bxOf(c)-38; el('line',{x1:cx,y1:c===3?y0+dy-28:y0-10,x2:cx,y2:y0+2*dy+40,stroke:C.g,'stroke-width':3},svg);
el('text',{x:cx,y:y0+2*dy+60,'text-anchor':'middle','font-family':f,'font-size':12,'font-weight':700,fill:C.ink},svg,'Col '+(c+1)+' → '+H('P'+(32+c))); }
for(var r=0;r<3;r++){ var ry=y0+r*dy-18, left=bxOf(r===0?2:3)+9;
el('line',{x1:left,y1:ry,x2:rowEnd,y2:ry,stroke:C.y,'stroke-width':3},svg);
el('text',{x:rowEnd+6,y:ry+4,'font-family':f,'font-size':12,'font-weight':700,fill:C.ink},svg,'Row '+(r+1)+' → '+H('P'+(29+r)));
for(c=0;c<4;c++){ var bx=bxOf(c), by=y0+r*dy;
if(!names[r][c]){ el('rect',{x:bx-12,y:by-16,width:24,height:32,rx:4,fill:'none',stroke:C.muted,'stroke-width':1.2,'stroke-dasharray':'4 3'},svg);
el('text',{x:bx,y:by+4,'text-anchor':'middle','font-family':f,'font-size':10,fill:C.ink},svg,'RUN');
el('text',{x:bx,y:by+34,'text-anchor':'middle','font-family':f,'font-size':9,fill:C.muted},svg,'toggle, not in matrix'); continue; }
el('circle',{cx:bx,cy:by,r:17,fill:C.part},svg);
el('text',{x:bx,y:by+34,'text-anchor':'middle','font-family':f,'font-size':11,fill:C.muted},svg,names[r][c]);
var lRow=bx+9, lDio=bx-9, colX=bx-38;
el('circle',{cx:lRow,cy:by,r:3.2,fill:'#D4AF37'},svg); el('circle',{cx:lDio,cy:by,r:3.2,fill:'#D4AF37'},svg);
el('line',{x1:lRow,y1:by-3,x2:lRow,y2:ry,stroke:C.y,'stroke-width':2},svg);
el('line',{x1:lDio,y1:by,x2:colX,y2:by,stroke:'#9AA3AD','stroke-width':1.5},svg);
el('rect',{x:colX+4,y:by-4,width:18,height:8,rx:2,fill:'#D9663A'},svg); el('rect',{x:colX+4,y:by-4,width:4,height:8,fill:'#111'},svg);
}
}
el('text',{x:x0-60,y:22,'font-family':f,'font-size':12,'font-weight':700,fill:C.ink},svg,'Seen from the BACK (lug side): KICK is top-right.');
el('text',{x:x0-60,y:38,'font-family':f,'font-size':10,fill:C.muted},svg,'Diode band → column wire. Lid flipped left to right, back wall still at the top.');
}
function drawDin(){ // 3.5 mm TRS panel jacks, Type A, lugs seen from inside the box
var svg=document.getElementById('din'); svg.innerHTML='';
var f=css('--f-mono'), ink=css('--ink'), m=css('--muted');
var jacks=[{n:'IN',x:52,w:{T:['--w-blue','P2'],R:['--w-blue','P1']}},{n:'OUT KIT',x:150,w:{T:['--w-blue','P3'],R:['--w-red','P4'],S:['--w-black','P5']}},{n:'OUT SYNTH',x:248,w:{T:['--w-blue','P6'],R:['--w-red','P7'],S:['--w-black','P8']}}];
var LUG={T:[-20,'T·5'],R:[0,'R·4'],S:[20,'S·2']};
jacks.forEach(function(j){
el('rect',{x:j.x-30,y:30,width:60,height:34,rx:4,fill:'#2C3238'},svg);
el('circle',{cx:j.x,cy:47,r:9,fill:'none',stroke:'#9AA3AD','stroke-width':2},svg);
Object.keys(LUG).forEach(function(k){ var lx=j.x+LUG[k][0], used=j.w[k];
el('rect',{x:lx-3,y:64,width:6,height:12,fill:'#C9CFD5'},svg);
if(used){ el('line',{x1:lx,y1:76,x2:lx,y2:100,stroke:css(used[0]),'stroke-width':4,'stroke-linecap':'round'},svg);
el('text',{x:lx,y:112,'text-anchor':'middle','font-family':f,'font-size':11,'font-weight':700,fill:ink},svg,H(used[1])); }
else el('text',{x:lx,y:90,'text-anchor':'middle','font-family':f,'font-size':8,fill:m},svg,'—');
el('text',{x:lx,y:124,'text-anchor':'middle','font-family':f,'font-size':8,fill:m},svg,LUG[k][1]); });
el('text',{x:j.x,y:142,'text-anchor':'middle','font-family':f,'font-size':11,fill:ink},svg,j.n); });
el('text',{x:150,y:14,'text-anchor':'middle','font-family':f,'font-size':9,fill:m},svg,'Type A · T tip = pin 5 · R ring = 4 · S sleeve = 2');
}
function pinRow(id,pins,w){
var svg=document.getElementById(id); svg.innerHTML=''; var f=css('--f-mono'), ink=css('--ink');
var n=pins.length, sp=Math.min(36,260/n), x0=150-sp*(n-1)/2;
pins.forEach(function(p,i){ var x=x0+i*sp;
el('rect',{x:x-6,y:14,width:12,height:12,fill:'#111',stroke:'#D4AF37','stroke-width':1.5},svg);
el('line',{x1:x,y1:26,x2:x,y2:52,stroke:p[1]?css(p[1]):'none','stroke-width':4,'stroke-linecap':'round'},svg);
el('text',{x:x,y:10,'text-anchor':'middle','font-family':f,'font-size':n>6?8:9,fill:ink},svg,p[0]);
el('text',{x:x,y:68,'text-anchor':'middle','font-family':f,'font-size':10,'font-weight':700,fill:ink},svg,H(p[2]||'')); });
}
function drawMisc(){
var svg=document.getElementById('misc'); svg.innerHTML=''; var f=css('--f-mono'), ink=css('--ink'), m=css('--muted');
function pot(x,label,wp){ el('circle',{cx:x,cy:42,r:20,fill:'#2C3238'},svg); el('text',{x:x,y:14,'text-anchor':'middle','font-family':f,'font-size':10,fill:ink},svg,label);
[[-12,'--w-black','P25'],[0,'--w-blue',wp],[12,'--w-red','P24']].forEach(function(l){ el('rect',{x:x+l[0]-2.5,y:62,width:5,height:12,fill:'#C9CFD5'},svg); el('line',{x1:x+l[0],y1:74,x2:x+l[0],y2:96,stroke:css(l[1]),'stroke-width':4,'stroke-linecap':'round'},svg);
el('text',{x:x+l[0],y:108,'text-anchor':'middle','font-family':f,'font-size':9,'font-weight':700,fill:ink},svg,H(l[2])); }); }
pot(45,'ENERGY','P22'); pot(115,'DRIFT','P23');
el('circle',{cx:190,cy:42,r:16,fill:'#2C3238'},svg); el('text',{x:190,y:14,'text-anchor':'middle','font-family':f,'font-size':10,fill:ink},svg,'SEED');
[[-7,'--w-yellow','P26'],[7,'--w-black','P28']].forEach(function(l){ el('line',{x1:190+l[0],y1:58,x2:190+l[0],y2:96,stroke:css(l[1]),'stroke-width':4,'stroke-linecap':'round'},svg); el('text',{x:190+l[0],y:108,'text-anchor':'middle','font-family':f,'font-size':9,'font-weight':700,fill:ink},svg,H(l[2])); });
el('rect',{x:240,y:30,width:34,height:24,rx:3,fill:'#2C3238'},svg); el('text',{x:257,y:14,'text-anchor':'middle','font-family':f,'font-size':10,fill:ink},svg,'RUN');
[[-11,null,''],[0,'--w-yellow','P27'],[11,'--w-black','P28']].forEach(function(l){ el('rect',{x:257+l[0]-2.5,y:54,width:5,height:10,fill:'#C9CFD5'},svg); if(l[1]){ el('line',{x1:257+l[0],y1:64,x2:257+l[0],y2:96,stroke:css(l[1]),'stroke-width':4,'stroke-linecap':'round'},svg); el('text',{x:257+l[0],y:108,'text-anchor':'middle','font-family':f,'font-size':9,'font-weight':700,fill:ink},svg,H(l[2])); } });
el('text',{x:150,y:138,'text-anchor':'middle','font-family':f,'font-size':9,fill:m},svg,'lugs facing down, seen from the front');
}
/* ---------- Wire map: every panel wire, by part, with its board hole ---------- */
var WMAP=[ // [pad, part, lug, short label]
['P29','Buttons','Row 1 · KICK, KICK 2, SNARE','ROW 1'],['P30','Buttons','Row 2 · HAT, HAT 16, PERC, GHOST','ROW 2'],['P31','Buttons','Row 3 · BASS, MEL A, MEL B, PAD','ROW 3'],
['P32','Buttons','Col 1 · KICK, HAT, BASS (diode band side)','COL 1'],['P33','Buttons','Col 2 · KICK 2, HAT 16, MEL A','COL 2'],['P34','Buttons','Col 3 · SNARE, PERC, MEL B','COL 3'],['P35','Buttons','Col 4 · GHOST, PAD','COL 4'],
['P26','SEED','one lug','SEED'],['P27','RUN toggle','middle lug (it sits in the button grid, row 1 / col 4)','RUN'],['P28','SEED + RUN','ground: SEED other lug, RUN one outer lug','GND BUS'],
['P20','Encoder','VCC (3.3 V, never 5 V)','ENC VCC'],['P21','Encoder','GND','ENC GND'],['P19','Encoder','SW','ENC SW'],['P18','Encoder','SIB','ENC SIB'],['P17','Encoder','SIA','ENC SIA'],
['P22','ENERGY pot','middle lug','ENERGY'],['P23','DRIFT pot','middle lug','DRIFT'],['P24','Pots','right lugs, both (3.3 V)','POTS +'],['P25','Pots','left lugs, both (AGND)','POTS −'],
['P14','LCD','1 · VCC (3.3 V)','LCD VCC'],['P15','LCD','2 · GND','LCD GND'],['P10','LCD','3 · SCE','LCD SCE'],['P9','LCD','4 · RST','LCD RST'],['P11','LCD','5 · D/C','LCD D/C'],['P12','LCD','6 · DN (MOSI)','LCD DN'],['P13','LCD','7 · SCLK','LCD SCLK'],['P16','LCD','8 · LED, through a 330 Ω resistor (if dark, move to any AA hole)','LCD LED'],
['P2','MIDI IN jack','tip','IN tip'],['P1','MIDI IN jack','ring','IN ring'],
['P3','OUT KIT jack','tip','KIT tip'],['P4','OUT KIT jack','ring','KIT ring'],['P5','OUT KIT jack','sleeve','KIT slv'],
['P6','OUT SYNTH jack','tip','SYN tip'],['P7','OUT SYNTH jack','ring','SYN ring'],['P8','OUT SYNTH jack','sleeve','SYN slv']
];
function wireOf(p){ return L.wires[+p.slice(1)-1]; }
function drawMap(){
var svg=document.getElementById('wmap'); if(!svg) return; svg.innerHTML='';
var LM=10.5, RM=10.5, f=css('--f-mono'), ink=css('--ink');
svg.setAttribute('viewBox',(-LM)+' -3.2 '+(L.W+LM+RM)+' '+(L.H+4.6));
el('rect',{x:-0.8,y:-0.5,width:L.W+0.6,height:L.H+0.3,rx:0.4,fill:css('--board'),stroke:css('--board-edge'),'stroke-width':0.12,opacity:0.55},svg);
for(var r=0;r<L.H;r++) el('line',{x1:-0.4,y1:r,x2:L.W-0.6,y2:r,stroke:css('--copper'),'stroke-width':0.5,opacity:0.18},svg);
el('rect',{x:11.3,y:-0.55,width:8.4,height:20.1,rx:0.4,fill:css('--part'),opacity:0.85},svg);
el('text',{x:15.5,y:9.5,'text-anchor':'middle','font-family':f,'font-size':'1.1','font-weight':700,fill:css('--part-ink')},svg,'PICO');
el('text',{x:15.5,y:-1.2,'text-anchor':'middle','font-family':f,'font-size':'0.7',fill:css('--muted')},svg,'USB edge');
el('rect',{x:3.6,y:19.6,width:3.8,height:3.8,rx:0.2,fill:css('--part'),opacity:0.85},svg);
el('text',{x:5.5,y:21.8,'text-anchor':'middle','font-family':f,'font-size':'0.6',fill:css('--part-ink')},svg,'opto');
// strip letters on both sides, hole numbers along the bottom
for(r=0;r<L.H;r++){ el('text',{x:-1.0,y:r+0.22,'text-anchor':'end','font-family':f,'font-size':'0.5',fill:css('--muted')},svg,rowName(r)); el('text',{x:L.W-0.1,y:r+0.22,'font-family':f,'font-size':'0.5',fill:css('--muted')},svg,rowName(r)); }
for(var c=0;c<L.W;c+=2) el('text',{x:c,y:L.H+0.9,'text-anchor':'middle','font-family':f,'font-size':'0.5',fill:css('--muted')},svg,String(c+1));
var sides={L:[],R:[]};
WMAP.forEach(function(m){ var w=wireOf(m[0]); (w.h[0]<=12?sides.L:sides.R).push({m:m,w:w}); });
['L','R'].forEach(function(sd){
var list=sides[sd].sort(function(a,b){ return a.w.h[1]-b.w.h[1] || (sd==='L'?b.w.h[0]-a.w.h[0]:a.w.h[0]-b.w.h[0]); }), last=-9, k;
for(k=0;k<list.length;k++){ list[k].ly=Math.max(list[k].w.h[1],last+1.05); last=list[k].ly; }
var cap=L.H-0.6; // keep labels inside the board's height: push the stack up from the bottom
for(k=list.length-1;k>=0;k--){ list[k].ly=Math.min(list[k].ly,cap); cap=list[k].ly-1.05; }
list.forEach(function(o){
var h=o.w.h, col=css(COL[o.w.col]), ly=o.ly;
var lx=sd==='L'?-1.9:L.W+0.9;
el('polyline',{points:h[0]+','+h[1]+' '+(sd==='L'?-0.6:L.W-0.4)+','+ly+' '+lx+','+ly,fill:'none',stroke:col,'stroke-width':0.13,opacity:0.9},svg);
el('circle',{cx:h[0],cy:h[1],r:0.36,fill:col,stroke:'#fff','stroke-width':0.08},svg);
var t=el('text',{x:sd==='L'?lx-0.25:lx+0.25,y:ly+0.25,'text-anchor':sd==='L'?'end':'start','font-family':f,'font-size':'0.72',fill:ink},svg);
var a=document.createElementNS(NS,'tspan'); a.setAttribute('font-weight','700'); a.textContent=o.m[3]+' '; t.appendChild(a);
var b=document.createElementNS(NS,'tspan'); b.setAttribute('fill',css('--accent')); b.setAttribute('font-weight','700'); b.textContent=pos(h); t.appendChild(b);
});
});
}
function checklist(){
var tb=document.getElementById('wcheck'); if(!tb) return; tb.innerHTML='';
var done={}; try{ done=JSON.parse(localStorage.getItem('seedbox.wires')||'{}')||{}; }catch(e){}
var prev='';
WMAP.forEach(function(m){
var w=wireOf(m[0]), tr=document.createElement('tr'), part=m[1]===prev?'':m[1]; prev=m[1];
if(part) tr.className='grp';
var td0=document.createElement('td'), cb=document.createElement('input'); cb.type='checkbox'; cb.checked=!!done[m[0]]; cb.setAttribute('aria-label','Done: '+m[1]+' '+m[2]);
cb.addEventListener('change',function(){ done[m[0]]=cb.checked; tr.classList.toggle('done',cb.checked); try{ localStorage.setItem('seedbox.wires',JSON.stringify(done)); }catch(e){} });
td0.appendChild(cb); tr.appendChild(td0); tr.classList.toggle('done',cb.checked);
var td1=document.createElement('td'); td1.className='part'; td1.textContent=part; tr.appendChild(td1);
var td2=document.createElement('td'); td2.textContent=m[2]; tr.appendChild(td2);
var td3=document.createElement('td'), sw=document.createElement('span'); sw.className='sw'; sw.style.background='var('+COL[w.col]+')'; td3.appendChild(sw); td3.appendChild(document.createTextNode(w.col)); tr.appendChild(td3);
var td4=document.createElement('td'); td4.className='hole'; td4.textContent=pos(w.h); tr.appendChild(td4);
tb.appendChild(tr);
});
}
function all(){
drawMap(); checklist(); drawTop(); drawBottom(); tables(); drawMatrix(); drawDin();
pinRow('lcd',[['1 VCC','--w-red','P14'],['2 GND','--w-black','P15'],['3 SCE','--w-blue','P10'],['4 RST','--w-blue','P9'],['5 D/C','--w-blue','P11'],['6 DN','--w-blue','P12'],['7 SCLK','--w-blue','P13'],['8 LED','--w-red','P16']]);
pinRow('enc',[['VCC','--w-red','P20'],['GND','--w-black','P21'],['SW','--w-green','P19'],['SIB','--w-green','P18'],['SIA','--w-green','P17']]);
drawMisc();
}
all();
try{ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change',all); }catch(e){}
})();