Jean0's picture
non ce n'est pas réaliste. Je veux
2f337b6 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FaceMotion Simulator</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body class="bg-indigo-50 min-h-screen flex items-center justify-center p-4">
<div class="max-w-md w-full bg-white rounded-2xl shadow-xl overflow-hidden">
<!-- Header -->
<div class="bg-indigo-600 p-6 text-white">
<div class="flex items-center justify-between">
<div>
<h1 class="text-2xl font-bold">FaceMotion Simulator</h1>
<p class="text-indigo-100">Interactive 3D Head Tracking</p>
</div>
<div class="w-12 h-12 rounded-full bg-indigo-500 flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
<circle cx="9" cy="7" r="4"></circle>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
</svg>
</div>
</div>
</div>
<!-- 3D Canvas -->
<div id="canvas-container" class="w-full aspect-square bg-indigo-100 relative">
<canvas id="liveness-canvas" class="absolute inset-0 w-full h-full"></canvas>
<div class="absolute bottom-4 left-0 right-0 flex justify-center">
<div class="bg-indigo-600 text-white px-3 py-1 rounded-full text-xs font-medium shadow-md">
Move the sliders below
</div>
</div>
</div>
<!-- Controls -->
<div class="p-6 space-y-6">
<div>
<div class="flex justify-between mb-2">
<label for="rotate-y" class="text-sm font-medium text-gray-700">Horizontal Rotation</label>
<span id="rotate-y-value" class="text-sm text-indigo-600 font-medium"></span>
</div>
<input type="range" id="rotate-y" min="-80" max="80" value="0" class="w-full h-2 bg-indigo-200 rounded-lg appearance-none cursor-pointer">
</div>
<div>
<div class="flex justify-between mb-2">
<label for="rotate-x" class="text-sm font-medium text-gray-700">Vertical Rotation</label>
<span id="rotate-x-value" class="text-sm text-indigo-600 font-medium"></span>
</div>
<input type="range" id="rotate-x" min="-45" max="45" value="0" class="w-full h-2 bg-indigo-200 rounded-lg appearance-none cursor-pointer">
</div>
<button id="reset-btn" class="w-full py-2 px-4 bg-indigo-100 hover:bg-indigo-200 text-indigo-700 font-medium rounded-lg transition duration-200 flex items-center justify-center space-x-2">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="1 4 1 10 7 10"></polyline>
<polyline points="23 20 23 14 17 14"></polyline>
<path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"></path>
</svg>
<span>Reset Position</span>
</button>
</div>
</div>
<script>
// === 3D Scene Initialization ===
const canvasContainer = document.getElementById('canvas-container');
const canvas = document.getElementById('liveness-canvas');
// Scene
const scene = new THREE.Scene();
scene.background = null;
// Camera
const camera = new THREE.PerspectiveCamera(75, canvasContainer.clientWidth / canvasContainer.clientHeight, 0.1, 1000);
camera.position.z = 5;
// Renderer
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true,
alpha: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(canvasContainer.clientWidth, canvasContainer.clientHeight);
// === Create Abstract Face Mesh ===
const headGroup = new THREE.Group();
scene.add(headGroup);
// Main face shape (simple sphere)
const headGeometry = new THREE.SphereGeometry(1.5, 32, 32);
const headMaterial = new THREE.MeshStandardMaterial({
color: 0x3498db,
wireframe: true,
transparent: true,
opacity: 0.8
});
const head = new THREE.Mesh(headGeometry, headMaterial);
headGroup.add(head);
// Eyes (simple dots)
const eyeGeometry = new THREE.SphereGeometry(0.15, 16, 16);
const eyeMaterial = new THREE.MeshStandardMaterial({
color: 0x2ecc71,
emissive: 0x2ecc71,
emissiveIntensity: 0.5
});
// Left Eye
const eyeLeft = new THREE.Mesh(eyeGeometry, eyeMaterial);
eyeLeft.position.set(-0.5, 0.2, 1.2);
headGroup.add(eyeLeft);
// Right Eye
const eyeRight = new THREE.Mesh(eyeGeometry, eyeMaterial.clone());
eyeRight.position.set(0.5, 0.2, 1.2);
headGroup.add(eyeRight);
// Mouth (simple line)
const mouthGeometry = new THREE.TorusGeometry(0.3, 0.02, 8, 32, Math.PI);
const mouthMaterial = new THREE.MeshStandardMaterial({
color: 0xe74c3c,
emissive: 0xe74c3c,
emissiveIntensity: 0.3
});
const mouth = new THREE.Mesh(mouthGeometry, mouthMaterial);
mouth.position.set(0, -0.3, 1.2);
mouth.rotation.x = Math.PI / 8;
headGroup.add(mouth);
// Facial points (abstract representation)
const pointsGeometry = new THREE.SphereGeometry(0.05, 8, 8);
const pointsMaterial = new THREE.MeshStandardMaterial({
color: 0xf1c40f,
emissive: 0xf1c40f,
emissiveIntensity: 0.2
});
// Create facial points
const pointsPositions = [
[0, 0.5, 1.3], // Forehead
[-0.3, -0.1, 1.3], // Left cheek
[0.3, -0.1, 1.3], // Right cheek
[0, 0.1, 1.5] // Nose
];
pointsPositions.forEach(pos => {
const point = new THREE.Mesh(pointsGeometry, pointsMaterial.clone());
point.position.set(pos[0], pos[1], pos[2]);
headGroup.add(point);
});
// Abstract Lighting
const ambientLight = new THREE.AmbientLight(0x333333, 0.8);
scene.add(ambientLight);
const directionalLight1 = new THREE.DirectionalLight(0x3498db, 0.8);
directionalLight1.position.set(5, 3, 5);
scene.add(directionalLight1);
const directionalLight2 = new THREE.DirectionalLight(0xe74c3c, 0.5);
directionalLight2.position.set(-5, 3, 5);
scene.add(directionalLight2);
const directionalLight3 = new THREE.DirectionalLight(0x2ecc71, 0.3);
directionalLight3.position.set(0, -5, 5);
scene.add(directionalLight3);
// === Controls ===
const sliderY = document.getElementById('rotate-y');
const sliderX = document.getElementById('rotate-x');
const rotateYValue = document.getElementById('rotate-y-value');
const rotateXValue = document.getElementById('rotate-x-value');
const resetBtn = document.getElementById('reset-btn');
sliderY.addEventListener('input', (e) => {
const rotationRadians = (e.target.value * Math.PI) / 180;
headGroup.rotation.y = rotationRadians;
rotateYValue.textContent = `${e.target.value}°`;
});
sliderX.addEventListener('input', (e) => {
const rotationRadians = (e.target.value * Math.PI) / 180;
headGroup.rotation.x = rotationRadians;
rotateXValue.textContent = `${e.target.value}°`;
});
resetBtn.addEventListener('click', () => {
sliderY.value = 0;
sliderX.value = 0;
headGroup.rotation.set(0, 0, 0);
rotateYValue.textContent = '0°';
rotateXValue.textContent = '0°';
});
// Animation Loop with pulsing effect
let pulseDirection = 1;
let pulseIntensity = 0;
function animate() {
requestAnimationFrame(animate);
// Pulsing animation
pulseIntensity += 0.01 * pulseDirection;
if (pulseIntensity > 0.3 || pulseIntensity < 0) {
pulseDirection *= -1;
}
headGroup.children.forEach(child => {
if (child.material && child.material.emissiveIntensity !== undefined) {
child.material.emissiveIntensity = 0.2 + pulseIntensity;
}
});
renderer.render(scene, camera);
}
// Handle Window Resize
function onResize() {
const width = canvasContainer.clientWidth;
const height = canvasContainer.clientHeight;
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
}
window.addEventListener('resize', onResize);
animate();
onResize();
</script>
<script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
</body>
</html>