Meta Description" name="description" />
<!DOCTYPE html>
<html lang="hi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>3D Human Anatomy Viewer - Har System, Har Organ, 3D Positions</title>
<style>
body {
margin: 0;
overflow: hidden;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
#info {
position: absolute;
top: 20px;
left: 20px;
background: rgba(0,0,0,0.8);
color: white;
padding: 12px 20px;
border-radius: 8px;
backdrop-filter: blur(5px);
pointer-events: none;
z-index: 10;
font-size: 14px;
border-left: 5px solid #ff3366;
box-shadow: 0 2px 10px rgba(0,0,0,0.3);
max-width: 280px;
}
#info h1 {
margin: 0 0 5px;
font-size: 18px;
}
#info p {
margin: 0;
font-size: 12px;
opacity: 0.8;
}
#click-feedback {
position: absolute;
bottom: 20px;
left: 20px;
background: rgba(0,0,0,0.7);
color: #ffaa44;
padding: 8px 15px;
border-radius: 20px;
font-size: 14px;
font-weight: bold;
pointer-events: none;
z-index: 10;
font-family: monospace;
}
.controls-note {
position: absolute;
bottom: 20px;
right: 20px;
background: rgba(0,0,0,0.5);
color: #ccc;
padding: 5px 10px;
border-radius: 8px;
font-size: 12px;
pointer-events: none;
z-index: 10;
}
@media (max-width: 600px) {
#info { font-size: 10px; top: 10px; left: 10px; max-width: 200px; }
#click-feedback { font-size: 10px; }
}
</style>
</head>
<body>
<div id="info">
<h1>𧬠3D Human Anatomy - Complete Viewer</h1>
<p>π±οΈ Click kisi bhi organ par β naam aur system dekhein | π±οΈ+π±οΈ Drag se ghumayein | Scroll zoom</p>
<p style="font-size:11px; margin-top:5px;">π¨ Colors: Skeleton(White) | Muscles(Red) | Nerves(Yellow) | Heart/Circulation(Red/Blue) | Digestive(Green/Brown) | Lungs(Pink) | Brain(Purple)</p>
</div>
<div id="click-feedback">β¨ Click karein kisi bhi structure par β¨</div>
<div class="controls-note">π±οΈ Mouse drag = rotate | Right click drag = pan | Scroll = zoom</div>
<!-- Import Three.js core and add-ons -->
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.128.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.128.0/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
// --- Setup Scene, Camera, Renderers ---
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x050b1a);
scene.fog = new THREE.FogExp2(0x050b1a, 0.008);
// Camera: perspective, position at angle
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(8, 5, 12);
camera.lookAt(0, 1, 0);
// WebGL renderer
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true; // shadows add depth
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
// CSS2 renderer for labels (always face camera)
const labelRenderer = new CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = '0px';
labelRenderer.domElement.style.left = '0px';
labelRenderer.domElement.style.pointerEvents = 'none';
document.body.appendChild(labelRenderer.domElement);
// --- Controls ---
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.8;
controls.enableZoom = true;
controls.enablePan = true;
controls.target.set(0, 1.5, 0);
// --- Lighting (rich colors) ---
// Ambient light
const ambientLight = new THREE.AmbientLight(0x404060);
scene.add(ambientLight);
// Main directional light
const mainLight = new THREE.DirectionalLight(0xffffff, 1);
mainLight.position.set(5, 10, 7);
mainLight.castShadow = true;
mainLight.receiveShadow = false;
mainLight.shadow.mapSize.width = 1024;
mainLight.shadow.mapSize.height = 1024;
scene.add(mainLight);
// Fill light from below
const fillLight = new THREE.PointLight(0x4466cc, 0.3);
fillLight.position.set(0, -2, 0);
scene.add(fillLight);
// Back rim light
const rimLight = new THREE.PointLight(0xffaa66, 0.5);
rimLight.position.set(-2, 3, -4);
scene.add(rimLight);
// Warm fill from side
const warmFill = new THREE.PointLight(0xff8866, 0.4);
warmFill.position.set(3, 2, 2);
scene.add(warmFill);
// Optional: grid helper and ground subtle
const gridHelper = new THREE.GridHelper(20, 20, 0x88aaff, 0x335588);
gridHelper.position.y = -2.5;
gridHelper.material.transparent = true;
gridHelper.material.opacity = 0.25;
scene.add(gridHelper);
// Simple axis helper (optional, subtle)
// scene.add(new THREE.AxesHelper(5));
// --- Helper function to create labeled object ---
function makeLabel(text, color, position, fontSize = '14px', bgOpacity = 0.7) {
const div = document.createElement('div');
div.textContent = text;
div.style.color = color;
div.style.fontSize = fontSize;
div.style.fontWeight = 'bold';
div.style.textShadow = '1px 1px 0px black';
div.style.background = `rgba(0,0,0,${bgOpacity})`;
div.style.padding = '2px 8px';
div.style.borderRadius = '20px';
div.style.borderLeft = `3px solid ${color}`;
div.style.fontFamily = 'monospace';
div.style.backdropFilter = 'blur(4px)';
div.style.whiteSpace = 'nowrap';
const label = new CSS2DObject(div);
label.position.copy(position);
return label;
}
// --- Create a group to hold all anatomical parts for click detection ---
const anatomyGroup = new THREE.Group();
scene.add(anatomyGroup);
// Store clickable objects with metadata
const clickableObjects = [];
function addWithClick(mesh, name, system, colorHex) {
mesh.userData = { name, system, color: colorHex };
anatomyGroup.add(mesh);
clickableObjects.push(mesh);
return mesh;
}
// --- Materials (various colors for systems) ---
const matSkeleton = new THREE.MeshStandardMaterial({ color: 0xeeeeff, roughness: 0.4, metalness: 0.1, emissive: 0x111111 });
const matMuscle = new THREE.MeshStandardMaterial({ color: 0xcc5555, roughness: 0.5, emissive: 0x331100 });
const matNerve = new THREE.MeshStandardMaterial({ color: 0xffdd77, emissive: 0x442200, roughness: 0.3 });
const matHeart = new THREE.MeshStandardMaterial({ color: 0xcc3333, emissive: 0x441111, roughness: 0.2 });
const matLung = new THREE.MeshStandardMaterial({ color: 0xffaaaa, roughness: 0.6, transparent: true, opacity: 0.85 });
const matLiver = new THREE.MeshStandardMaterial({ color: 0xaa6644, roughness: 0.4 });
const matKidney = new THREE.MeshStandardMaterial({ color: 0xcc8866, roughness: 0.5 });
const matBrain = new THREE.MeshStandardMaterial({ color: 0xaa99ff, emissive: 0x221144, roughness: 0.3 });
const matStomach = new THREE.MeshStandardMaterial({ color: 0x88aa66, roughness: 0.5 });
const matIntestine = new THREE.MeshStandardMaterial({ color: 0xaa8866, roughness: 0.7 });
const matBloodVessel = new THREE.MeshStandardMaterial({ color: 0xdd5555, emissive: 0x331111 });
const matEye = new THREE.MeshStandardMaterial({ color: 0xffffff, emissive: 0x224466 });
// ========== 1. SKELETAL SYSTEM (White-ish) ==========
// Skull
const skull = new THREE.Mesh(new THREE.SphereGeometry(0.55, 32, 32), matSkeleton);
skull.position.set(0, 3.7, 0);
addWithClick(skull, "Skull (Cranium)", "Skeletal", 0xeeeeff);
// Jaw
const jaw = new THREE.Mesh(new THREE.BoxGeometry(0.9, 0.35, 0.7), matSkeleton);
jaw.position.set(0, 3.15, 0.2);
addWithClick(jaw, "Mandible (Jawbone)", "Skeletal", 0xeeeeff);
// Ribcage (simplified torus + cylinders)
const ribcage = new THREE.Mesh(new THREE.TorusGeometry(0.9, 0.08, 16, 48), matSkeleton);
ribcage.rotation.x = Math.PI / 2;
ribcage.rotation.z = 0;
ribcage.position.set(0, 2.0, 0);
ribcage.scale.set(1.2, 1.2, 0.6);
addWithClick(ribcage, "Ribcage", "Skeletal", 0xeeeeff);
// Spine (stack of small cylinders)
for (let i = 0; i < 5; i++) {
const vertebra = new THREE.Mesh(new THREE.CylinderGeometry(0.25, 0.25, 0.2, 8), matSkeleton);
vertebra.position.set(0, 2.6 - i * 0.45, -0.2);
addWithClick(vertebra, `Vertebra L${i+1}`, "Skeletal", 0xeeeeff);
}
// Pelvis
const pelvis = new THREE.Mesh(new THREE.SphereGeometry(0.65, 24, 24), matSkeleton);
pelvis.scale.set(1.1, 0.5, 0.8);
pelvis.position.set(0, 0.65, -0.1);
addWithClick(pelvis, "Pelvis", "Skeletal", 0xeeeeff);
// Femurs (leg bones)
const leftFemur = new THREE.Mesh(new THREE.CylinderGeometry(0.22, 0.18, 1.4, 10), matSkeleton);
leftFemur.position.set(-0.7, -0.1, 0);
addWithClick(leftFemur, "Left Femur", "Skeletal", 0xeeeeff);
const rightFemur = new THREE.Mesh(new THREE.CylinderGeometry(0.22, 0.18, 1.4, 10), matSkeleton);
rightFemur.position.set(0.7, -0.1, 0);
addWithClick(rightFemur, "Right Femur", "Skeletal", 0xeeeeff);
// Tibias (simplified)
const leftTibia = new THREE.Mesh(new THREE.CylinderGeometry(0.18, 0.15, 1.2, 8), matSkeleton);
leftTibia.position.set(-0.7, -1.3, 0.05);
addWithClick(leftTibia, "Left Tibia", "Skeletal", 0xeeeeff);
const rightTibia = new THREE.Mesh(new THREE.CylinderGeometry(0.18, 0.15, 1.2, 8), matSkeleton);
rightTibia.position.set(0.7, -1.3, 0.05);
addWithClick(rightTibia, "Right Tibia", "Skeletal", 0xeeeeff);
// Humerus arms
const leftHumerus = new THREE.Mesh(new THREE.CylinderGeometry(0.18, 0.15, 1.1, 8), matSkeleton);
leftHumerus.position.set(-1.3, 2.2, 0);
leftHumerus.rotation.z = 0.3;
leftHumerus.rotation.x = -0.2;
addWithClick(leftHumerus, "Left Humerus", "Skeletal", 0xeeeeff);
const rightHumerus = new THREE.Mesh(new THREE.CylinderGeometry(0.18, 0.15, 1.1, 8), matSkeleton);
rightHumerus.position.set(1.3, 2.2, 0);
rightHumerus.rotation.z = -0.3;
rightHumerus.rotation.x = 0.2;
addWithClick(rightHumerus, "Right Humerus", "Skeletal", 0xeeeeff);
// ========== 2. MUSCULAR SYSTEM (Reddish) ==========
const pectorals = new THREE.Mesh(new THREE.BoxGeometry(1.6, 0.7, 0.4), matMuscle);
pectorals.position.set(0, 2.2, 0.45);
addWithClick(pectorals, "Pectorals (Chest Muscles)", "Muscular", 0xcc5555);
const abs = new THREE.Mesh(new THREE.BoxGeometry(1.1, 0.9, 0.3), matMuscle);
abs.position.set(0, 1.3, 0.5);
addWithClick(abs, "Abdominal Muscles", "Muscular", 0xcc5555);
const deltoidL = new THREE.Mesh(new THREE.SphereGeometry(0.35, 16, 16), matMuscle);
deltoidL.position.set(-1.25, 2.6, 0.2);
addWithClick(deltoidL, "Left Deltoid", "Muscular", 0xcc5555);
const deltoidR = new THREE.Mesh(new THREE.SphereGeometry(0.35, 16, 16), matMuscle);
deltoidR.position.set(1.25, 2.6, 0.2);
addWithClick(deltoidR, "Right Deltoid", "Muscular", 0xcc5555);
const quadricepsL = new THREE.Mesh(new THREE.BoxGeometry(0.5, 0.8, 0.4), matMuscle);
quadricepsL.position.set(-0.7, -0.6, 0.4);
addWithClick(quadricepsL, "Left Quadriceps", "Muscular", 0xcc5555);
const quadricepsR = new THREE.Mesh(new THREE.BoxGeometry(0.5, 0.8, 0.4), matMuscle);
quadricepsR.position.set(0.7, -0.6, 0.4);
addWithClick(quadricepsR, "Right Quadriceps", "Muscular", 0xcc5555);
// ========== 3. NERVOUS SYSTEM (Yellow/Gold) ==========
const brain = new THREE.Mesh(new THREE.SphereGeometry(0.6, 32, 32), matBrain);
brain.position.set(0, 3.95, 0.1);
addWithClick(brain, "Brain (Cerebrum + Cerebellum)", "Nervous", 0xaa99ff);
// Spinal cord (yellow tube)
const spinalCord = new THREE.Mesh(new THREE.CylinderGeometry(0.12, 0.12, 2.8, 8), matNerve);
spinalCord.position.set(0, 1.7, -0.5);
addWithClick(spinalCord, "Spinal Cord", "Nervous", 0xffdd77);
// Nerves branching (simple lines using cylinders)
const sciaticL = new THREE.Mesh(new THREE.CylinderGeometry(0.07, 0.07, 1.2, 5), matNerve);
sciaticL.position.set(-0.6, 0.2, -0.3);
sciaticL.rotation.z = 0.4;
addWithClick(sciaticL, "Left Sciatic Nerve", "Nervous", 0xffdd77);
const sciaticR = new THREE.Mesh(new THREE.CylinderGeometry(0.07, 0.07, 1.2, 5), matNerve);
sciaticR.position.set(0.6, 0.2, -0.3);
sciaticR.rotation.z = -0.4;
addWithClick(sciaticR, "Right Sciatic Nerve", "Nervous", 0xffdd77);
// ========== 4. CIRCULATORY SYSTEM (Heart & Vessels) ==========
const heart = new THREE.Mesh(new THREE.ConeGeometry(0.45, 0.65, 24), matHeart);
heart.position.set(0, 2.1, 0.55);
heart.rotation.x = 0.2;
addWithClick(heart, "Heart (Cardiac Muscle)", "Circulatory", 0xcc3333);
// Aorta (simple curved cylinder approximation)
const aorta = new THREE.Mesh(new THREE.CylinderGeometry(0.13, 0.18, 0.8, 6), matBloodVessel);
aorta.position.set(0.2, 2.45, 0.7);
aorta.rotation.z = 0.4;
addWithClick(aorta, "Aorta", "Circulatory", 0xdd5555);
// ========== 5. RESPIRATORY SYSTEM ==========
const leftLung = new THREE.Mesh(new THREE.SphereGeometry(0.5, 24, 24), matLung);
leftLung.position.set(-0.65, 2.15, 0.25);
leftLung.scale.set(0.8, 1.1, 0.6);
addWithClick(leftLung, "Left Lung", "Respiratory", 0xffaaaa);
const rightLung = new THREE.Mesh(new THREE.SphereGeometry(0.55, 24, 24), matLung);
rightLung.position.set(0.7, 2.15, 0.25);
rightLung.scale.set(0.85, 1.1, 0.6);
addWithClick(rightLung, "Right Lung", "Respiratory", 0xffaaaa);
// Trachea
const trachea = new THREE.Mesh(new THREE.CylinderGeometry(0.13, 0.13, 0.9, 8), new THREE.MeshStandardMaterial({ color: 0xccaa88 }));
trachea.position.set(0, 2.75, 0.4);
addWithClick(trachea, "Trachea (Windpipe)", "Respiratory", 0xccaa88);
// ========== 6. DIGESTIVE SYSTEM ==========
const liver = new THREE.Mesh(new THREE.SphereGeometry(0.5, 24, 24), matLiver);
liver.position.set(0.5, 1.65, 0.35);
liver.scale.set(1.0, 0.7, 0.6);
addWithClick(liver, "Liver", "Digestive", 0xaa6644);
const stomach = new THREE.Mesh(new THREE.SphereGeometry(0.4, 20, 20), matStomach);
stomach.position.set(-0.5, 1.5, 0.4);
stomach.scale.set(0.9, 0.8, 0.6);
addWithClick(stomach, "Stomach", "Digestive", 0x88aa66);
const intestines = new THREE.Mesh(new THREE.TorusKnotGeometry(0.5, 0.12, 100, 16, 3, 4), matIntestine);
intestines.position.set(0, 0.9, 0.2);
intestines.scale.set(0.8, 0.6, 0.5);
addWithClick(intestines, "Small & Large Intestines", "Digestive", 0xaa8866);
// ========== 7. KIDNEYS & URINARY ==========
const leftKidney = new THREE.Mesh(new THREE.SphereGeometry(0.28, 20, 20), matKidney);
leftKidney.position.set(-0.9, 1.35, -0.2);
leftKidney.scale.set(0.7, 0.9, 0.6);
addWithClick(leftKidney, "Left Kidney", "Urinary", 0xcc8866);
const rightKidney = new THREE.Mesh(new THREE.SphereGeometry(0.28, 20, 20), matKidney);
rightKidney.position.set(0.95, 1.35, -0.2);
rightKidney.scale.set(0.7, 0.9, 0.6);
addWithClick(rightKidney, "Right Kidney", "Urinary", 0xcc8866);
// ========== 8. SENSE ORGANS (Eyes, Nose) ==========
const leftEye = new THREE.Mesh(new THREE.SphereGeometry(0.12, 24, 24), matEye);
leftEye.position.set(-0.28, 3.85, 0.65);
addWithClick(leftEye, "Left Eye", "Sensory", 0xffffff);
const rightEye = new THREE.Mesh(new THREE.SphereGeometry(0.12, 24, 24), matEye);
rightEye.position.set(0.28, 3.85, 0.65);
addWithClick(rightEye, "Right Eye", "Sensory", 0xffffff);
const nose = new THREE.Mesh(new THREE.ConeGeometry(0.13, 0.25, 8), new THREE.MeshStandardMaterial({ color: 0xddbb99 }));
nose.position.set(0, 3.55, 0.75);
addWithClick(nose, "Nose (Nasal Cavity)", "Respiratory", 0xddbb99);
// Additional details: Ear positions
const leftEar = new THREE.Mesh(new THREE.SphereGeometry(0.12, 16, 16), new THREE.MeshStandardMaterial({ color: 0xddbb99 }));
leftEar.position.set(-0.65, 3.6, 0.0);
addWithClick(leftEar, "Left Ear (Auricle)", "Sensory", 0xddbb99);
const rightEar = new THREE.Mesh(new THREE.SphereGeometry(0.12, 16, 16), new THREE.MeshStandardMaterial({ color: 0xddbb99 }));
rightEar.position.set(0.65, 3.6, 0.0);
addWithClick(rightEar, "Right Ear (Auricle)", "Sensory", 0xddbb99);
// Skin overlay? Not needed, but add a subtle transparent body contour for reference? Optional.
// ========== CSS2D LABELS for each major structure (always readable) ==========
const labelsGroup = [];
labelsGroup.push(makeLabel("π§ Brain", "#cc99ff", new THREE.Vector3(0, 4.5, 0.4), "13px"));
labelsGroup.push(makeLabel("β€οΈ Heart", "#ff8888", new THREE.Vector3(0.6, 2.35, 1.0), "12px"));
labelsGroup.push(makeLabel("π« Lung", "#ffaaaa", new THREE.Vector3(-1.1, 2.5, 0.8), "12px"));
labelsGroup.push(makeLabel("π« Lung", "#ffaaaa", new THREE.Vector3(1.2, 2.5, 0.8), "12px"));
labelsGroup.push(makeLabel("Liver", "#ccaa77", new THREE.Vector3(1.0, 1.9, 1.0), "11px"));
labelsGroup.push(makeLabel("Stomach", "#aacc77", new THREE.Vector3(-1.0, 1.8, 1.0), "11px"));
labelsGroup.push(makeLabel("Kidney", "#cc8866", new THREE.Vector3(-1.3, 1.4, -0.5), "11px"));
labelsGroup.push(makeLabel("Kidney", "#cc8866", new THREE.Vector3(1.4, 1.4, -0.5), "11px"));
labelsGroup.push(makeLabel("Spine", "#ffdd99", new THREE.Vector3(0, 2.5, -1.2), "11px"));
labelsGroup.push(makeLabel("Pelvis", "#ddddff", new THREE.Vector3(0, 0.4, -0.9), "11px"));
labelsGroup.push(makeLabel("Femur", "#ddddff", new THREE.Vector3(-1.1, -0.3, 0.6), "10px"));
labelsGroup.push(makeLabel("Femur", "#ddddff", new THREE.Vector3(1.2, -0.3, 0.6), "10px"));
labelsGroup.push(makeLabel("Ribcage", "#ddddff", new THREE.Vector3(1.3, 2.0, 0.2), "11px"));
labelsGroup.push(makeLabel("Skull", "#ddddff", new THREE.Vector3(0, 4.2, -0.7), "12px"));
labelsGroup.push(makeLabel("Intestines", "#aa8866", new THREE.Vector3(0, 0.5, 1.1), "11px"));
labelsGroup.push(makeLabel("Trachea", "#ccaa88", new THREE.Vector3(-0.5, 3.0, 1.0), "10px"));
labelsGroup.push(makeLabel("Pectorals", "#dd8888", new THREE.Vector3(1.2, 2.3, 1.0), "10px"));
labelsGroup.push(makeLabel("Quadriceps", "#dd8888", new THREE.Vector3(1.2, -0.5, 1.0), "10px"));
labelsGroup.forEach(lbl => scene.add(lbl));
// Additional floating labels for smaller parts
scene.add(makeLabel("ποΈ Eye", "#ffffff", new THREE.Vector3(-0.45, 4.0, 1.1), "10px", 0.5));
scene.add(makeLabel("ποΈ Eye", "#ffffff", new THREE.Vector3(0.55, 4.0, 1.1), "10px", 0.5));
scene.add(makeLabel("Aorta", "#ff8888", new THREE.Vector3(0.5, 2.7, 1.2), "9px", 0.5));
// ========== Raycaster for click detection ==========
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
const feedbackDiv = document.getElementById('click-feedback');
window.addEventListener('click', (event) => {
// Calculate mouse position in normalized coordinates
mouse.x = (event.clientX / renderer.domElement.clientWidth) * 2 - 1;
mouse.y = -(event.clientY / renderer.domElement.clientHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(clickableObjects);
if (intersects.length > 0) {
const hit = intersects[0].object;
const data = hit.userData;
if (data && data.name) {
feedbackDiv.innerHTML = `π ${data.name} | 𧬠System: ${data.system}`;
feedbackDiv.style.opacity = '1';
feedbackDiv.style.transform = 'scale(1.02)';
setTimeout(() => {
feedbackDiv.style.transform = 'scale(1)';
}, 200);
} else {
feedbackDiv.innerHTML = `π Unknown structure (try another)`;
}
} else {
feedbackDiv.innerHTML = `β¨ Click kisi bhi color-coded part par β naam aur system dekhein β¨`;
}
});
// Optional: add subtle animation to heartbeat? Not needed but fun
let time = 0;
// ========== Animation Loop ==========
function animate() {
requestAnimationFrame(animate);
controls.update(); // update orbit
time += 0.01;
// Subtle pulsation to heart (just for visual interest)
if (heart) {
const scale = 1 + Math.sin(time * 12) * 0.02;
heart.scale.set(scale, scale, scale);
}
renderer.render(scene, camera);
labelRenderer.render(scene, camera);
}
animate();
// Handle window resize
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.setSize(window.innerWidth, window.innerHeight);
}
console.log("3D Anatomy Viewer Loaded - 30+ structures, all systems, colors, labels, clickable!");
</script>
</body>
</html>4
2
257KB
1168KB
550.0ms
188.0ms
551.0ms