<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Health Tracker</title>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js"
}
}
</script>
<style>
* { box-sizing: border-box; }
body {
margin: 0;
font-family: Arial, sans-serif;
background: #f8f3ff;
color: #38294d;
}
header {
padding: 25px;
background: white;
text-align: center;
}
header h1 {
color: #a16bd6;
margin: 0;
}
header p { color: #887a99; }
.dashboard {
display: grid;
grid-template-columns: repeat(auto-fit,minmax(230px,1fr));
gap: 18px;
padding: 20px;
}
.card {
background: white;
border-radius: 20px;
padding: 20px;
box-shadow: 0 5px 20px #ddd0ee;
}
.card h3 { color: #9b65ce; }
.value {
font-size: 30px;
font-weight: bold;
}
button {
background: #a875d5;
color: white;
border: none;
padding: 11px 16px;
border-radius: 12px;
cursor: pointer;
margin: 4px;
}
button:hover { background: #8050b4; }
#scene {
width: 100%;
height: 430px;
cursor: grab;
background: radial-gradient(#ffffff,#eadcff);
border-radius: 20px;
overflow: hidden;
}
.model-card {
margin: 20px;
padding: 20px;
background: white;
border-radius: 20px;
text-align: center;
}
#info {
background: #f5edff;
padding: 15px;
border-radius: 15px;
margin-top: 12px;
min-height: 65px;
}
input {
width: 70px;
padding: 8px;
border: 1px solid #d6c3ed;
border-radius: 8px;
}
footer {
text-align: center;
padding: 25px;
color: #9889a6;
}
</style>
</head>
<body>
<header>
<h1>๐ My Health Tracker</h1>
<p>Your personal wellness dashboard</p>
</header>
<div class="dashboard">
<div class="card">
<h3>๐ง Water Intake</h3>
<div class="value" id="water">0 / 8</div>
<p>Glasses today</p>
<button onclick="addWater()">+ Add Glass</button>
<button onclick="resetWater()">Reset</button>
</div>
<div class="card">
<h3>๐ถ Steps</h3>
<div class="value" id="steps">0</div>
<p>Steps today</p>
<input id="stepInput" type="number" placeholder="Steps">
<button onclick="addSteps()">Save</button>
</div>
<div class="card">
<h3>๐ด Sleep</h3>
<div class="value" id="sleep">0 hrs</div>
<p>Hours slept</p>
<input id="sleepInput" type="number" placeholder="Hours">
<button onclick="saveSleep()">Save</button>
</div>
<div class="card">
<h3>๐ Mood</h3>
<div class="value" id="mood">๐</div>
<p>How are you feeling?</p>
<button onclick="setMood('๐')">Happy</button>
<button onclick="setMood('๐ด')">Tired</button>
<button onclick="setMood('๐')">Okay</button>
</div>
</div>
<div class="model-card">
<h2>๐ง 3D Human Body</h2>
<p>Drag to rotate. Click a body part to explore.</p>
<div id="scene"></div>
<div id="info">
Click the 3D model to explore different body areas.
</div>
</div>
<footer>
Personal wellness tracker โข Not a medical diagnostic tool
</footer>
<script type="module">
import * as THREE from 'three';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
45, 1, 0.1, 100
);
camera.position.set(0, 1.5, 7);
const renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setPixelRatio(Math.min(window.devicePixelRatio,2));
document.getElementById('scene').appendChild(renderer.domElement);
scene.add(new THREE.AmbientLight(0xffffff, 1.5));
const light = new THREE.DirectionalLight(0xffffff, 2);
light.position.set(4,5,5);
scene.add(light);
const person = new THREE.Group();
scene.add(person);
const material = new THREE.MeshStandardMaterial({
color: 0xb78be5,
roughness: 0.45
});
const darkMaterial = new THREE.MeshStandardMaterial({
color: 0x8755bd
});
const parts = [];
function makePart(name, x,y,z, sx,sy,sz, description) {
const geometry = new THREE.SphereGeometry(1,32,24);
const mesh = new THREE.Mesh(geometry,material);
mesh.position.set(x,y,z);
mesh.scale.set(sx,sy,sz);
mesh.userData = {name,description};
person.add(mesh);
parts.push(mesh);
return mesh;
}
// Head
makePart(
'Head',0,2.25,0,0.38,0.45,0.35,
'The head contains the brain and important sensory organs.'
);
// Neck
makePart(
'Neck',0,1.75,0,0.15,0.2,0.15,
'The neck supports the head.'
);
// Torso
makePart(
'Chest',0,1.15,0,0.58,0.65,0.3,
'The chest contains the heart and lungs.'
);
// Abdomen
makePart(
'Abdomen',0,0.55,0,0.43,0.43,0.27,
'The abdomen contains several digestive organs.'
);
// Arms
makePart(
'Left Arm',-0.75,1.1,0,0.18,0.65,0.18,
'The arm helps with movement and everyday activities.'
);
makePart(
'Right Arm',0.75,1.1,0,0.18,0.65,0.18,
'The arm helps with movement and everyday activities.'
);
// Legs
makePart(
'Left Leg',-0.25,-0.35,0,0.22,0.8,0.23,
'The legs support the body and help with walking.'
);
makePart(
'Right Leg',0.25,-0.35,0,0.22,0.8,0.23,
'The legs support the body and help with walking.'
);
// Feet
makePart(
'Left Foot',-0.25,-1.15,0.1,0.25,0.13,0.4,
'The feet help with balance and movement.'
);
makePart(
'Right Foot',0.25,-1.15,0.1,0.25,0.13,0.4,
'The feet help with balance and movement.'
);
// Decorative platform
const platform = new THREE.Mesh(
new THREE.CylinderGeometry(1.15,1.15,0.08,64),
darkMaterial
);
platform.position.y = -1.35;
person.add(platform);
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
function resize() {
const container = document.getElementById('scene');
const w = container.clientWidth;
const h = container.clientHeight;
camera.aspect = w/h;
camera.updateProjectionMatrix();
renderer.setSize(w,h);
}
resize();
window.addEventListener('resize',resize);
renderer.domElement.addEventListener('click',event => {
const rect = renderer.domElement.getBoundingClientRect();
mouse.x = ((event.clientX-rect.left)/rect.width)*2-1;
mouse.y = -((event.clientY-rect.top)/rect.height)*2+1;
raycaster.setFromCamera(mouse,camera);
const hits = raycaster.intersectObjects(parts);
if(hits.length) {
const part = hits[0].object.userData;
document.getElementById('info').innerHTML =
'<b>' + part.name + '</b><br>' + part.description;
}
});
// Drag to rotate
let dragging = false;
let lastX = 0;
renderer.domElement.addEventListener('pointerdown',e => {
dragging = true;
lastX = e.clientX;
});
window.addEventListener('pointerup',() => dragging = false);
window.addEventListener('pointermove',e => {
if(dragging) {
person.rotation.y += (e.clientX-lastX)*0.01;
lastX = e.clientX;
}
});
function animate() {
requestAnimationFrame(animate);
if(!dragging) person.rotation.y += 0.002;
renderer.render(scene,camera);
}
animate();
// Dashboard
let water = 0;
let steps = 0;
window.addWater = function() {
water++;
document.getElementById('water').textContent = water + ' / 8';
};
window.resetWater = function() {
water = 0;
document.getElementById('water').textContent = '0 / 8';
};
window.addSteps = function() {
const amount = Number(document.getElementById('stepInput').value);
if(amount >= 0) {
steps = amount;
document.getElementById('steps').textContent =
steps.toLocaleString();
}
};
window.saveSleep = function() {
const hours = Number(document.getElementById('sleepInput').value);
if(hours >= 0 && hours <= 24) {
document.getElementById('sleep').textContent = hours + ' hrs';
}
};
window.setMood = function(mood) {
document.getElementById('mood').textContent = mood;
};
</script>
</body>
</html>