component
STM32F103C8T6 - Arm Cortex-M3 MCU (Blue Pill)
Public Made by Adomby adom
STMicroelectronics mainstream Arm Cortex-M3 MCU. 72 MHz, 64 KB Flash, 20 KB SRAM, USB, CAN, LQFP-48. The workhorse Blue Pill microcontroller.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>STM32F103C8T6 on its footprint — 3D Viewer</title>
<script>
// Defined BEFORE the viewer bundle tag so its onerror handler can call
// it. A failed load fires onerror during head parsing, before the main
// body script runs — without this, the user gets a permanent spinner.
// (N7 / C7 / F-UX2) The handler is idempotent and DOM-safe (the #error /
// #loading nodes may not exist yet, so it guards on them).
window.__viewerLoadFailed = function (msg) {
window.__viewerFailed = true;
function show() {
var err = document.getElementById("error");
var load = document.getElementById("preload-msg");
var em = document.getElementById("error-msg");
if (em) em.textContent = msg || "The 3D viewer could not be loaded. Try reloading the page.";
if (err) err.classList.add("visible");
if (load) load.style.display = "none";
}
if (document.getElementById("error")) show();
else document.addEventListener("DOMContentLoaded", show);
};
</script>
<link rel="stylesheet" href="https://wiki.adom.inc/static/vendor/adom-3d-viewer-babylon9/style.css">
<!-- Babylon 9 bundle is an ES module; loading it sets window.Adom3DViewerBabylon9.
The init module below runs after this one (modules execute in document
order), so the global is defined by the time it runs. -->
<script type="module" src="https://wiki.adom.inc/static/vendor/adom-3d-viewer-babylon9/adom-3d-viewer-babylon9.esm.js?v=20260611d" onerror="window.__viewerLoadFailed && window.__viewerLoadFailed()"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 100%; height: 100%; overflow: hidden; background: #0d1117; color: #c9d1d9; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; }
#viewer-wrap { position: absolute; inset: 0; }
/* No wiki-side loading screen — the embedded viewer shows its own. The only
thing here is a minimal text message during the brief window before the
viewer bundle finishes downloading and paints its loader (z-index 1, so
the viewer's canvas + its own loader cover it the moment they mount). On
most navigations the bundle is already prefetched on hover, so this is
barely seen. */
#preload-msg {
position: absolute; inset: 0; z-index: 1; pointer-events: none;
display: flex; align-items: center; justify-content: center;
color: #6e7681; font-size: 13px;
}
/* Info bar (kept above the viewer's own UI, click-through) */
#info-bar {
position: absolute; top: 0; left: 0; right: 0; padding: 12px 16px;
background: linear-gradient(180deg, rgba(13,17,23,0.85) 0%, rgba(13,17,23,0) 100%);
z-index: 10; pointer-events: none;
}
#info-bar h1 { font-size: 16px; font-weight: 600; color: #e6edf3; line-height: 1.3; }
#info-bar .meta { font-size: 12px; color: #8b949e; margin-top: 4px; }
#info-bar .meta span { margin-right: 12px; }
/* Error state */
#error {
position: absolute; inset: 0; display: none; flex-direction: column;
align-items: center; justify-content: center; background: #0d1117; z-index: 200;
}
#error.visible { display: flex; }
#error h2 { color: #f85149; margin-bottom: 8px; }
#error p { color: #8b949e; font-size: 14px; max-width: 400px; text-align: center; }
</style>
</head>
<body>
<div id="viewer-wrap"></div>
<div id="preload-msg">Loading 3D viewer…</div>
<div id="info-bar">
<h1>STM32F103C8T6 on its footprint</h1>
<div class="meta">
<span>STMicroelectronics</span>
<span>STM32F103C8T6</span>
<span>LQFP-48 board-context</span>
</div>
</div>
<div id="error">
<h2>Failed to load model</h2>
<p id="error-msg">The 3D model could not be loaded. It may be missing or corrupted.</p>
</div>
<script type="module">
(function() {
const loadingEl = document.getElementById("preload-msg");
const errorMsg = document.getElementById("error-msg");
const errorEl = document.getElementById("error");
let modelLoaded = false;
function showError(msg) {
if (errorMsg) errorMsg.textContent = msg || "The 3D model could not be loaded. It may be missing or corrupted.";
if (errorEl) errorEl.classList.add("visible");
if (loadingEl) loadingEl.style.display = "none";
}
// Watchdog: if the bundle never defined the global or the GLB hasn't
// loaded within the budget, surface the error div instead of spinning
// forever. (N7 / C7 / F-UX2, F-UX3)
const LOAD_TIMEOUT_MS = 20000;
const loadTimer = setTimeout(function() {
if (modelLoaded) return;
if (typeof window.Adom3DViewerBabylon9 === "undefined") {
showError("The 3D viewer could not be loaded. Try reloading the page.");
} else {
showError("The 3D model is taking too long to load. It may be unavailable or too large.");
}
}, LOAD_TIMEOUT_MS);
const Viewer = window.Adom3DViewerBabylon9;
if (window.__viewerFailed || typeof Viewer === "undefined") {
clearTimeout(loadTimer);
showError("The 3D viewer could not be loaded. Try reloading the page.");
return;
}
// Self-host the Draco decoder (#18). Babylon defaults to fetching the
// decoder wasm from the Babylon CDN at decode time, which the viewer CSP
// blocks (status 0) -- so any KHR_draco_mesh_compression GLB (the default
// step2glb output) failed with "Failed to load model". Point Draco at the
// vendored copy before any model loads. window.BABYLON is set by the bundle
// above; the URLs are ASSET_BASE-aware so they resolve behind a proxy too.
try {
if (window.BABYLON && window.BABYLON.DracoCompression) {
window.BABYLON.DracoCompression.Configuration = { decoder: {
wasmUrl: "https://wiki.adom.inc/static/vendor/adom-3d-viewer-babylon9/draco/draco_wasm_wrapper_gltf.js",
wasmBinaryUrl: "https://wiki.adom.inc/static/vendor/adom-3d-viewer-babylon9/draco/draco_decoder_gltf.wasm",
fallbackUrl: "https://wiki.adom.inc/static/vendor/adom-3d-viewer-babylon9/draco/draco_decoder_gltf.js",
} };
}
} catch (e) { /* non-fatal: a non-Draco GLB still renders */ }
const glbUrl = "/blob/component/stm32f103c8t6/stm32f103c8t6-board.glb";
try {
// zUp:true — components are CAD/KiCad parts authored Z-up; this both
// orients them correctly and puts the scene in a right-handed system
// that matches the view cube (so the cube tracks + clicks correctly).
// It also sets the overhead spotlight + ground for proper shadows. No
// environmentUrl — the Babylon 9 build ships a gradient studio default.
const viewer = Viewer.init(document.getElementById("viewer-wrap"), {
zUp: true,
showViewCube: true,
showGround: true,
});
// The bundle has loaded and the viewer is mounting — remove the text
// message; the viewer's own loading screen takes over from here. (It's
// z-index 1, above the canvas, so it must be removed, not just covered.)
if (loadingEl) loadingEl.style.display = "none";
viewer.loadModel(glbUrl).then(function() {
modelLoaded = true;
clearTimeout(loadTimer);
viewer.frameModel();
// Hide the world-origin XYZ axis gizmo — the view cube already
// conveys orientation, so the in-scene axes are redundant clutter.
// (refreshAxisScale preserves this state across later re-frames.)
try { if (viewer.toggleAxes) viewer.toggleAxes("world", false); } catch (e) {}
}).catch(function(err) {
clearTimeout(loadTimer);
showError("Error: " + ((err && err.message) || "the GLB could not be loaded"));
});
} catch (err) {
clearTimeout(loadTimer);
showError("The 3D viewer failed to start: " + ((err && err.message) || "unknown error"));
}
})();
</script>
</body>
</html>