app
Board to Molecule
Public Made by Adomby adom
Turn any KiCad, Fusion/EAGLE, or Altium board into an Adom molecule: wings plus MP1-MP4 machine pins, written back in the board's own format.
main
Colby Knox
1.1.0: every molecule gets large machine pins on the 32 mm grid; gallery rebuilt; corrected notes on kicad-to-molecule
c794385
4d ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Board to Molecule 3D</title>
<style>
:root { --bg: #0b0f14; }
html, body { margin: 0; height: 100%; background: var(--bg); overflow: hidden; }
#host { position: absolute; inset: 0; }
</style>
<script>
// Node-style globals the viewer bundle's inspector deps expect, set before loading it.
window.process = window.process || { env: { NODE_ENV: "production" } };
window.global = window.global || window;
</script>
</head>
<body>
<div id="host"></div>
<script type="module">
// One Adom 3D viewer per document: the viewer keeps its engine, scene and camera in
// page-wide statics, so a compare view puts each model in its own frame and links
// the cameras through the parent page.
const VIEWER = 'https://wiki.adom.inc/static/vendor/adom-3d-viewer-babylon9/adom-3d-viewer-babylon9.esm.js';
const q = new URLSearchParams(location.search);
const id = q.get('id') || 'v';
const post = (msg) => parent.postMessage({ source: 'b2m-3d', id, ...msg }, '*');
try {
await import(VIEWER);
const viewer = window.Adom3DViewerBabylon9.init(document.getElementById('host'), {
zUp: true, showViewCube: q.get('cube') !== '0', showGround: true,
});
await viewer.whenReady();
await viewer.loadModel(q.get('model'));
viewer.frameModel(0.8);
const cam = viewer.getCamera();
// Let the framing animation finish before taking or applying a shared pose.
await new Promise(r => setTimeout(r, 1200));
let applying = 0;
const pose = () => ({ alpha: cam.alpha, beta: cam.beta, radius: cam.radius });
cam.onViewMatrixChangedObservable.add(() => { if (!applying) post({ type: 'camera', pose: pose() }); });
addEventListener('message', (e) => {
const m = e.data;
if (!m || m.source !== 'b2m-parent') return;
if (m.type === 'camera' || m.type === 'view') {
const p = m.pose;
// A pose from the other frame must not echo back; a button press should.
if (m.type === 'camera') applying++;
if (p.alpha != null) cam.alpha = p.alpha;
if (p.beta != null) cam.beta = p.beta;
if (p.radius != null) cam.radius = p.radius;
cam.inertialAlphaOffset = 0; cam.inertialBetaOffset = 0; cam.inertialRadiusOffset = 0;
if (m.type === 'camera') requestAnimationFrame(() => requestAnimationFrame(() => applying--));
} else if (m.type === 'home') {
viewer.frameModel(0.8);
}
});
post({ type: 'ready', pose: pose(), report: viewer.getReadyReport() });
} catch (e) {
post({ type: 'error', message: String(e && e.message || e) });
}
</script>
</body>
</html>