skill
Adom SF Convert
Public Made by Adomby adom
Native Rust converter: EAGLE/Fusion .lbr + Altium .SchLib/.PcbLib → KiCad, rendering each format's own geometry.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
// build-variants.js — generate adom-wiki-hero heroes across two axes: LAYOUT × THEME.
// Usage:
// node build-variants.js -> writes the curated showcase set (see COMBOS)
// node build-variants.js <layout> <theme> -> one hero, e.g. "bleedRight pcb"
// node build-variants.js name <comboName> -> one named combo from COMBOS
// LAYOUTS: bottom | mirror | bleedRight | contained
// THEMES: midnight | pcb | onion | pill | gradient
// Brand assets (fonts, wordmark, Kickstand tiles) are bundled under assets/, referenced relatively.
const fs = require('fs');
const path = require('path');
const DIR = __dirname;
const WORDMARK = fs.readFileSync(path.join(DIR, 'assets', 'adom-white.svg'), 'utf8')
.replace(/<\?xml[^>]*\?>/, '').replace(/<style>[\s\S]*?<\/style>/, '').replace(/class="cls-1"/g, 'fill="#fff"');
// recolor a currentColor tile SVG and return a CSS background data-URI
function tile(name, color) {
const svg = fs.readFileSync(path.join(DIR, 'assets', 'tiling', name), 'utf8').replace(/currentColor/g, color);
return `url("data:image/svg+xml;base64,${Buffer.from(svg).toString('base64')}")`;
}
// ---- content (adom-sfconvert hero) ----
const C = {
headline: 'Adom<br><span class="accent">SF Convert</span>',
sub: 'EAGLE/Fusion <b>.lbr</b> and Altium <b>.SchLib/.PcbLib</b> <b>→ KiCad</b> — each format rendered from its <b>own geometry</b> as a native SVG. No KiCad install.',
chip: 'EDA Converter', prompt: 'convert this EAGLE .lbr to KiCad',
url: 'wiki.adom.inc/adom/adom-sfconvert',
winlabel: 'adom-sfconvert · ADS1263 footprint · four-source compare · Adom webview',
shot: 'file:///tmp/herowork2/shot.png',
};
// ---- THEMES: background + texture overlay + text colors ----
const THEMES = {
midnight: {
bg: `radial-gradient(1200px 800px at 88% -10%, rgba(0,184,177,.22), transparent 60%),
radial-gradient(900px 700px at -5% 110%, rgba(140,107,247,.18), transparent 55%),
linear-gradient(155deg,#0a0e14 0%,#0d1117 45%,#071318 100%)`,
tex: `background:${tile('dot-grid.svg', '#ffffff')} 0 0/24px repeat;opacity:.05;
-webkit-mask-image:linear-gradient(115deg,transparent 0%,#000 48%);mask-image:linear-gradient(115deg,transparent 0%,#000 48%)`,
text: '#e6edf3', sub: '#aeb8c4', chipB: 'rgba(0,184,177,.34)', chipF: 'rgba(0,184,177,.07)', chipT: '#7fe3dd', accent: true,
},
// PCB traces — Kickstand "ethereal circuit field" on deep brand teal
pcb: {
bg: `radial-gradient(1000px 760px at 86% -5%, rgba(0,184,177,.28), transparent 60%),
linear-gradient(160deg,#022a2b 0%,#003c3f 46%,#021a1c 100%)`,
tex: `background:${tile('pcb-trace.svg', '#8FD3D4')} center/170px repeat;opacity:.16;
-webkit-mask-image:linear-gradient(115deg,transparent 6%,#000 52%);mask-image:linear-gradient(115deg,transparent 6%,#000 52%)`,
text: '#eafdfb', sub: '#a9d6d2', chipB: 'rgba(143,211,212,.40)', chipF: 'rgba(0,184,177,.10)', chipT: '#8fd3d4', accent: true,
},
// Onion corner — signature concentric-arc motif on solid navy (deck "substance" slide)
onion: {
bg: `radial-gradient(900px 700px at 80% -10%, rgba(100,171,255,.16), transparent 60%),
linear-gradient(160deg,#021a36 0%,#00204f 50%,#01122b 100%)`,
tex: `background:${tile('onion-corner.svg', '#8FD3D4')} right bottom/62% no-repeat;opacity:.5`,
text: '#eaf2ff', sub: '#a9c0e0', chipB: 'rgba(100,171,255,.40)', chipF: 'rgba(100,171,255,.10)', chipT: '#9fc4ff', accent: true,
},
// Pill field on navy
pill: {
bg: `radial-gradient(900px 700px at 85% 0%, rgba(100,171,255,.18), transparent 60%),
linear-gradient(160deg,#001a3f 0%,#00204f 50%,#001129 100%)`,
tex: `background:${tile('pill-field.svg', '#64ABFF')} center/64px repeat;opacity:.5;
-webkit-mask-image:linear-gradient(115deg,transparent 4%,#000 50%);mask-image:linear-gradient(115deg,transparent 4%,#000 50%)`,
text: '#eaf2ff', sub: '#a9c0e0', chipB: 'rgba(100,171,255,.40)', chipF: 'rgba(100,171,255,.10)', chipT: '#9fc4ff', accent: true,
},
// Brand gradient — the "wow"/cover-slide look; left scrim keeps copy readable
gradient: {
bg: `linear-gradient(90deg, rgba(5,8,12,.82) 0%, rgba(5,8,12,.42) 42%, rgba(5,8,12,.08) 70%),
radial-gradient(800px 600px at 90% 0%, rgba(255,255,255,.12), transparent 55%),
linear-gradient(115deg,#00b8b1 0%,#0061ef 52%,#8c6bf7 100%)`,
tex: ``,
text: '#ffffff', sub: '#d7e2ee', chipB: 'rgba(255,255,255,.40)', chipF: 'rgba(255,255,255,.10)', chipT: '#ffffff', accent: true,
},
};
// ---- LAYOUTS: window position/shape + text side ----
const LAYOUTS = {
bottom: { side: 'left', win: 'right:72px;top:280px;width:806px;border-radius:16px 16px 0 0', imgH: 760 },
mirror: { side: 'right', win: 'left:72px;top:280px;width:806px;border-radius:16px 16px 0 0', imgH: 760 },
bleedRight: { side: 'left', win: 'right:-74px;top:104px;width:900px;border-radius:16px 0 0 16px', imgH: 812 },
contained: { side: 'left', win: 'right:80px;top:150px;width:752px;border-radius:16px', imgH: 672 },
};
function html(L, T) {
const left = L.side === 'left';
return `<!DOCTYPE html><html><head><meta charset="utf-8">
<style>
@font-face{font-family:'Familjen Grotesk';font-weight:700;font-display:block;src:url('assets/fonts/familjen-grotesk-700-normal.woff2') format('woff2')}
@font-face{font-family:'Satoshi';font-weight:400;font-display:block;src:url('assets/fonts/satoshi-400-normal.woff2') format('woff2')}
@font-face{font-family:'Satoshi';font-weight:500;font-display:block;src:url('assets/fonts/satoshi-500-normal.woff2') format('woff2')}
*{margin:0;padding:0;box-sizing:border-box}
html,body{width:1600px;height:1000px;overflow:hidden}
body{font-family:'Satoshi',sans-serif;color:${T.text};position:relative;background:${T.bg};}
.tex{position:absolute;inset:0;z-index:0;${T.tex}}
.zone{position:absolute;inset:0;padding:80px 92px 0;z-index:3;display:flex;flex-direction:column}
.top{display:flex;align-items:flex-start;justify-content:space-between}
.wordmark svg{height:44px;width:auto;display:block}
.chip{border:1px solid ${T.chipB};background:${T.chipF};border-radius:999px;padding:9px 17px;font-size:14px;
letter-spacing:2.5px;text-transform:uppercase;color:${T.chipT};display:inline-flex;align-items:center;gap:9px;font-weight:600}
.chip .dot{width:8px;height:8px;border-radius:50%;background:#00e6dc;box-shadow:0 0 10px #00e6dc}
.col{max-width:520px;${left ? '' : 'margin-left:auto;text-align:right;display:flex;flex-direction:column;align-items:flex-end'}}
h1{font-family:'Familjen Grotesk',sans-serif;font-weight:700;font-size:68px;line-height:1.02;letter-spacing:-1.8px;color:${T.text};margin-top:46px;margin-bottom:22px}
h1 .accent{${T.accent ? 'background:linear-gradient(100deg,#00e6dc,#39b8ff 60%,#8c6bf7);-webkit-background-clip:text;background-clip:text;color:transparent' : 'color:' + T.text}}
.sub{font-size:23px;line-height:1.5;color:${T.sub};max-width:500px;margin-bottom:30px}
.sub b{color:${T.text};font-weight:500}
.prompt{display:inline-flex;align-items:center;gap:12px;background:rgba(255,255,255,.06);border:1px solid rgba(0,230,220,.30);
border-radius:14px;padding:15px 20px;font-size:19px;color:#e3eaf2}
.prompt .q{color:#00e6dc;font-weight:700}.prompt .ask{color:#9aa6b5;font-size:15px;margin-left:6px}
.url{position:absolute;${left ? 'left:92px' : 'right:92px'};bottom:54px;z-index:3;color:#00e6dc;font-weight:600;font-size:19px;font-family:'Familjen Grotesk',sans-serif}
.window{position:absolute;${L.win};overflow:hidden;z-index:1;
box-shadow:0 28px 80px rgba(0,0,0,.62), 0 0 0 1px rgba(255,255,255,.07), 0 0 130px rgba(0,184,177,.07)}
.chrome{height:42px;background:#1b2128;display:flex;align-items:center;padding-left:18px;border-bottom:1px solid #232a33}
.chrome .ct{color:#8b949e;font-size:15px;margin-right:auto}
.winbtns{display:flex;height:100%}.winbtns .b{width:48px;height:100%;display:flex;align-items:center;justify-content:center;color:#b9c2cd}
.winbtns .min i{display:block;width:12px;height:1.5px;background:#b9c2cd}
.winbtns .max i{display:block;width:11px;height:11px;border:1.5px solid #b9c2cd;border-radius:1px}
.winbtns .cls{font-family:Arial,sans-serif;font-size:18px;line-height:1}
.window img{width:100%;height:${L.imgH}px;display:block;object-fit:cover;object-position:top left}
</style></head><body>
<div class="tex"></div>
<div class="window">
<div class="chrome"><span class="ct">${C.winlabel}</span>
<div class="winbtns"><span class="b min"><i></i></span><span class="b max"><i></i></span><span class="b cls">✕</span></div></div>
<img src="${C.shot}">
</div>
<div class="zone">
<div class="top"><div class="wordmark">${WORDMARK}</div><div class="chip"><span class="dot"></span>${C.chip}</div></div>
<div class="col">
<h1>${C.headline}</h1>
<div class="sub">${C.sub}</div>
<div class="prompt"><span class="q">"${C.prompt}"</span><span class="ask">— just ask Claude</span></div>
</div>
</div>
<div class="url">${C.url}</div>
</body></html>`;
}
// curated showcase set: name -> [layout, theme]
const COMBOS = {
'midnight': ['bottom', 'midnight'],
'mirror': ['mirror', 'midnight'],
'pcb': ['bottom', 'pcb'],
'onion': ['bottom', 'onion'],
'pill': ['bottom', 'pill'],
'gradient': ['bottom', 'gradient'],
'bleed-right': ['bleedRight', 'midnight'],
'bleed-right-pcb': ['bleedRight', 'pcb'],
'contained': ['contained', 'midnight'],
'contained-gradient': ['contained', 'gradient'],
};
function write(name, layoutKey, themeKey) {
const L = LAYOUTS[layoutKey], T = THEMES[themeKey];
if (!L || !T) throw new Error('bad layout/theme: ' + layoutKey + '/' + themeKey);
const out = path.join(DIR, `variant-${name}.html`);
fs.writeFileSync(out, html(L, T));
console.log('wrote', out, `(${layoutKey} × ${themeKey})`);
}
const a = process.argv.slice(2);
if (a.length === 0) {
for (const [name, [l, t]] of Object.entries(COMBOS)) write(name, l, t);
} else if (a[0] === 'name') {
const [l, t] = COMBOS[a[1]]; write(a[1], l, t);
} else {
write(`${a[0]}-${a[1]}`, a[0], a[1]);
}