| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="utf-8" /> |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> |
| <title>X-RAY ANYTHING Β· RADIOLOGY UNIT 07</title> |
| <link rel="preconnect" href="https://fonts.googleapis.com" /> |
| <link href="https://fonts.googleapis.com/css2?family=Share+Tech+Mono&display=swap" rel="stylesheet" /> |
| <style> |
| :root { |
| --bg: #04070d; --panel: #070d18; --line: #11304a; |
| --cyan: #4fd6ff; --green: #3dff9e; --text: #bfe9ff; --dim: #2f7ea8; |
| } |
| * { box-sizing: border-box; margin: 0; padding: 0; } |
| html, body { height: 100%; } |
| body { |
| background: radial-gradient(ellipse at 50% -20%, #0a1c33 0%, var(--bg) 60%) fixed; |
| color: var(--text); font-family: 'Share Tech Mono', monospace; overflow-x: hidden; |
| } |
| body::before { |
| content: ''; position: fixed; inset: 0; pointer-events: none; z-index: 0; |
| background-image: |
| linear-gradient(rgba(79,214,255,.04) 1px, transparent 1px), |
| linear-gradient(90deg, rgba(79,214,255,.04) 1px, transparent 1px); |
| background-size: 28px 28px; |
| } |
| #root { position: relative; z-index: 2; max-width: 1180px; margin: 0 auto; padding: 20px 16px 36px; } |
| |
| .header { |
| text-align: center; border: 1px solid var(--line); border-radius: 12px; |
| padding: 14px 10px 10px; |
| background: linear-gradient(180deg, #08121f 0%, #060b14 100%); |
| box-shadow: 0 0 30px rgba(31,167,255,.08), inset 0 0 18px rgba(0,0,0,.6); |
| } |
| .header h1 { |
| letter-spacing: .35em; color: #e6f8ff; font-size: 1.55em; font-weight: 400; |
| text-shadow: 0 0 14px rgba(79,214,255,.7); |
| } |
| .header .sub { color: var(--cyan); letter-spacing: .18em; font-size: .7em; opacity: .85; margin-top: 3px; } |
| .online { color: var(--green); font-size: .68em; letter-spacing: .25em; } |
| .online::before { content: 'β'; margin-right: .5em; animation: blink 1.6s infinite; } |
| @keyframes blink { 0%,55% {opacity:1} 60%,100% {opacity:.15} } |
| |
| |
| #stage-wrap { |
| margin-top: 14px; border: 1px solid var(--line); border-radius: 12px; |
| background: radial-gradient(ellipse at 50% 30%, #081526 0%, #03060c 75%); |
| box-shadow: inset 0 0 40px rgba(0,0,0,.8), 0 0 24px rgba(31,167,255,.07); |
| position: relative; overflow: hidden; height: 480px; |
| } |
| #stage { width: 100%; height: 100%; display: block; } |
| .scanning-label { |
| position: absolute; top: 14px; right: 18px; z-index: 7; display: none; |
| color: #6fe3ff; font-size: 11px; letter-spacing: .4em; |
| text-shadow: 0 0 10px rgba(79,214,255,.9); |
| animation: blink .9s infinite; pointer-events: none; |
| } |
| #stage-hint { |
| position: absolute; left: 0; right: 0; bottom: 14px; z-index: 7; |
| text-align: center; color: var(--dim); font-size: .68em; letter-spacing: .3em; |
| pointer-events: none; |
| } |
| |
| .controls { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 14px; } |
| @media (max-width: 880px) { .controls { grid-template-columns: 1fr; } } |
| .panel { |
| border: 1px solid var(--line); border-radius: 12px; background: var(--panel); |
| box-shadow: inset 0 0 25px rgba(0,0,0,.7); padding: 12px; |
| } |
| .panel .tag { text-align: center; color: var(--dim); font-size: .64em; letter-spacing: .35em; margin-bottom: 8px; } |
| |
| .btn { |
| width: 100%; padding: 13px; border-radius: 10px; margin-top: 8px; |
| font-family: inherit; font-size: .95em; letter-spacing: .3em; cursor: pointer; |
| color: #aee9ff; background: linear-gradient(180deg, #0e2c47 0%, #0a1d31 100%); |
| border: 1px solid #1fa7ff; text-shadow: 0 0 10px rgba(79,214,255,.8); |
| box-shadow: 0 0 22px rgba(31,167,255,.25), inset 0 0 12px rgba(31,167,255,.12); |
| transition: all .25s; |
| } |
| .btn:hover:not(:disabled) { box-shadow: 0 0 36px rgba(31,167,255,.55); color: #fff; } |
| .btn:disabled { opacity: .4; cursor: not-allowed; } |
| .btn.secondary { border-color: #15425f; color: #7fc4e4; letter-spacing: .2em; font-size: .78em; padding: 9px; box-shadow: none; margin-top: 8px; } |
| |
| .samples { display: flex; gap: 10px; margin-top: 8px; } |
| .samples .chip { |
| flex: 1; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; |
| cursor: pointer; background: #050a12; transition: border-color .2s; position: relative; |
| } |
| .samples .chip:hover { border-color: var(--cyan); } |
| .samples .chip img { width: 100%; height: 72px; object-fit: cover; display: block; opacity: .8; } |
| .samples .chip span { |
| position: absolute; bottom: 0; left: 0; right: 0; font-size: .56em; letter-spacing: .22em; |
| text-align: center; color: var(--cyan); background: rgba(4,9,16,.78); padding: 3px 0; |
| } |
| |
| .readout { |
| padding: 9px 11px; border: 1px solid var(--line); border-radius: 8px; |
| background: #050b14; min-height: 86px; font-size: .74em; line-height: 1.7; |
| color: var(--green); white-space: pre-wrap; |
| } |
| .readout .dim { color: var(--dim); } |
| |
| .footer { text-align: center; color: var(--dim); font-size: .62em; letter-spacing: .3em; margin-top: 18px; line-height: 2; } |
| .footer a { color: var(--cyan); text-decoration: none; } |
| |
| #boot { |
| position: fixed; inset: 0; z-index: 50; background: var(--bg); |
| display: flex; align-items: center; justify-content: center; |
| transition: opacity .8s; font-size: .85em; |
| } |
| #boot.done { opacity: 0; pointer-events: none; } |
| #boot pre { color: var(--green); letter-spacing: .15em; line-height: 2; } |
| |
| |
| #viewer { |
| position: fixed; inset: 0; z-index: 60; background: rgba(2,5,10,.94); |
| display: none; align-items: center; justify-content: center; cursor: zoom-out; |
| } |
| #viewer img { max-width: 92vw; max-height: 92vh; box-shadow: 0 0 60px rgba(79,214,255,.25); border-radius: 8px; } |
| </style> |
| </head> |
| <body> |
| <div id="boot"><pre id="bootlog"></pre></div> |
| <div id="viewer"><img id="viewer-img" alt="radiograph"/></div> |
|
|
| <div id="root"> |
| <div class="header"> |
| <div class="online">SCANNER ONLINE</div> |
| <h1>X-RAY ANYTHING</h1> |
| <div class="sub">RADIOLOGY UNIT 07 Β· PHOTOGRAPH ANY OBJECT β SEE INSIDE IT</div> |
| </div> |
|
|
| <div id="stage-wrap"> |
| <canvas id="stage"></canvas> |
| <div class="scanning-label" id="scan-label">SCANNING</div> |
| <div id="stage-hint">LOAD A SPECIMEN β IT RIDES THE TABLE INTO THE BORE AND RETURNS AS A RADIOGRAPH</div> |
| </div> |
|
|
| <div class="controls"> |
| <div class="panel"> |
| <div class="tag">βΌ SPECIMEN INTAKE βΌ</div> |
| <button class="btn" id="load-btn">β¬ LOAD SPECIMEN</button> |
| <input type="file" id="file" accept="image/*" style="display:none"/> |
| <div class="samples"> |
| <div class="chip" data-src="/samples/gpu.jpg"><img src="/samples/gpu.jpg" alt=""/><span>SPECIMEN 001 Β· GPU</span></div> |
| <div class="chip" data-src="/samples/mouse.jpg"><img src="/samples/mouse.jpg" alt=""/><span>SPECIMEN 002 Β· MOUSE</span></div> |
| </div> |
| <button class="btn" id="scan-btn" disabled>βΆ BEGIN SCAN</button> |
| </div> |
| <div class="panel"> |
| <div class="tag">βΌ CONSOLE βΌ</div> |
| <div class="readout" id="readout"><span class="dim">// system idle β load a specimen to begin</span></div> |
| <button class="btn secondary" id="view-btn" style="display:none">βΆ VIEW RADIOGRAPH FULLSCREEN</button> |
| <button class="btn secondary" id="dl-btn" style="display:none">β¬ DOWNLOAD RADIOGRAPH</button> |
| </div> |
| </div> |
|
|
| <div class="footer"> |
| BUILD SMALL HACKATHON 2026 Β· ALL MODELS β€ 32B PARAMETERS<br/> |
| FLUX.2-KLEIN-9B + QWEN2.5-VL-3B Β· BUILT WITH GRADIO gr.Server Β· |
| <a href="https://huggingface.co/spaces/build-small-hackathon/xray-anything" target="_blank">SOURCE</a> |
| </div> |
| </div> |
|
|
| <script type="module"> |
| import * as THREE from "https://cdn.jsdelivr.net/npm/three@0.169.0/build/three.module.js"; |
| import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client/+esm"; |
| |
| const $ = (s) => document.querySelector(s); |
| |
| |
| const BOOT_LINES = [ |
| "RADIOLOGY UNIT 07 Β· POWER ON", |
| "LOADING EMITTER ......... FLUX.2-KLEIN-9B", |
| "LOADING OPTICS .......... QWEN2.5-VL-3B", |
| "PARAMETER BUDGET ........ 12B / 32B CAP", |
| "SPINNING UP GANTRY ...... OK", |
| "SCANNER ONLINE.", |
| ]; |
| (async () => { |
| const log = $("#bootlog"); |
| for (const line of BOOT_LINES) { |
| log.textContent += line + "\n"; |
| await new Promise(r => setTimeout(r, 240)); |
| } |
| await new Promise(r => setTimeout(r, 350)); |
| $("#boot").classList.add("done"); |
| })(); |
| |
| |
| const readout = $("#readout"); |
| function log(line, color) { |
| const div = document.createElement("div"); |
| if (color) div.style.color = color; |
| div.textContent = line; |
| readout.appendChild(div); |
| while (readout.childNodes.length > 5) readout.removeChild(readout.firstChild); |
| } |
| function clearLog() { readout.innerHTML = ""; } |
| |
| |
| const canvas = $("#stage"); |
| const renderer = new THREE.WebGLRenderer({ canvas, antialias: true, alpha: true }); |
| renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); |
| |
| const scene = new THREE.Scene(); |
| scene.fog = new THREE.Fog(0x03060c, 8, 18); |
| |
| const camera = new THREE.PerspectiveCamera(42, 2, 0.1, 50); |
| camera.position.set(0.0, 1.1, 7.2); |
| |
| function resize() { |
| const w = canvas.clientWidth, h = canvas.clientHeight; |
| renderer.setSize(w, h, false); |
| camera.aspect = w / h; |
| camera.updateProjectionMatrix(); |
| } |
| new ResizeObserver(resize).observe(canvas); |
| |
| scene.add(new THREE.AmbientLight(0x2a4a66, 1.2)); |
| const key = new THREE.PointLight(0x9fd9ff, 60, 30); key.position.set(4, 5, 6); scene.add(key); |
| const rim = new THREE.PointLight(0x1fa7ff, 40, 20); rim.position.set(-5, 2, -2); scene.add(rim); |
| |
| |
| const machine = new THREE.Group(); |
| scene.add(machine); |
| |
| const shellMat = new THREE.MeshStandardMaterial({ color: 0xdfe9f2, roughness: 0.35, metalness: 0.15 }); |
| const darkMat = new THREE.MeshStandardMaterial({ color: 0x0a1929, roughness: 0.6, metalness: 0.3 }); |
| |
| |
| const gantry = new THREE.Mesh(new THREE.TorusGeometry(1.95, 0.85, 32, 64), shellMat); |
| machine.add(gantry); |
| |
| const housing = new THREE.Mesh(new THREE.CylinderGeometry(2.6, 2.6, 1.6, 48), shellMat); |
| housing.rotation.x = Math.PI / 2; |
| housing.position.z = -1.3; |
| machine.add(housing); |
| |
| const bore = new THREE.Mesh( |
| new THREE.CylinderGeometry(1.12, 1.12, 3.4, 48, 1, true), |
| new THREE.MeshStandardMaterial({ color: 0x060d16, roughness: .9, side: THREE.BackSide }) |
| ); |
| bore.rotation.x = Math.PI / 2; |
| bore.position.z = -0.6; |
| machine.add(bore); |
| |
| |
| const glowMat = new THREE.MeshBasicMaterial({ color: 0x4fd6ff, transparent: true, opacity: 0.85 }); |
| const ringLight = new THREE.Mesh(new THREE.TorusGeometry(1.13, 0.035, 12, 64), glowMat); |
| ringLight.position.z = 0.95; |
| machine.add(ringLight); |
| const ringLight2 = ringLight.clone(); ringLight2.position.z = -0.2; ringLight2.material = glowMat.clone(); |
| ringLight2.material.opacity = 0.35; machine.add(ringLight2); |
| |
| |
| const pedestal = new THREE.Mesh(new THREE.BoxGeometry(1.5, 0.9, 4.6), darkMat); |
| pedestal.position.set(0, -1.62, 2.6); |
| scene.add(pedestal); |
| const tray = new THREE.Group(); |
| const trayTop = new THREE.Mesh(new THREE.BoxGeometry(1.35, 0.09, 3.6), shellMat); |
| tray.add(trayTop); |
| tray.position.set(0, -1.12, 2.8); |
| scene.add(tray); |
| |
| |
| const floor = new THREE.Mesh( |
| new THREE.CircleGeometry(7, 48), |
| new THREE.MeshBasicMaterial({ color: 0x06121f, transparent: true, opacity: 0.85 }) |
| ); |
| floor.rotation.x = -Math.PI / 2; floor.position.y = -2.08; scene.add(floor); |
| |
| |
| const texLoader = new THREE.TextureLoader(); |
| let specimenMesh = null; |
| function makeSpecimen(dataUrl, cb) { |
| texLoader.load(dataUrl, (tex) => { |
| tex.colorSpace = THREE.SRGBColorSpace; |
| const aspect = tex.image.width / tex.image.height; |
| |
| let w = 1.5, h = w / aspect; |
| if (h > 1.3) { h = 1.3; w = h * aspect; } |
| if (specimenMesh) { |
| tray.remove(specimenMesh); |
| specimenMesh.geometry.dispose(); |
| specimenMesh.material.dispose(); |
| } |
| specimenMesh = new THREE.Mesh( |
| new THREE.PlaneGeometry(w, h), |
| new THREE.MeshBasicMaterial({ map: tex, side: THREE.DoubleSide, transparent: true }) |
| ); |
| specimenMesh.position.set(0, h / 2 + 0.05, 0.4); |
| tray.add(specimenMesh); |
| cb && cb(); |
| }); |
| } |
| function swapSpecimenTexture(dataUrl, cb) { |
| texLoader.load(dataUrl, (tex) => { |
| tex.colorSpace = THREE.SRGBColorSpace; |
| specimenMesh.material.map = tex; |
| specimenMesh.material.needsUpdate = true; |
| cb && cb(); |
| }); |
| } |
| |
| |
| const beam = new THREE.Mesh( |
| new THREE.PlaneGeometry(2.1, 0.045), |
| new THREE.MeshBasicMaterial({ color: 0x9ff0ff, transparent: true, opacity: 0, blending: THREE.AdditiveBlending }) |
| ); |
| beam.position.z = 1.0; |
| scene.add(beam); |
| |
| |
| const flash = new THREE.Mesh( |
| new THREE.PlaneGeometry(30, 30), |
| new THREE.MeshBasicMaterial({ color: 0xcdf6ff, transparent: true, opacity: 0, blending: THREE.AdditiveBlending }) |
| ); |
| flash.position.z = 3.5; |
| scene.add(flash); |
| |
| |
| const ease = (t) => t < .5 ? 2*t*t : -1 + (4 - 2*t) * t; |
| let mode = "idle"; |
| let t0 = 0; |
| const TRAY_HOME = 2.8, TRAY_IN = -0.25; |
| let scanDone = false, revealData = null; |
| |
| function setMode(m) { mode = m; t0 = performance.now(); } |
| |
| let mouse = { x: 0, y: 0 }; |
| window.addEventListener("pointermove", (e) => { |
| mouse.x = (e.clientX / window.innerWidth - 0.5) * 2; |
| mouse.y = (e.clientY / window.innerHeight - 0.5) * 2; |
| }); |
| |
| const clock = new THREE.Clock(); |
| function animate() { |
| requestAnimationFrame(animate); |
| const t = clock.getElapsedTime(); |
| const since = (performance.now() - t0) / 1000; |
| |
| |
| ringLight.rotation.z = t * 0.6; |
| ringLight2.rotation.z = -t * 0.4; |
| const basePulse = 0.75 + Math.sin(t * 2.2) * 0.15; |
| |
| if (mode === "idle") { |
| glowMat.opacity = basePulse * 0.6; |
| beam.material.opacity = 0; |
| } |
| |
| if (mode === "in") { |
| const p = ease(Math.min(since / 1.8, 1)); |
| tray.position.z = TRAY_HOME + (TRAY_IN - TRAY_HOME) * p; |
| glowMat.opacity = 0.5 + p * 0.5; |
| if (p >= 1) setMode("scanning"); |
| } |
| |
| if (mode === "scanning") { |
| glowMat.opacity = 0.9 + Math.sin(t * 14) * 0.1; |
| ringLight.rotation.z = t * 5; |
| ringLight2.rotation.z = -t * 3.4; |
| |
| const sweep = Math.sin(t * 2.6); |
| beam.position.y = sweep * 0.95; |
| beam.material.opacity = 0.55 + Math.sin(t * 9) * 0.2; |
| |
| if (scanDone && since > 4.2) { |
| swapSpecimenTexture(revealData.image, () => { |
| flash.material.opacity = 0.9; |
| setMode("out"); |
| }); |
| scanDone = false; |
| } |
| } |
| |
| if (mode === "out") { |
| const p = ease(Math.min(since / 1.9, 1)); |
| tray.position.z = TRAY_IN + (TRAY_HOME - TRAY_IN) * p; |
| beam.material.opacity = Math.max(0, 0.5 - p); |
| glowMat.opacity = 1 - p * 0.4; |
| ringLight.rotation.z = t * (5 - 4.4 * p); |
| if (p >= 1) { setMode("idle"); onScanFinished(); } |
| } |
| |
| |
| flash.material.opacity = Math.max(0, flash.material.opacity - 0.03); |
| |
| |
| camera.position.x += ((mouse.x * 0.55) - camera.position.x) * 0.04; |
| camera.position.y += ((1.1 - mouse.y * 0.3) - camera.position.y) * 0.04; |
| camera.lookAt(0, -0.15, 0.6); |
| |
| renderer.render(scene, camera); |
| } |
| resize(); |
| animate(); |
| |
| |
| let specimenDataUrl = null; |
| let scanning = false; |
| let client = null; |
| |
| async function fileToDataUrl(file) { |
| return new Promise((res) => { |
| const fr = new FileReader(); |
| fr.onload = () => res(fr.result); |
| fr.readAsDataURL(file); |
| }); |
| } |
| |
| function setSpecimen(dataUrl) { |
| if (scanning) return; |
| specimenDataUrl = dataUrl; |
| makeSpecimen(dataUrl, () => { |
| $("#scan-btn").disabled = false; |
| $("#stage-hint").style.display = "none"; |
| clearLog(); |
| log("// specimen on table β gantry ready", "#4fd6ff"); |
| }); |
| } |
| |
| $("#load-btn").addEventListener("click", () => $("#file").click()); |
| $("#file").addEventListener("change", async (e) => { |
| if (e.target.files[0]) setSpecimen(await fileToDataUrl(e.target.files[0])); |
| }); |
| document.body.addEventListener("dragover", (e) => e.preventDefault()); |
| document.body.addEventListener("drop", async (e) => { |
| e.preventDefault(); |
| if (e.dataTransfer.files[0]) setSpecimen(await fileToDataUrl(e.dataTransfer.files[0])); |
| }); |
| document.querySelectorAll(".chip").forEach((chip) => { |
| chip.addEventListener("click", async () => { |
| const blob = await (await fetch(chip.dataset.src)).blob(); |
| setSpecimen(await fileToDataUrl(blob)); |
| }); |
| }); |
| |
| |
| let audioCtx = null, hum = null; |
| function startHum() { |
| try { |
| audioCtx = audioCtx || new AudioContext(); |
| const osc = audioCtx.createOscillator(), osc2 = audioCtx.createOscillator(); |
| const gain = audioCtx.createGain(); |
| osc.type = "sawtooth"; osc.frequency.value = 48; |
| osc2.type = "sine"; osc2.frequency.value = 97; |
| gain.gain.value = 0.022; |
| osc.connect(gain); osc2.connect(gain); gain.connect(audioCtx.destination); |
| osc.start(); osc2.start(); |
| hum = { osc, osc2, gain }; |
| } catch {} |
| } |
| function stopHum() { |
| if (!hum) return; |
| hum.gain.gain.linearRampToValueAtTime(0, audioCtx.currentTime + .4); |
| setTimeout(() => { hum.osc.stop(); hum.osc2.stop(); hum = null; }, 500); |
| } |
| |
| const STAGES = [ |
| "β TABLE ADVANCING INTO BORE", |
| "β IDENTIFYING SPECIMEN", |
| "β EXPOSING β 4-STEP RECTIFIED FLOW", |
| "β RECONSTRUCTING SLICES", |
| ]; |
| |
| let stageTimer = null; |
| $("#scan-btn").addEventListener("click", async () => { |
| if (!specimenDataUrl || scanning || mode !== "idle") return; |
| scanning = true; |
| scanDone = false; revealData = null; |
| $("#scan-btn").disabled = true; |
| $("#view-btn").style.display = "none"; |
| $("#dl-btn").style.display = "none"; |
| $("#scan-label").style.display = "block"; |
| clearLog(); |
| log(STAGES[0] + " ..."); |
| let stage = 1; |
| stageTimer = setInterval(() => { |
| log(STAGES[Math.min(stage, STAGES.length - 1)] + " ..."); |
| stage++; |
| }, 2100); |
| startHum(); |
| setMode("in"); |
| |
| try { |
| client = client || await Client.connect(location.origin); |
| const out = await client.predict("/xray", { image_b64: specimenDataUrl }); |
| revealData = out.data[0]; |
| scanDone = true; |
| } catch (err) { |
| clearInterval(stageTimer); |
| stopHum(); |
| $("#scan-label").style.display = "none"; |
| setMode("out"); |
| clearLog(); |
| log("// SCAN FAULT β " + (err?.message || err), "#ff6b6b"); |
| scanning = false; |
| $("#scan-btn").disabled = false; |
| } |
| }); |
| |
| function onScanFinished() { |
| if (!revealData) return; |
| clearInterval(stageTimer); |
| stopHum(); |
| $("#scan-label").style.display = "none"; |
| clearLog(); |
| log(`// SCAN COMPLETE β SPECIMEN: ${String(revealData.object).toUpperCase()}`, "#3dff9e"); |
| log("// radiograph is an AI reconstruction, not engineering documentation", "#2f7ea8"); |
| $("#view-btn").style.display = "block"; |
| $("#dl-btn").style.display = "block"; |
| const img = revealData.image; |
| $("#view-btn").onclick = () => { |
| $("#viewer-img").src = img; |
| $("#viewer").style.display = "flex"; |
| }; |
| $("#dl-btn").onclick = () => { |
| const a = document.createElement("a"); |
| a.href = img; a.download = "radiograph.webp"; a.click(); |
| }; |
| scanning = false; |
| $("#scan-btn").disabled = false; |
| } |
| $("#viewer").addEventListener("click", () => { $("#viewer").style.display = "none"; }); |
| </script> |
| </body> |
| </html> |
|
|