project
12 V to 5 V / 1 A Buck Molecule (TPS54202)
Public Unreviewedby John Lauer
An independently designed 12 V to 5 V, 1 A synchronous buck molecule (TI TPS54202), with calculations, ngspice and PSpice simulation, KiCad 10 schematic and board, and the board laid out and analysed with adom-aiflow.
← Commit history
fusion-360/widget-test.htmldeleted−129@@ -1,129 +0,0 @@-<!doctype html><html><head><meta charset="utf-8"></head><body>-<adom-3d src="/john/buck-12v5v-molecule/render/fusion-360/buck-fusion-360.glb" poster="/john/buck-12v5v-molecule/render/fusion-360/img/3d-poster.jpg" heading="The finished board, exported from Fusion 360" caption="test"></adom-3d>-<script>/*!- * <adom-3d> - an interactive 3D view of any GLB on a wiki page, in the canonical Adom 3D Viewer.- *- * Drop-in (wiki README):- * ::adom-3d{src="/OWNER/SLUG/render/board.glb" poster="/OWNER/SLUG/render/board.jpg" heading="The finished board"}- *- * - src: the GLB (absolute path on the wiki, usually the page's own render route). Publish it WITHOUT Draco:- * the widget frame's connect-src does not reach Babylon's decoder CDN, so a Draco GLB cannot decode here.- * - poster: optional still shown until the reader asks for 3D (a render or screenshot of the same model).- * - heading: optional title over the view; caption: optional line under it.- *- * Nothing heavy loads on the page path (adom/wiki#1292): the wiki puts every widget in a click-to-load slot, so- * this frame only exists once the reader asked for it, and the model then loads straight away (one click, not- * two). Unload, scrolling it well offscreen or leaving the page disposes the- * viewer and releases the WebGL context; Load 3D model brings it back. The model is fetched as bytes and handed to loadModelBytes, and the- * GLB's embedded textures are given out as data: URLs, because the frame's img-src forbids blob:.- */-(() => {- const VIEWER = 'https://wiki.adom.inc/static/vendor/adom-3d-viewer-babylon9/adom-3d-viewer-babylon9.esm.js';- const esc = s => String(s == null ? '' : s).replace(/[&<>"]/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c]));-- // The glTF loader turns embedded images into blob: URLs, which this frame's CSP blocks. Remember each Blob's- // bytes and hand out an equivalent data: URL instead. Installed once, only when a reader loads a model.- let shimmed = false;- function shimBlobUrls() {- if (shimmed) return; shimmed = true;- const NativeBlob = window.Blob;- function TrackedBlob(parts, opts) { const b = new NativeBlob(parts || [], opts); try { b.__parts = parts; b.__type = (opts && opts.type) || ''; } catch (e) {} return b; }- TrackedBlob.prototype = NativeBlob.prototype; Object.setPrototypeOf(TrackedBlob, NativeBlob); window.Blob = TrackedBlob;- const create = URL.createObjectURL.bind(URL), revoke = URL.revokeObjectURL.bind(URL);- URL.createObjectURL = o => {- if (!o || !o.__parts) return create(o);- let s = '';- for (const p of o.__parts) {- const u = typeof p === 'string' ? new TextEncoder().encode(p) : p instanceof ArrayBuffer ? new Uint8Array(p) : ArrayBuffer.isView(p) ? new Uint8Array(p.buffer, p.byteOffset, p.byteLength) : new Uint8Array(0);- for (let i = 0; i < u.length; i += 0x8000) s += String.fromCharCode.apply(null, u.subarray(i, i + 0x8000));- }- return 'data:' + (o.__type || 'application/octet-stream') + ';base64,' + btoa(s);- };- URL.revokeObjectURL = u => { if (typeof u === 'string' && u.startsWith('blob:')) revoke(u); };- }- // the frame is an opaque origin: storage throws, and the viewer reads its preferences on init- function shimStorage() {- try { window.localStorage; } catch (e) {- let m = {};- Object.defineProperty(window, 'localStorage', { value: { getItem: k => (k in m ? m[k] : null), setItem: (k, v) => { m[k] = String(v); }, removeItem: k => { delete m[k]; }, clear: () => { m = {}; } } });- }- window.process = window.process || { env: { NODE_ENV: 'production' } };- window.global = window.global || window;- }-- class Adom3D extends HTMLElement {- connectedCallback() {- if (this._init) return; this._init = true;- this.attachShadow({ mode: 'open' });- this._src = this.getAttribute('src');- this._poster = this.getAttribute('poster');- this._idle();- this._io = new IntersectionObserver(es => {- for (const e of es) if (!e.isIntersecting && this._viewer && !this._loading) this._unload('offscreen');- }, { rootMargin: '600px 0px' });- this._io.observe(this);- if (this._src) this._load(); // the wiki slot already was the reader's click- }- disconnectedCallback() { this._io && this._io.disconnect(); this._unload('removed'); }-- _frame(stage, foot) {- const h = this.getAttribute('heading'), c = this.getAttribute('caption');- this.shadowRoot.innerHTML = `<style>- :host { display: block; font: 13px/1.5 Satoshi, -apple-system, 'Segoe UI', sans-serif; color: #e6edf3; }- .card { background: #0d1117; border: 1px solid #30363d; border-radius: 10px; overflow: hidden; }- .h { padding: 10px 14px; font: 600 14px/1.3 'Familjen Grotesk', -apple-system, sans-serif; border-bottom: 1px solid #30363d; }- .stage { position: relative; aspect-ratio: 16 / 9; min-height: 320px; background: linear-gradient(180deg, #1e2a3d 0%, #1e2a3d 20%, #0a121f 100%); }- .stage img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }- .over { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; }- button { font: 600 14px/1 inherit; padding: 11px 18px; border-radius: 8px; border: 1px solid #00b8b1; background: rgba(13, 17, 23, 0.82); color: #00b8b1; cursor: pointer; transition: background .12s ease, color .12s ease, transform .06s ease; }- button:hover { background: #00b8b1; color: #0d1117; }- button:active { transform: translateY(1px) scale(.98); }- button:focus-visible { outline: 2px solid #00b8b1; outline-offset: 3px; }- button:disabled { opacity: .7; cursor: progress; }- .foot { display: flex; align-items: center; gap: 10px; padding: 8px 14px; border-top: 1px solid #30363d; color: #8b949e; font-size: 12px; }- .foot .sp { flex: 1; }- .foot button { font-size: 12px; padding: 5px 10px; }- .err { color: #f85149; }- ::slotted([slot=v]) { position: absolute; inset: 0; }- </style>- <div class="card">${h ? `<div class="h">${esc(h)}</div>` : ''}<div class="stage">${stage}</div>- <div class="foot"><span>${esc(c || '')}</span><span class="sp"></span>${foot || ''}</div></div>`;- }- _idle(note) {- this._frame(`${this._poster ? `<img src="${esc(new URL(this._poster, location.href).href)}" alt="${esc(this.getAttribute('heading') || '3D model')}" loading="lazy">` : ''}- <div class="over"><button id="go" type="button">Load 3D model</button></div>`, note ? `<span class="err">${esc(note)}</span>` : '');- const go = this.shadowRoot.getElementById('go');- if (!this._src) { go.disabled = true; go.textContent = 'No src: point me at a GLB'; return; }- go.addEventListener('click', () => this._load());- }- async _load() {- const go = this.shadowRoot.getElementById('go'); go.disabled = true; go.textContent = 'Loading...';- this._loading = true;- try {- shimStorage(); shimBlobUrls();- const res = await fetch(new URL(this._src, location.href).href);- if (!res.ok) throw new Error('could not fetch the model (' + res.status + ')');- const bytes = new Uint8Array(await res.arrayBuffer());- await import(VIEWER);- this._frame('<slot name="v"></slot>', '<button id="off" type="button">Unload</button>');- this._host = document.createElement('div'); this._host.slot = 'v'; this.appendChild(this._host);- this._viewer = window.Adom3DViewerBabylon9.init(this._host, { zUp: true, showViewCube: true });- await this._viewer.loadModelBytes(bytes, { extension: '.glb' });- this._viewer.frameModel();- this.shadowRoot.getElementById('off').addEventListener('click', () => this._unload());- this.dispatchEvent(new CustomEvent('modelready', { detail: { bytes: bytes.length }, bubbles: true, composed: true }));- } catch (e) {- console.warn(e); this._unload(); this._idle(String(e && e.message || e).slice(0, 160));- } finally { this._loading = false; }- }- _unload(why) {- if (this._viewer) { try { this._viewer.destroy(); } catch (e) {} this._viewer = null; }- if (this._host) { this._host.remove(); this._host = null; }- if (why !== 'removed' && this.shadowRoot && !this.shadowRoot.getElementById('go')) this._idle();- }- // for AIs and tests: what the widget is showing- selfCheck() { return { src: this._src, loaded: !!this._viewer, report: this._viewer && this._viewer.getReadyReport ? this._viewer.getReadyReport() : null }; }- }- if (!customElements.get('adom-3d')) customElements.define('adom-3d', Adom3D);-})();-</script></body></html>