← Commit history

ds2sf provenance widget + datasheet-cover thumbnail + named-node board GLB (pad_N/solder_N) + per-node tooltip sidecar + timeline 3d viewer

Ray ·3b09a6056f ·3mo ago ·parent c637fd7
6 files changed +573−28
3d.html+73−25
@@ -16,6 +16,14 @@ body{background:var(--bg);color:var(--ink);font-family:'Satoshi',system-ui,sans- .stage{flex:1;min-height:0;position:relative;overflow:hidden;background:var(--bg)} .stage canvas{width:100%;height:100%;display:block;outline:none;touch-action:none} .ph{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:var(--mut);font-size:12px}+.timeline{display:flex;align-items:center;gap:9px;padding:7px 11px;border-top:1px solid var(--edge);flex:none;background:var(--bg)}+.tl-play{width:26px;height:26px;flex:none;border-radius:50%;border:1px solid var(--acc);background:rgba(0,184,176,.12);color:var(--acc);cursor:pointer;font-size:10px;line-height:1;display:flex;align-items:center;justify-content:center}+.tl-play:hover{background:rgba(0,184,176,.2)}+.tl-track{position:relative;flex:1;display:flex;height:24px;border-radius:6px;overflow:hidden;background:#0d1117;border:1px solid var(--edge);cursor:pointer;touch-action:none}+.tl-seg{display:flex;align-items:center;justify-content:center;border-right:1px solid var(--edge);font-size:9.5px;color:var(--mut);text-transform:uppercase;letter-spacing:.05em;user-select:none;min-width:0}+.tl-seg:last-child{border-right:0}+.tl-seg.on{color:var(--ink);background:rgba(0,184,176,.12)}+.tl-head{position:absolute;top:0;bottom:0;left:0;width:2px;background:var(--acc);box-shadow:0 0 8px var(--acc);pointer-events:none} </style></head><body> <div class=bar><span class=h>3D model</span><span class=sp></span>   <button class="lyrtog on" data-mesh="solder"><span class=d style="background:#c9ccd1"></span>Solder</button>@@ -25,6 +33,15 @@ body{background:var(--bg);color:var(--ink);font-family:'Satoshi',system-ui,sans-   <button class="act plain" id=reset>Reset</button> </div> <div class=stage id=stage><div class=ph id=ph>loading 3D&hellip;</div></div>+<div class=timeline id=timeline hidden>+  <button class="tl-play" id=tl-play title="Play the lifecycle">&#9654;</button>+  <div class=tl-track id=tl-track>+    <div class=tl-seg style="flex:34"><span>Place</span></div>+    <div class=tl-seg style="flex:34"><span>Reflow</span></div>+    <div class=tl-seg style="flex:32"><span>Power-on</span></div>+    <div class=tl-head id=tl-head></div>+  </div>+</div> <script>var O$e=Object.defineProperty;var R$e=(B9,j1,z9)=>j1 in B9?O$e(B9,j1,{enumerable:!0,configurable:!0,writable:!0,value:z9}):B9[j1]=z9;var mr=(B9,j1,z9)=>R$e(B9,typeof j1!="symbol"?j1+"":j1,z9);(function(){"use strict";function B9(a,e){for(var t=0;t<e.length;t++){const i=e[t];if(typeof i!="string"&&!Array.isArray(i)){for(const s in i)if(s!=="default"&&!(s in a)){const r=Object.getOwnPropertyDescriptor(i,s);r&&Object.defineProperty(a,s,r.get?r:{enumerable:!0,get:()=>i[s]})}}}return Object.freeze(Object.defineProperty(a,Symbol.toStringTag,{value:"Module"}))}function j1(){}function z9(a){return a()}function Aue(){return Object.create(null)}function QI(a){a.forEach(z9)}function Cue(a){return typeof a=="function"}function xue(a,e){return a!=a?e==e:a!==e||a&&typeof a=="object"||typeof a=="function"}function $Ie(a){return Object.keys(a).length===0}function ePe(a,...e){if(a==null){for(const i of e)i(void 0);return j1}const t=a.subscribe(...e);return t.unsubscribe?()=>t.unsubscribe():t}function tPe(a){let e;return ePe(a,t=>e=t)(),e}function Mc(a,e){a.appendChild(e)}function iPe(a,e,t){const i=sPe(a);if(!i.getElementById(e)){const s=$2("style");s.id=e,s.textContent=t,rPe(i,s)}}function sPe(a){if(!a)return document;const e=a.getRootNode?a.getRootNode():a.ownerDocument;return e&&e.host?e:a.ownerDocument}function rPe(a,e){return Mc(a.head||a,e),e.sheet}function JI(a,e,t){a.insertBefore(e,t||null)}function F9(a){a.parentNode&&a.parentNode.removeChild(a)}function $2(a){return document.createElement(a)}function VV(a){return document.createElementNS("http://www.w3.org/2000/svg",a)}function JY(a){return document.createTextNode(a)}function k9(){return JY(" ")}function U9(a,e,t,i){return a.addEventListener(e,t,i),()=>a.removeEventListener(e,t,i)}function bue(a){return function(e){return e.stopPropagation(),a.call(this,e)}}function ya(a,e,t){t==null?a.removeAttribute(e):a.getAttribute(e)!==t&&a.setAttribute(e,t)}function nPe(a){return Array.from(a.childNodes)}function $I(a,e,t){a.classList.toggle(e,!!t)}let nw;function aw(a){nw=a}function Sue(){if(!nw)throw new Error("Function called outside component initialization");return nw}function aPe(a){Sue().$$.on_mount.push(a)}function oPe(a){Sue().$$.on_destroy.push(a)}function lPe(a,e){const t=a.$$.callbacks[e.type];t&&t.slice().forEach(i=>i.call(this,e))}const eP=[],AV=[];let tP=[];const yue=[],cPe=Promise.resolve();let $Y=!1;function uPe(){$Y||($Y=!0,cPe.then(Mue))}function eX(a){tP.push(a)}const tX=new Set;let iP=0;function Mue(){if(iP!==0)return;const a=nw;do{try{for(;iP<eP.length;){const e=eP[iP];iP++,aw(e),hPe(e.$$)}}catch(e){throw eP.length=0,iP=0,e}for(aw(null),eP.length=0,iP=0;AV.length;)AV.pop()();for(let e=0;e<tP.length;e+=1){const t=tP[e];tX.has(t)||(tX.add(t),t())}tP.length=0}while(eP.length);for(;yue.length;)yue.pop()();$Y=!1,tX.clear(),aw(a)}function hPe(a){if(a.fragment!==null){a.update(),QI(a.before_update);const e=a.dirty;a.dirty=[-1],a.fragment&&a.fragment.p(a.ctx,e),a.after_update.forEach(eX)}}function dPe(a){const e=[],t=[];tP.forEach(i=>a.indexOf(i)===-1?e.push(i):t.push(i)),t.forEach(i=>i()),tP=e}const fPe=new Set;function pPe(a,e){a&&a.i&&(fPe.delete(a),a.i(e))}function mPe(a,e,t){const{fragment:i,after_update:s}=a.$$;i&&i.m(e,t),eX(()=>{const r=a.$$.on_mount.map(z9).filter(Cue);a.$$.on_destroy?a.$$.on_destroy.push(...r):QI(r),a.$$.on_mount=[]}),s.forEach(eX)}function gPe(a,e){const t=a.$$;t.fragment!==null&&(dPe(t.after_update),QI(t.on_destroy),t.fragment&&t.fragment.d(e),t.on_destroy=t.fragment=null,t.ctx=[])}function _Pe(a,e){a.$$.dirty[0]===-1&&(eP.push(a),uPe(),a.$$.dirty.fill(0)),a.$$.dirty[e/31|0]|=1<<e%31}function vPe(a,e,t,i,s,r,n=null,o=[-1]){const l=nw;aw(a);const c=a.$$={fragment:null,ctx:[],props:r,update:j1,not_equal:s,bound:Aue(),on_mount:[],on_destroy:[],on_disconnect:[],before_update:[],after_update:[],context:new Map(e.context||(l?l.$$.context:[])),callbacks:Aue(),dirty:o,skip_bound:!1,root:e.target||l.$$.root};n&&n(c.root);let u=!1;if(c.ctx=t?t(a,e.props||{},(f,p,...m)=>{const _=m.length?m[0]:p;return c.ctx&&s(c.ctx[f],c.ctx[f]=_)&&(!c.skip_bound&&c.bound[f]&&c.bound[f](_),u&&_Pe(a,f)),p}):[],c.update(),u=!0,QI(c.before_update),c.fragment=i?i(c.ctx):!1,e.target){if(e.hydrate){const f=nPe(e.target);c.fragment&&c.fragment.l(f),f.forEach(F9)}else c.fragment&&c.fragment.c();e.intro&&pPe(a.$$.fragment),mPe(a,e.target,e.anchor),Mue()}aw(l)}class APe{constructor(){mr(this,"$$");mr(this,"$$set")}$destroy(){gPe(this,1),this.$destroy=j1}$on(e,t){if(!Cue(t))return j1;const i=this.$$.callbacks[e]||(this.$$.callbacks[e]=[]);return i.push(t),()=>{const s=i.indexOf(t);s!==-1&&i.splice(s,1)}}$set(e){this.$$set&&!$Ie(e)&&(this.$$.skip_bound=!0,this.$$set(e),this.$$.skip_bound=!1)}}const CPe="4";typeof window<"u"&&(window.__svelte||(window.__svelte={v:new Set})).v.add(CPe);const xPe=typeof WeakRef<"u";class iX{constructor(e,t=!1,i,s){this.initialize(e,t,i,s)}initialize(e,t=!1,i,s){return this.mask=e,this.skipNextObservers=t,this.target=i,this.currentTarget=s,this}}class Eue{constructor(e,t,i=null){this.callback=e,this.mask=t,this.scope=i,this._willBeUnregistered=!1,this.unregisterOnNextCall=!1,this._remove=null}remove(){this._remove&&this._remove()}}class xe{static FromPromise(e,t){const i=new xe;return e.then(s=>{i.notifyObservers(s)}).catch(s=>{if(t)t.notifyObservers(s);else throw s}),i}get observers(){return this._observers}constructor(e,t=!1){this.notifyIfTriggered=t,this._observers=new Array,this._numObserversMarkedAsDeleted=0,this._hasNotified=!1,this._eventState=new iX(0),e&&(this._onObserverAdded=e)}add(e,t=-1,i=!1,s=null,r=!1){if(!e)return null;const n=new Eue(e,t,s);n.unregisterOnNextCall=r,i?this._observers.unshift(n):this._observers.push(n),this._onObserverAdded&&this._onObserverAdded(n),this._hasNotified&&this.notifyIfTriggered&&this._lastNotifiedValue!==void 0&&this.notifyObserver(n,this._lastNotifiedValue);const o=xPe?new WeakRef(this):{deref:()=>this};return n._remove=()=>{const l=o.deref();l&&l._remove(n)},n}addOnce(e){return this.add(e,void 0,void 0,void 0,!0)}remove(e){return e?(e._remove=null,this._observers.indexOf(e)!==-1?(this._deferUnregister(e),!0):!1):!1}removeCallback(e,t){for(let i=0;i<this._observers.length;i++){const s=this._observers[i];if(!s._willBeUnregistered&&s.callback===e&&(!t||t===s.scope))return this._deferUnregister(s),!0}return!1}_deferUnregister(e){e._willBeUnregistered||(this._numObserversMarkedAsDeleted++,e.unregisterOnNextCall=!1,e._willBeUnregistered=!0,setTimeout(()=>{this._remove(e)},0))}_remove(e,t=!0){if(!e)return!1;const i=this._observers.indexOf(e);return i!==-1?(t&&this._numObserversMarkedAsDeleted--,this._observers.splice(i,1),!0):!1}makeObserverTopPriority(e){this._remove(e,!1),this._observers.unshift(e)}makeObserverBottomPriority(e){this._remove(e,!1),this._observers.push(e)}notifyObservers(e,t=-1,i,s,r){if(this.notifyIfTriggered&&(this._hasNotified=!0,this._lastNotifiedValue=e),!this._observers.length)return!0;const n=this._eventState;n.mask=t,n.target=i,n.currentTarget=s,n.skipNextObservers=!1,n.lastReturnValue=e,n.userInfo=r;for(const o of this._observers)if(!o._willBeUnregistered&&(o.mask&t&&(o.unregisterOnNextCall&&this._deferUnregister(o),o.scope?n.lastReturnValue=o.callback.apply(o.scope,[e,n]):n.lastReturnValue=o.callback(e,n)),n.skipNextObservers))return!1;return!0}notifyObserver(e,t,i=-1){if(this.notifyIfTriggered&&(this._hasNotified=!0,this._lastNotifiedValue=t),e._willBeUnregistered)return;const s=this._eventState;s.mask=i,s.skipNextObservers=!1,e.unregisterOnNextCall&&this._deferUnregister(e),e.callback(t,s)}hasObservers(){return this._observers.length-this._numObserversMarkedAsDeleted>0}clear(){for(;this._observers.length;){const e=this._observers.pop();e&&(e._remove=null)}this._onObserverAdded=null,this._numObserversMarkedAsDeleted=0,this.cleanLastNotifiedState()}cleanLastNotifiedState(){this._hasNotified=!1,this._lastNotifiedValue=void 0}clone(){const e=new xe;return e._observers=this._observers.slice(0),e}hasSpecificMask(e=-1){for(const t of this._observers)if(t.mask&e||t.mask===e)return!0;return!1}}function Il(){return typeof window<"u"}function LT(){return typeof navigator<"u"}function H6(){return typeof document<"u"}function ow(a){let e="",t=a.firstChild;for(;t;)t.nodeType===3&&(e+=t.textContent),t=t.nextSibling;return e}const bPe={IsWindowObjectExist:Il,IsNavigatorAvailable:LT,IsDocumentAvailable:H6,GetDOMTextContent:ow};class de{static _CheckLimit(e,t){let i=de._LogLimitOutputs[e];return i?i.current++:(i={limit:t,current:1},de._LogLimitOutputs[e]=i),i.current<=i.limit}static _GenerateLimitMessage(e,t=1){const i=de._LogLimitOutputs[e];if(!i||!de.MessageLimitReached)return;const s=this._Levels[t];i.current===i.limit&&de[s.name](de.MessageLimitReached.replace(/%LIMIT%/g,""+i.limit).replace(/%TYPE%/g,s.name??""))}static _AddLogEntry(e){de._LogCache=e+de._LogCache,de.OnNewCacheEntry&&de.OnNewCacheEntry(e)}static _FormatMessage(e){const t=s=>s<10?"0"+s:""+s,i=new Date;return"["+t(i.getHours())+":"+t(i.getMinutes())+":"+t(i.getSeconds())+"]: "+e}static _LogDisabled(e,t){}static _LogEnabled(e=1,t,i){const s=Array.isArray(t)?t[0]:t;if(i!==void 0&&!de._CheckLimit(s,i))return;const r=de._FormatMessage(s),n=this._Levels[e],o=Array.isArray(t)?t.slice(1):[];n.logFunc&&n.logFunc("BJS - "+r,...o);const l=`<div style='color:${n.color}'>${r}</div><br>`;de._AddLogEntry(l),de._GenerateLimitMessage(s,e)}static get LogCache(){return de._LogCache}static ClearLogCache(){de._LogCache="",de._LogLimitOutputs={},de.errorsCount=0}static set LogLevels(e){de.Log=de._LogDisabled,de.Warn=de._LogDisabled,de.Error=de._LogDisabled,[de.MessageLogLevel,de.WarningLogLevel,de.ErrorLogLevel].forEach(t=>{if((e&t)===t){const i=this._Levels[t];de[i.name]=de._LogEnabled.bind(de,t)}})}}de.NoneLogLevel=0,de.MessageLogLevel=1,de.WarningLogLevel=2,de.ErrorLogLevel=4,de.AllLogLevel=7,de.MessageLimitReached="Too many %TYPE%s (%LIMIT%), no more %TYPE%s will be reported for this message.",de._LogCache="",de._LogLimitOutputs={},de._Levels=[{},{color:"white",logFunc:console.log,name:"Log"},{color:"orange",logFunc:console.warn,name:"Warn"},{},{color:"red",logFunc:console.error,name:"Error"}],de.errorsCount=0,de.Log=de._LogEnabled.bind(de,de.MessageLogLevel),de.Warn=de._LogEnabled.bind(de,de.WarningLogLevel),de.Error=de._LogEnabled.bind(de,de.ErrorLogLevel);const Tue=(a,e,t)=>!a||a.getClassName&&a.getClassName()==="Mesh"?null:a.getClassName&&(a.getClassName()==="SubMesh"||a.getClassName()==="PhysicsBody")?a.clone(e):a.clone?a.clone():Array.isArray(a)?a.slice():t&&typeof a=="object"?{...a}:null;function SPe(a){const e=[];do Object.getOwnPropertyNames(a).forEach(function(t){e.indexOf(t)===-1&&e.push(t)});while(a=Object.getPrototypeOf(a));return e}class nu{static DeepCopy(e,t,i,s,r=!1){const n=SPe(e);for(const o of n){if(o[0]==="_"&&(!s||s.indexOf(o)===-1)||o.endsWith("Observable")||i&&i.indexOf(o)!==-1)continue;const l=e[o],c=typeof l;if(c!=="function")try{if(c==="object")if(l instanceof Uint8Array)t[o]=Uint8Array.from(l);else if(l instanceof Array){if(t[o]=[],l.length>0)if(typeof l[0]=="object")for(let u=0;u<l.length;u++){const f=Tue(l[u],t,r);t[o].indexOf(f)===-1&&t[o].push(f)}else t[o]=l.slice(0)}else t[o]=Tue(l,t,r);else t[o]=l}catch(u){de.Warn(u.message)}}}}class lr{static get Now(){return Il()&&window.performance&&window.performance.now?window.performance.now():Date.now()}}const Lue={};function as(a,e=!1){if(!(e&&Lue[a]))return Lue[a]=!0,`${a} needs to be imported before as it contains a side-effect required by your code.`}function yPe(){return typeof _native<"u"&&_native.XMLHttpRequest?new _native.XMLHttpRequest:new XMLHttpRequest}class ha{constructor(){this._xhr=yPe(),this._requestURL=""}static get IsCustomRequestAvailable(){return Object.keys(ha.CustomRequestHeaders).length>0||ha.CustomRequestModifiers.length>0}get requestURL(){return this._requestURL}_injectCustomRequestHeaders(){if(!this._shouldSkipRequestModifications(this._requestURL))for(const e in ha.CustomRequestHeaders){const t=ha.CustomRequestHeaders[e];t&&this._xhr.setRequestHeader(e,t)}}_shouldSkipRequestModifications(e){return ha.SkipRequestModificationForBabylonCDN&&(e.includes("preview.babylonjs.com")||e.includes("cdn.babylonjs.com"))}get onprogress(){return this._xhr.onprogress}set onprogress(e){this._xhr.onprogress=e}get readyState(){return this._xhr.readyState}get status(){return this._xhr.status}get statusText(){return this._xhr.statusText}get response(){return this._xhr.response}get responseURL(){return this._xhr.responseURL}get responseText(){return this._xhr.responseText}get responseType(){return this._xhr.responseType}set responseType(e){this._xhr.responseType=e}get timeout(){return this._xhr.timeout}set timeout(e){this._xhr.timeout=e}addEventListener(e,t,i){this._xhr.addEventListener(e,t,i)}removeEventListener(e,t,i){this._xhr.removeEventListener(e,t,i)}abort(){this._xhr.abort()}send(e){ha.CustomRequestHeaders&&this._injectCustomRequestHeaders(),this._xhr.send(e)}open(e,t){for(const i of ha.CustomRequestModifiers){if(this._shouldSkipRequestModifications(t))return;t=i(this._xhr,t)||t}t=t.replace("file:http:","http:"),t=t.replace("file:https:","https:"),this._requestURL=t,this._xhr.open(e,t,!0)}setRequestHeader(e,t){this._xhr.setRequestHeader(e,t)}getResponseHeader(e){return this._xhr.getResponseHeader(e)}}ha.CustomRequestHeaders={},ha.CustomRequestModifiers=new Array,ha.SkipRequestModificationForBabylonCDN=!0;class ei{static get LastCreatedEngine(){return this.Instances.length===0?null:this.Instances[this.Instances.length-1]}static get LastCreatedScene(){return this._LastCreatedScene}}ei.Instances=[],ei.OnEnginesDisposedObservable=new xe,ei._LastCreatedScene=null,ei.UseFallbackTexture=!0,ei.FallbackTexture="";class j9{}j9.FilesToLoad={};class Iue{static ExponentialBackoff(e=3,t=500){return(i,s,r)=>s.status!==0||r>=e||i.indexOf("file:")!==-1?-1:Math.pow(2,r)*t}}class py extends Error{}py._setPrototypeOf=Object.setPrototypeOf||((a,e)=>(a.__proto__=e,a));const Xx={MeshInvalidPositionsError:0,UnsupportedTextureError:1e3,GLTFLoaderUnexpectedMagicError:2e3,SceneLoaderError:3e3,LoadFileError:4e3,RequestFileError:4001,ReadFileError:4002};class Y6 extends py{constructor(e,t,i){super(e),this.errorCode=t,this.innerError=i,this.name="RuntimeError",py._setPrototypeOf(this,Y6.prototype)}}class sX extends py{constructor(e="Operation aborted"){super(e),this.name="AbortError",py._setPrototypeOf(this,sX.prototype)}}const Pue=(a,e)=>a.endsWith(e),Oue=(a,e)=>a?a.startsWith(e):!1,rX=a=>{if(typeof TextDecoder<"u")return new TextDecoder().decode(a);let e="";for(let t=0;t<a.byteLength;t++)e+=String.fromCharCode(a[t]);return e},lw=a=>{const e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";let t="",i,s,r,n,o,l,c,u=0;const f=ArrayBuffer.isView(a)?new Uint8Array(a.buffer,a.byteOffset,a.byteLength):new Uint8Array(a);for(;u<f.length;)i=f[u++],s=u<f.length?f[u++]:Number.NaN,r=u<f.length?f[u++]:Number.NaN,n=i>>2,o=(i&3)<<4|s>>4,l=(s&15)<<2|r>>6,c=r&63,isNaN(s)?l=c=64:isNaN(r)&&(c=64),t+=e.charAt(n)+e.charAt(o)+e.charAt(l)+e.charAt(c);return t},WV=a=>atob(a),cw=a=>{const e=WV(a),t=e.length,i=new Uint8Array(new ArrayBuffer(t));for(let s=0;s<t;s++)i[s]=e.charCodeAt(s);return i.buffer},Rue=(a,e)=>{let t=String(a);for(;t.length<e;)t="0"+t;return t},MPe={EndsWith:Pue,StartsWith:Oue,Decode:rX,EncodeArrayBufferToBase64:lw,DecodeBase64ToString:WV,DecodeBase64ToBinary:cw,PadNumber:Rue},EPe="attribute",TPe="varying";class uw{constructor(){this.children=[]}isValid(e){return!0}process(e,t){var s,r,n,o,l,c;let i="";if(this.line){let u=this.line;const f=t.processor;if(f){f.lineProcessor&&(u=f.lineProcessor(u,t.isFragment,t.processingContext));const p=((s=t.processor)==null?void 0:s.attributeKeywordName)??EPe,m=t.isFragment&&((r=t.processor)!=null&&r.varyingFragmentKeywordName)?(n=t.processor)==null?void 0:n.varyingFragmentKeywordName:!t.isFragment&&((o=t.processor)!=null&&o.varyingVertexKeywordName)?(l=t.processor)==null?void 0:l.varyingVertexKeywordName:TPe;!t.isFragment&&f.attributeProcessor&&this.line.startsWith(p)?u=f.attributeProcessor(this.line,e,t.processingContext):f.varyingProcessor&&((c=f.varyingCheck)!=null&&c.call(f,this.line,t.isFragment)||!f.varyingCheck&&this.line.startsWith(m))?u=f.varyingProcessor(this.line,t.isFragment,e,t.processingContext):f.uniformProcessor&&f.uniformRegexp&&f.uniformRegexp.test(this.line)?t.lookForClosingBracketForUniformBuffer||(u=f.uniformProcessor(this.line,t.isFragment,e,t.processingContext)):f.uniformBufferProcessor&&f.uniformBufferRegexp&&f.uniformBufferRegexp.test(this.line)?t.lookForClosingBracketForUniformBuffer||(u=f.uniformBufferProcessor(this.line,t.isFragment,t.processingContext),t.lookForClosingBracketForUniformBuffer=!0):f.textureProcessor&&f.textureRegexp&&f.textureRegexp.test(this.line)?u=f.textureProcessor(this.line,t.isFragment,e,t.processingContext):(f.uniformProcessor||f.uniformBufferProcessor)&&this.line.startsWith("uniform")&&!t.lookForClosingBracketForUniformBuffer&&(/uniform\s+(?:(?:highp)?|(?:lowp)?)\s*(\S+)\s+(\S+)\s*;/.test(this.line)?f.uniformProcessor&&(u=f.uniformProcessor(this.line,t.isFragment,e,t.processingContext)):f.uniformBufferProcessor&&(u=f.uniformBufferProcessor(this.line,t.isFragment,t.processingContext),t.lookForClosingBracketForUniformBuffer=!0)),t.lookForClosingBracketForUniformBuffer&&this.line.indexOf("}")!==-1&&(t.lookForClosingBracketForUniformBuffer=!1,f.endOfUniformBufferProcessor&&(u=f.endOfUniformBufferProcessor(this.line,t.isFragment,t.processingContext)))}i+=u+` `}return this.children.forEach(u=>{i+=u.process(e,t)}),this.additionalDefineKey&&(e[this.additionalDefineKey]=this.additionalDefineValue||"true"),i}}class LPe{constructor(){this._lines=[]}get currentLine(){return this._lines[this.lineIndex]}get canRead(){return this.lineIndex<this._lines.length-1}set lines(e){this._lines.length=0;for(const t of e){if(!t||t==="\r")continue;if(t[0]==="#"){this._lines.push(t);continue}const i=t.trim();if(!i)continue;if(i.startsWith("//")){this._lines.push(t);continue}const s=i.indexOf(";");if(s===-1)this._lines.push(i);else if(s===i.length-1)i.length>1&&this._lines.push(i);else{const r=t.split(";");for(let n=0;n<r.length;n++){let o=r[n];o&&(o=o.trim(),o&&this._lines.push(o+(n!==r.length-1?";":"")))}}}}}class nX extends uw{process(e,t){for(let i=0;i<this.children.length;i++){const s=this.children[i];if(s.isValid(e))return s.process(e,t)}return""}}class IPe extends uw{isValid(e){return this.testExpression.isTrue(e)}}class Zo{isTrue(e){return!0}static postfixToInfix(e){const t=[];for(const i of e)if(Zo._OperatorPriority[i]===void 0)t.push(i);else{const s=t[t.length-1],r=t[t.length-2];t.length-=2,t.push(`(${r}${i}${s})`)}return t[t.length-1]}static infixToPostfix(e){const t=Zo._InfixToPostfixCache.get(e);if(t)return t.accessTime=Date.now(),t.result;if(!e.includes("&&")&&!e.includes("||")&&!e.includes(")")&&!e.includes("("))return[e];const i=[];let s=-1;const r=()=>{u=u.trim(),u!==""&&(i.push(u),u="")},n=f=>{s<Zo._Stack.length-1&&(Zo._Stack[++s]=f)},o=()=>Zo._Stack[s],l=()=>s===-1?"!!INVALID EXPRESSION!!":Zo._Stack[s--];let c=0,u="";for(;c<e.length;){const f=e.charAt(c),p=c<e.length-1?e.substring(c,2+c):"";if(f==="(")u="",n(f);else if(f===")"){for(r();s!==-1&&o()!=="(";)i.push(l());l()}else if(Zo._OperatorPriority[p]>1){for(r();s!==-1&&Zo._OperatorPriority[o()]>=Zo._OperatorPriority[p];)i.push(l());n(p),c++}else u+=f;c++}for(r();s!==-1;)o()==="("?l():i.push(l());return Zo._InfixToPostfixCache.size>=Zo.InfixToPostfixCacheLimitSize&&Zo.ClearCache(),Zo._InfixToPostfixCache.set(e,{result:i,accessTime:Date.now()}),i}static ClearCache(){const e=Array.from(Zo._InfixToPostfixCache.entries()).sort((t,i)=>t[1].accessTime-i[1].accessTime);for(let t=0;t<Zo.InfixToPostfixCacheCleanupSize;t++)Zo._InfixToPostfixCache.delete(e[t][0])}}Zo.InfixToPostfixCacheLimitSize=5e4,Zo.InfixToPostfixCacheCleanupSize=25e3,Zo._InfixToPostfixCache=new Map,Zo._OperatorPriority={")":0,"(":1,"||":2,"&&":3},Zo._Stack=["","","","","","","","","","","","","","","","","","","",""];class HV extends Zo{constructor(e,t=!1){super(),this.define=e,this.not=t}isTrue(e){let t=e[this.define]!==void 0;return this.not&&(t=!t),t}}class PPe extends Zo{isTrue(e){return this.leftOperand.isTrue(e)||this.rightOperand.isTrue(e)}}class OPe extends Zo{isTrue(e){return this.leftOperand.isTrue(e)&&this.rightOperand.isTrue(e)}}class RPe extends Zo{constructor(e,t,i){super(),this.define=e,this.operand=t,this.testValue=i}isTrue(e){let t=e[this.define];t===void 0&&(t=this.define);let i=!1;const s=parseInt(t),r=parseInt(this.testValue);switch(this.operand){case">":i=s>r;break;case"<":i=s<r;break;case"<=":i=s<=r;break;case">=":i=s>=r;break;case"==":i=s===r;break;case"!=":i=s!==r;break}return i}}const YV={};function Due(a,e,t=""){return t+(e?e+` `:"")+a}function Nue(a,e,t,i,s,r,n){const o=n||YV.loadFile;if(o)return o(a,e,t,i,s,r);throw as("FileTools")}function wue(a,e,t,i){if(a){e?a.IS_NDC_HALF_ZRANGE="":delete a.IS_NDC_HALF_ZRANGE,t?a.USE_REVERSE_DEPTHBUFFER="":delete a.USE_REVERSE_DEPTHBUFFER,i?a.USE_EXACT_SRGB_CONVERSIONS="":delete a.USE_EXACT_SRGB_CONVERSIONS;return}else{let s="";return e&&(s+="#define IS_NDC_HALF_ZRANGE"),t&&(s&&(s+=`@@ -41571,17 +41588,18 @@ function onReady(s){       byName(s,re).forEach(function(m){ m.setEnabled(on); });     });   });-  var pb=document.getElementById('play'); if(pb) pb.addEventListener('click',function(){ playLifecycle(s); });+  initLifecycle(s); wireTimeline();+  var pb=document.getElementById('play'); if(pb) pb.addEventListener('click',lcToggle);   var rb=document.getElementById('reset'); if(rb) rb.addEventListener('click',function(){ try{v.goHome&&v.goHome();}catch(_){} });-  if((location.hash||'').indexOf('play')>=0) setTimeout(function(){playLifecycle(s);},500);+  if((location.hash||'').indexOf('play')>=0) setTimeout(function(){lcPlay();},500);   if((location.hash||'').indexOf('low')>=0){ try{var c=v.getCamera(); if(c){c.beta=1.46; c.radius=c.radius*0.32;}}catch(_){} }   if((location.hash||'').indexOf('demo')>=0){     try{var c=v.getCamera(); if(c){c.beta=1.05; c.radius=c.radius*1.12;}}catch(_){}-    var reps=6,i=0; (function loop(){ if(i++>=reps)return; playLifecycle(s); setTimeout(loop,9800); })();+    var reps=6,i=0; (function loop(){ if(i++>=reps)return; lcPlay(); setTimeout(loop,9800); })();   }   if((location.hash||'').indexOf('vid')>=0){   // single play from a nice angle, delayed so recording can start first     try{var c=v.getCamera(); if(c){c.beta=1.08; c.radius=c.radius*0.9;}}catch(_){}-    setTimeout(function(){ playLifecycle(s); }, 3800);+    setTimeout(function(){ lcPlay(); }, 3800);   } } @@ -41617,29 +41635,59 @@ var animing=false; function setEmis(mm,r,g,b){mm.forEach(function(m){try{if(m.material&&m.material.emissiveColor&&B.Color3)m.material.emissiveColor=new B.Color3(r,g,b);}catch(_){}});} function tween(dur,upd,done){var t0=performance.now();(function st(now){var t=Math.min(1,(now-t0)/dur);upd(t);if(t<1)requestAnimationFrame(st);else if(done)done();})(t0);} function easeIO(t){return t<0.5?4*t*t*t:1-Math.pow(-2*t+2,3)/2;}-function playLifecycle(s){-  if(animing||!B.Vector3)return; animing=true;-  var pb=document.getElementById('play'); if(pb)pb.disabled=true;-  var chip=byName(s,RE.chip), sol=byName(s,RE.solder), solBtn=document.querySelector('.lyrtog[data-mesh="solder"]');+// ---- lifecycle as a scrubbable TIMELINE (the "mini movie": place -> reflow -> power-on) ----+// John's ask: 10 datasheet pages compressed into one 3D viewer with a timeline the+// user enjoys watching. applyLifecycle(t) maps global t in [0,1] to chip position ++// solder + emissive across three "chapters", so it can be played OR scrubbed.+var _lc = null;   // { chip, sol, lift, solBtn } captured once the model is ready+function initLifecycle(s){+  var chip=byName(s,RE.chip), sol=byName(s,RE.solder);+  if(!chip.length){ return; }   var cb=boundsOf(chip); var lift=cb?Math.max(cb.hi.x-cb.lo.x, cb.hi.y-cb.lo.y)*0.55:0.004;   chip.forEach(function(m){ if(!m.__oz){m.computeWorldMatrix(true); m.__op=m.getAbsolutePosition().clone(); m.__oz=1;} });-  function place(f){ chip.forEach(function(m){ try{m.setAbsolutePosition(new B.Vector3(m.__op.x, m.__op.y, m.__op.z+lift*f));}catch(_){} }); }-  function solOn(on){ sol.forEach(function(m){m.setEnabled(on);}); if(solBtn)solBtn.classList.toggle('on',on); }-  function fin(){ place(0); setEmis(chip,0,0,0); setEmis(sol,0,0,0); animing=false; if(pb)pb.disabled=false; }-  place(0); solOn(true);-  tween(1000, function(t){ place(easeIO(t)); }, function(){                 // 1) lift the chip up-    setTimeout(function(){ solOn(false);                                     // 2) solder off-      setTimeout(function(){ solOn(true);                                    //    solder back on-        setTimeout(function(){-          tween(1400, function(t){ place(1-easeIO(t)); }, function(){        // 3) lower onto the solder-            tween(1600, function(t){ var g=Math.sin(t*Math.PI); setEmis(sol,0.95*g,0.30*g,0); setEmis(chip,0.26*g,0.08*g,0); }, function(){ setEmis(sol,0,0,0); setEmis(chip,0,0,0);  // 4) slow reflow glow-              tween(1700, function(t){ var p=Math.sin(t*Math.PI); setEmis(chip,0,0.5*p,0.48*p); }, fin);   // 5) slow power-on pulse-            });-          });-        }, 700);-      }, 800);-    }, 700);-  });+  _lc={chip:chip, sol:sol, lift:lift, solBtn:document.querySelector('.lyrtog[data-mesh="solder"]')};+  var tl=document.getElementById('timeline'); if(tl)tl.hidden=false;+  applyLifecycle(0);+}+function _place(f){ if(!_lc)return; _lc.chip.forEach(function(m){ try{m.setAbsolutePosition(new B.Vector3(m.__op.x, m.__op.y, m.__op.z+_lc.lift*f));}catch(_){} }); }+function _solOn(on){ if(!_lc)return; _lc.sol.forEach(function(m){m.setEnabled(on);}); if(_lc.solBtn)_lc.solBtn.classList.toggle('on',on); }+function applyLifecycle(t){+  if(!_lc||!B.Vector3)return; t=Math.max(0,Math.min(1,t));+  if(t<0.34){ var u=t/0.34; _place(1-easeIO(u)); _solOn(true); setEmis(_lc.chip,0,0,0); setEmis(_lc.sol,0,0,0); }         // Place: descend onto the pads+  else if(t<0.68){ var u=(t-0.34)/0.34; _place(0); _solOn(true); var g=Math.sin(u*Math.PI); setEmis(_lc.sol,0.95*g,0.30*g,0); setEmis(_lc.chip,0.26*g,0.08*g,0); } // Reflow: solder glows+  else { var u=(t-0.68)/0.32; _place(0); _solOn(true); setEmis(_lc.sol,0,0,0); var p=Math.min(1,u*1.6); setEmis(_lc.chip,0,0.42*p,0.40*p); }                       // Power-on: steady glow, held+  _tlPaint(t);+}+// player + scrubber+var LC_DUR=5200, _lcT=0, _lcPlaying=false, _lcRAF=0, _lcLast=0;+function _lcStop(){ _lcPlaying=false; if(_lcRAF)cancelAnimationFrame(_lcRAF); _lcRAF=0; _tlBtn(); }+function lcPlay(){+  if(!_lc)return;+  if(_lcT>=1)_lcT=0;+  _lcPlaying=true; _lcLast=performance.now(); _tlBtn();+  (function step(now){+    if(!_lcPlaying)return;+    _lcT+=(now-_lcLast)/LC_DUR; _lcLast=now;+    if(_lcT>=1){ _lcT=1; applyLifecycle(1); _lcStop(); return; }+    applyLifecycle(_lcT); _lcRAF=requestAnimationFrame(step);+  })(performance.now());+}+function lcToggle(){ if(_lcPlaying)_lcStop(); else lcPlay(); }+function lcSeek(t){ _lcStop(); _lcT=Math.max(0,Math.min(1,t)); applyLifecycle(_lcT); }+function _tlPaint(t){+  var head=document.getElementById('tl-head'); if(head)head.style.left=(t*100)+'%';+  var idx=t<0.34?0:(t<0.68?1:2);+  [].slice.call(document.querySelectorAll('.tl-seg')).forEach(function(el,i){ el.classList.toggle('on', i===idx); });+}+function _tlBtn(){ var b=document.getElementById('tl-play'); if(b)b.innerHTML=_lcPlaying?'&#10073;&#10073;':'&#9654;'; }+function wireTimeline(){+  var tlp=document.getElementById('tl-play'); if(tlp)tlp.addEventListener('click',lcToggle);+  var trk=document.getElementById('tl-track'); if(!trk)return;+  var scrubbing=false;+  function seek(e){ var r=trk.getBoundingClientRect(); lcSeek((e.clientX-r.left)/r.width); }+  trk.addEventListener('pointerdown',function(e){ scrubbing=true; try{trk.setPointerCapture(e.pointerId);}catch(_){} seek(e); });+  trk.addEventListener('pointermove',function(e){ if(scrubbing)seek(e); });+  function end(){ scrubbing=false; } trk.addEventListener('pointerup',end); trk.addEventListener('pointerleave',end); }  // ---- cross-highlight bus: 3D receives pin hovers and lights the matching lead ----
STM32F103C8T6-tooltips.jsonadded+452
@@ -0,0 +1,452 @@+{+  "mpn": "STM32F103C8T6",+  "schema": "adom-node-tooltips@1",+  "source": "ds2sf symbol extract",+  "nodeCount": 99,+  "nodes": {+    "pad_1": {+      "label": "Pin 1 · VBAT (Power in)",+      "type": "power_in",+      "why": "Backup battery supply for RTC and backup registers."+    },+    "solder_1": {+      "label": "Solder joint · pin 1 (VBAT)",+      "why": "Reflowed solder bonding pin 1's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_2": {+      "label": "Pin 2 · PC13-TAMPER-RTC (I/O)",+      "type": "bidirectional",+      "why": "GPIO port C bit 13, muxed with TAMPER input and RTC output."+    },+    "solder_2": {+      "label": "Solder joint · pin 2 (PC13-TAMPER-RTC)",+      "why": "Reflowed solder bonding pin 2's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_3": {+      "label": "Pin 3 · PC14-OSC32_IN (I/O)",+      "type": "bidirectional",+      "why": "GPIO port C bit 14, muxed with 32 kHz LSE oscillator input (OSC32_IN)."+    },+    "solder_3": {+      "label": "Solder joint · pin 3 (PC14-OSC32_IN)",+      "why": "Reflowed solder bonding pin 3's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_4": {+      "label": "Pin 4 · PC15-OSC32_OUT (I/O)",+      "type": "bidirectional",+      "why": "GPIO port C bit 15, muxed with 32 kHz LSE oscillator output (OSC32_OUT)."+    },+    "solder_4": {+      "label": "Solder joint · pin 4 (PC15-OSC32_OUT)",+      "why": "Reflowed solder bonding pin 4's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_5": {+      "label": "Pin 5 · PD0-OSC_IN (I/O)",+      "type": "bidirectional",+      "why": "HSE crystal oscillator input (OSC_IN) after reset; remappable to GPIO PD0 by software."+    },+    "solder_5": {+      "label": "Solder joint · pin 5 (PD0-OSC_IN)",+      "why": "Reflowed solder bonding pin 5's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_6": {+      "label": "Pin 6 · PD1-OSC_OUT (I/O)",+      "type": "bidirectional",+      "why": "HSE crystal oscillator output (OSC_OUT) after reset; remappable to GPIO PD1 by software."+    },+    "solder_6": {+      "label": "Solder joint · pin 6 (PD1-OSC_OUT)",+      "why": "Reflowed solder bonding pin 6's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_7": {+      "label": "Pin 7 · NRST (I/O)",+      "type": "bidirectional",+      "why": "Active-low bidirectional device reset."+    },+    "solder_7": {+      "label": "Solder joint · pin 7 (NRST)",+      "why": "Reflowed solder bonding pin 7's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_8": {+      "label": "Pin 8 · VSSA (Power in)",+      "type": "power_in",+      "why": "Analog ground reference for ADC, reset block, PLL, and analog peripherals."+    },+    "solder_8": {+      "label": "Solder joint · pin 8 (VSSA)",+      "why": "Reflowed solder bonding pin 8's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_9": {+      "label": "Pin 9 · VDDA (Power in)",+      "type": "power_in",+      "why": "Analog supply for ADC, reset block, PLL, and analog I/O."+    },+    "solder_9": {+      "label": "Solder joint · pin 9 (VDDA)",+      "why": "Reflowed solder bonding pin 9's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_10": {+      "label": "Pin 10 · PA0-WKUP (I/O)",+      "type": "bidirectional",+      "why": "GPIO port A bit 0, 5 V-tolerant when configured as digital input."+    },+    "solder_10": {+      "label": "Solder joint · pin 10 (PA0-WKUP)",+      "why": "Reflowed solder bonding pin 10's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_11": {+      "label": "Pin 11 · PA1 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port A bit 1."+    },+    "solder_11": {+      "label": "Solder joint · pin 11 (PA1)",+      "why": "Reflowed solder bonding pin 11's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_12": {+      "label": "Pin 12 · PA2 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port A bit 2."+    },+    "solder_12": {+      "label": "Solder joint · pin 12 (PA2)",+      "why": "Reflowed solder bonding pin 12's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_13": {+      "label": "Pin 13 · PA3 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port A bit 3."+    },+    "solder_13": {+      "label": "Solder joint · pin 13 (PA3)",+      "why": "Reflowed solder bonding pin 13's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_14": {+      "label": "Pin 14 · PA4 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port A bit 4."+    },+    "solder_14": {+      "label": "Solder joint · pin 14 (PA4)",+      "why": "Reflowed solder bonding pin 14's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_15": {+      "label": "Pin 15 · PA5 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port A bit 5."+    },+    "solder_15": {+      "label": "Solder joint · pin 15 (PA5)",+      "why": "Reflowed solder bonding pin 15's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_16": {+      "label": "Pin 16 · PA6 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port A bit 6."+    },+    "solder_16": {+      "label": "Solder joint · pin 16 (PA6)",+      "why": "Reflowed solder bonding pin 16's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_17": {+      "label": "Pin 17 · PA7 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port A bit 7."+    },+    "solder_17": {+      "label": "Solder joint · pin 17 (PA7)",+      "why": "Reflowed solder bonding pin 17's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_18": {+      "label": "Pin 18 · PB0 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port B bit 0."+    },+    "solder_18": {+      "label": "Solder joint · pin 18 (PB0)",+      "why": "Reflowed solder bonding pin 18's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_19": {+      "label": "Pin 19 · PB1 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port B bit 1."+    },+    "solder_19": {+      "label": "Solder joint · pin 19 (PB1)",+      "why": "Reflowed solder bonding pin 19's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_20": {+      "label": "Pin 20 · PB2 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port B bit 2, 5 V-tolerant."+    },+    "solder_20": {+      "label": "Solder joint · pin 20 (PB2)",+      "why": "Reflowed solder bonding pin 20's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_21": {+      "label": "Pin 21 · PB10 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port B bit 10, 5 V-tolerant."+    },+    "solder_21": {+      "label": "Solder joint · pin 21 (PB10)",+      "why": "Reflowed solder bonding pin 21's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_22": {+      "label": "Pin 22 · PB11 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port B bit 11, 5 V-tolerant."+    },+    "solder_22": {+      "label": "Solder joint · pin 22 (PB11)",+      "why": "Reflowed solder bonding pin 22's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_23": {+      "label": "Pin 23 · VSS_1 (Power in)",+      "type": "power_in",+      "why": "Digital ground, group 1."+    },+    "solder_23": {+      "label": "Solder joint · pin 23 (VSS_1)",+      "why": "Reflowed solder bonding pin 23's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_24": {+      "label": "Pin 24 · VDD_1 (Power in)",+      "type": "power_in",+      "why": "Digital supply, group 1."+    },+    "solder_24": {+      "label": "Solder joint · pin 24 (VDD_1)",+      "why": "Reflowed solder bonding pin 24's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_25": {+      "label": "Pin 25 · PB12 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port B bit 12, 5 V-tolerant."+    },+    "solder_25": {+      "label": "Solder joint · pin 25 (PB12)",+      "why": "Reflowed solder bonding pin 25's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_26": {+      "label": "Pin 26 · PB13 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port B bit 13, 5 V-tolerant."+    },+    "solder_26": {+      "label": "Solder joint · pin 26 (PB13)",+      "why": "Reflowed solder bonding pin 26's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_27": {+      "label": "Pin 27 · PB14 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port B bit 14, 5 V-tolerant."+    },+    "solder_27": {+      "label": "Solder joint · pin 27 (PB14)",+      "why": "Reflowed solder bonding pin 27's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_28": {+      "label": "Pin 28 · PB15 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port B bit 15, 5 V-tolerant."+    },+    "solder_28": {+      "label": "Solder joint · pin 28 (PB15)",+      "why": "Reflowed solder bonding pin 28's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_29": {+      "label": "Pin 29 · PA8 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port A bit 8, 5 V-tolerant."+    },+    "solder_29": {+      "label": "Solder joint · pin 29 (PA8)",+      "why": "Reflowed solder bonding pin 29's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_30": {+      "label": "Pin 30 · PA9 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port A bit 9, 5 V-tolerant."+    },+    "solder_30": {+      "label": "Solder joint · pin 30 (PA9)",+      "why": "Reflowed solder bonding pin 30's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_31": {+      "label": "Pin 31 · PA10 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port A bit 10, 5 V-tolerant."+    },+    "solder_31": {+      "label": "Solder joint · pin 31 (PA10)",+      "why": "Reflowed solder bonding pin 31's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_32": {+      "label": "Pin 32 · PA11 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port A bit 11, 5 V-tolerant."+    },+    "solder_32": {+      "label": "Solder joint · pin 32 (PA11)",+      "why": "Reflowed solder bonding pin 32's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_33": {+      "label": "Pin 33 · PA12 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port A bit 12, 5 V-tolerant."+    },+    "solder_33": {+      "label": "Solder joint · pin 33 (PA12)",+      "why": "Reflowed solder bonding pin 33's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_34": {+      "label": "Pin 34 · PA13 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port A bit 13, 5 V-tolerant."+    },+    "solder_34": {+      "label": "Solder joint · pin 34 (PA13)",+      "why": "Reflowed solder bonding pin 34's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_35": {+      "label": "Pin 35 · VSS_2 (Power in)",+      "type": "power_in",+      "why": "Digital ground, group 2."+    },+    "solder_35": {+      "label": "Solder joint · pin 35 (VSS_2)",+      "why": "Reflowed solder bonding pin 35's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_36": {+      "label": "Pin 36 · VDD_2 (Power in)",+      "type": "power_in",+      "why": "Digital supply, group 2."+    },+    "solder_36": {+      "label": "Solder joint · pin 36 (VDD_2)",+      "why": "Reflowed solder bonding pin 36's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_37": {+      "label": "Pin 37 · PA14 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port A bit 14, 5 V-tolerant."+    },+    "solder_37": {+      "label": "Solder joint · pin 37 (PA14)",+      "why": "Reflowed solder bonding pin 37's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_38": {+      "label": "Pin 38 · PA15 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port A bit 15, 5 V-tolerant."+    },+    "solder_38": {+      "label": "Solder joint · pin 38 (PA15)",+      "why": "Reflowed solder bonding pin 38's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_39": {+      "label": "Pin 39 · PB3 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port B bit 3, 5 V-tolerant."+    },+    "solder_39": {+      "label": "Solder joint · pin 39 (PB3)",+      "why": "Reflowed solder bonding pin 39's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_40": {+      "label": "Pin 40 · PB4 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port B bit 4, 5 V-tolerant."+    },+    "solder_40": {+      "label": "Solder joint · pin 40 (PB4)",+      "why": "Reflowed solder bonding pin 40's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_41": {+      "label": "Pin 41 · PB5 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port B bit 5 (NOT 5 V-tolerant on this pin)."+    },+    "solder_41": {+      "label": "Solder joint · pin 41 (PB5)",+      "why": "Reflowed solder bonding pin 41's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_42": {+      "label": "Pin 42 · PB6 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port B bit 6, 5 V-tolerant."+    },+    "solder_42": {+      "label": "Solder joint · pin 42 (PB6)",+      "why": "Reflowed solder bonding pin 42's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_43": {+      "label": "Pin 43 · PB7 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port B bit 7, 5 V-tolerant."+    },+    "solder_43": {+      "label": "Solder joint · pin 43 (PB7)",+      "why": "Reflowed solder bonding pin 43's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_44": {+      "label": "Pin 44 · BOOT0 (Input)",+      "type": "input",+      "why": "Boot mode selection input sampled at reset (with BOOT1/PB2): selects boot from Flash, System memory (bootloader), or embedded SRAM."+    },+    "solder_44": {+      "label": "Solder joint · pin 44 (BOOT0)",+      "why": "Reflowed solder bonding pin 44's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_45": {+      "label": "Pin 45 · PB8 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port B bit 8, 5 V-tolerant."+    },+    "solder_45": {+      "label": "Solder joint · pin 45 (PB8)",+      "why": "Reflowed solder bonding pin 45's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_46": {+      "label": "Pin 46 · PB9 (I/O)",+      "type": "bidirectional",+      "why": "GPIO port B bit 9, 5 V-tolerant."+    },+    "solder_46": {+      "label": "Solder joint · pin 46 (PB9)",+      "why": "Reflowed solder bonding pin 46's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_47": {+      "label": "Pin 47 · VSS_3 (Power in)",+      "type": "power_in",+      "why": "Digital ground, group 3."+    },+    "solder_47": {+      "label": "Solder joint · pin 47 (VSS_3)",+      "why": "Reflowed solder bonding pin 47's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "pad_48": {+      "label": "Pin 48 · VDD_3 (Power in)",+      "type": "power_in",+      "why": "Digital supply, group 3."+    },+    "solder_48": {+      "label": "Solder joint · pin 48 (VDD_3)",+      "why": "Reflowed solder bonding pin 48's lead to its pad. Formed when the board passes through reflow; the joint you inspect for shorts/opens."+    },+    "chip": {+      "label": "STM32F103C8T6 · LQFP-48",+      "why": "The LQFP-48 body. Leads on 48 pins carry every signal and supply to the die inside."+    },+    "fr4": {+      "label": "PCB substrate (FR4)",+      "why": "The board the part mounts to — copper pads sit on this FR4 laminate."+    },+    "silk_pin1": {+      "label": "Pin-1 marker",+      "why": "Silkscreen dot marking pin 1, so the part is placed in the correct orientation."+    }+  }+}\ No newline at end of file
datasheet-cover.pngadded
⋯ 1 unchanged line ⋯
page.json+7−2
@@ -43,7 +43,9 @@     "viewers": {       "symbol": "viewers/symbol.html",       "footprint": "viewers/footprint.html"-    }+    },+    "datasheet_cover": "screenshots/datasheet-cover.png",+    "tooltips": "STM32F103C8T6-tooltips.json"   },   "discovery_triggers": [     "stm32f103",@@ -99,7 +101,10 @@     "stm32f103c8t6.glb",     "stm32f103c8t6.step",     "screenshots/hero.png",-    "docs/stm32f103c8.pdf"+    "docs/stm32f103c8.pdf",+    "screenshots/datasheet-cover.png",+    "STM32F103C8T6-tooltips.json",+    "stm32f103c8t6-board.glb"   ],   "changelog": "0.2.2: add stm32f103c8t6-flashing (SWD/OpenOCD, UART ROM bootloader, the no-ROM-DFU gotcha, RDP unlock). Second skill: the #46 upgrade-delivery probe." }\ No newline at end of file
readme.html+41−1
@@ -35,6 +35,24 @@ h2{font-size:16px;font-weight:600;margin:24px 0 4px}h2 .s{color:var(--text-2);fo .c-seed{color:var(--green);background:rgba(63,185,80,.13)}.c-dk{color:var(--red);background:rgba(248,81,73,.12)}.c-jlc{color:var(--purple);background:rgba(140,107,247,.14)} .periphwrap{display:flex;flex-wrap:wrap;gap:7px;margin-top:8px} .periph{font-family:'JetBrains Mono';font-size:12px;background:var(--elevated);border:1px solid var(--border);border-radius:8px;padding:4px 9px}+.ds2sf{background:linear-gradient(180deg,var(--surface),#12161d);border:1px solid var(--border);border-radius:12px;padding:16px 18px;margin:12px 0;max-width:760px}+.ds2sf-h{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin-bottom:14px}+.ds2sf-h .t{font-family:'Familjen Grotesk',sans-serif;font-weight:600;font-size:15px;color:var(--text)}+.ds2sf-h .t b{color:var(--accent-bright)}+.ds2sf-h .s{font-size:12px;color:var(--text-2)}+.ds2sf-metrics{display:flex;flex-wrap:wrap;gap:22px;margin-bottom:14px}+.ds2sf-metric .n{font-family:'JetBrains Mono';font-variant-numeric:tabular-nums;font-size:22px;font-weight:700;color:var(--accent-bright);line-height:1}+.ds2sf-metric .l{font-size:11px;color:var(--text-2);margin-top:4px}+.ds2sf-bar{display:flex;height:10px;border-radius:5px;overflow:hidden;margin:2px 0 8px}+.ds2sf-bar span{display:block;height:100%}+.ds2sf-legend{display:flex;flex-wrap:wrap;gap:14px;font-size:11px;color:var(--text-2);margin-bottom:14px}+.ds2sf-legend i{display:inline-block;width:8px;height:8px;border-radius:2px;margin-right:6px;vertical-align:0}+.ds2sf-prov{display:flex;flex-wrap:wrap;gap:7px}+.ds2sf-tag{font-size:11px;background:var(--elevated);border:1px solid var(--border);border-radius:999px;padding:3px 10px;color:var(--text-2)}+.ds2sf-tag b{color:var(--text);font-weight:600;font-family:'JetBrains Mono'}+.ds2sf-tag.ok{border-color:rgba(63,185,80,.4);color:var(--green)}+.ds2sf-why{font-size:12.5px;color:var(--text-2);margin-top:13px;line-height:1.5}+.ds2sf-why a{color:var(--accent)} .pingroup h3{font-size:13px;color:var(--accent-bright);margin:16px 0 6px} .tblwrap{overflow-x:auto} table{border-collapse:collapse;width:100%;font-size:13px}@@ -135,7 +153,29 @@ tr[data-pin].hl td,tr[data-pin].hl td.data{color:var(--text)}  <div class=narrow> <h2>Provenance</h2>-<div class=callout>Pin functions extracted by <b>ds2sf</b> from the ST datasheet (116 pages, sha256 0596dd57693c, source lcsc); Claude cites pages and refuses to fabricate, flagging muxed pins for review. CAD from KiCad official libraries (CC-BY-SA 4.0). Footprint pads carry KiCad <code>pinfunction</code>/<code>pintype</code>. 3D board-context composed with cadquery (FR4 + copper pads + solder + pin 1) and rendered via step2glb. Datasheet: <a href="https://www.st.com/resource/en/datasheet/stm32f103cb.pdf" target=_blank>ST STM32F103x8/xB</a>.</div>+<div class=ds2sf>+  <div class=ds2sf-h><span class=t>Extracted by <b>ds2sf</b></span><span class=s>the datasheet's pin knowledge, inline and cited &mdash; not just a pinout</span></div>+  <div class=ds2sf-metrics>+    <div class=ds2sf-metric><div class=n>48/48</div><div class=l>pins with datasheet function</div></div>+    <div class=ds2sf-metric><div class=n>6</div><div class=l>functional groups</div></div>+    <div class=ds2sf-metric><div class=n>3</div><div class=l>electrical types</div></div>+    <div class=ds2sf-metric><div class=n>~104</div><div class=l>chars of detail / pin</div></div>+  </div>+  <div class=ds2sf-bar>+    <span style="width:18.8%;background:#f0883e" title="POWER 9"></span><span style="width:54.2%;background:#58a6ff" title="GPIO 26"></span><span style="width:8.3%;background:#3fb950" title="TIMING 4"></span><span style="width:4.2%;background:#8c6bf7" title="CONTROL 2"></span><span style="width:4.2%;background:#00b8b0" title="USB 2"></span><span style="width:10.4%;background:#d29922" title="DEBUG 5"></span>+  </div>+  <div class=ds2sf-legend>+    <span><i style="background:#f0883e"></i>POWER 9</span><span><i style="background:#58a6ff"></i>GPIO 26</span><span><i style="background:#3fb950"></i>TIMING 4</span><span><i style="background:#8c6bf7"></i>CONTROL 2</span><span><i style="background:#00b8b0"></i>USB 2</span><span><i style="background:#d29922"></i>DEBUG 5</span>+  </div>+  <div class=ds2sf-prov>+    <span class=ds2sf-tag><b>ST datasheet</b> &middot; 116 pp</span>+    <span class=ds2sf-tag>sha256 <b>0596dd57693c</b></span>+    <span class="ds2sf-tag ok">&check; cites datasheet pages</span>+    <span class="ds2sf-tag ok">&check; refuses to fabricate</span>+    <span class=ds2sf-tag>CAD &middot; <b>KiCad official</b></span>+  </div>+  <div class=ds2sf-why>Every pin in the map above carries the datasheet's actual function, alternate-function muxing, and electrical type &mdash; pulled by ds2sf and page-cited, so you get the datasheet's pin knowledge without opening the PDF. Muxed pins are flagged for review; nothing is invented. Footprint pads carry KiCad <code>pinfunction</code>/<code>pintype</code>; 3D board-context via cadquery + step2glb. Source: <a href="https://www.st.com/resource/en/datasheet/stm32f103cb.pdf" target=_blank>ST STM32F103x8/xB</a> (CAD CC-BY-SA 4.0).</div>+</div> </div> <div class=fptip id=fptip></div> </div>
stm32f103c8t6-board.glb
⋯ 1 unchanged line ⋯