spank / index.html
ES14195595's picture
Add 3 files
823c076 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FaceFX - AI NSFW Video Generator</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.gradient-bg {
background: linear-gradient(135deg, #6e45e2 0%, #89d4cf 100%);
}
.preview-container {
position: relative;
overflow: hidden;
border-radius: 12px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
}
.preview-overlay {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0.6);
padding: 1rem;
color: white;
transform: translateY(100%);
transition: transform 0.3s ease;
}
.preview-container:hover .preview-overlay {
transform: translateY(0);
}
.file-upload {
border: 2px dashed #9ca3af;
transition: all 0.3s ease;
}
.file-upload:hover {
border-color: #6b7280;
background-color: rgba(255, 255, 255, 0.05);
}
.file-upload.dragover {
border-color: #8b5cf6;
background-color: rgba(139, 92, 246, 0.1);
}
.slider-thumb::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: #8b5cf6;
cursor: pointer;
}
.progress-bar {
height: 6px;
transition: width 0.3s ease;
}
.face-marker {
position: absolute;
border: 2px solid #8b5cf6;
border-radius: 50%;
pointer-events: none;
}
</style>
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen">
<div class="gradient-bg fixed top-0 left-0 w-full h-1/2 -z-10"></div>
<div class="container mx-auto px-4 py-12">
<header class="flex justify-between items-center mb-12">
<div class="flex items-center">
<i class="fas fa-fire text-3xl text-purple-500 mr-3"></i>
<h1 class="text-3xl font-bold bg-gradient-to-r from-purple-500 to-pink-500 bg-clip-text text-transparent">FaceFX</h1>
</div>
<nav>
<ul class="flex space-x-6">
<li><a href="#" class="hover:text-purple-400 transition">Home</a></li>
<li><a href="#" class="hover:text-purple-400 transition">Examples</a></li>
<li><a href="#" class="hover:text-purple-400 transition">Pricing</a></li>
<li><a href="#" class="hover:text-purple-400 transition">API</a></li>
</ul>
</nav>
</header>
<main class="bg-gray-800 rounded-xl shadow-2xl overflow-hidden">
<div class="p-8">
<h2 class="text-2xl font-bold mb-6">Create NSFW Videos with Consistent Faces</h2>
<p class="text-gray-400 mb-8">Upload an image and our AI will generate a high-quality NSFW video while maintaining facial consistency throughout the animation.</p>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
<!-- Upload Section -->
<div class="file-upload rounded-lg p-6 flex flex-col items-center justify-center text-center cursor-pointer" id="uploadArea">
<i class="fas fa-cloud-upload-alt text-4xl text-purple-500 mb-4"></i>
<h3 class="text-xl font-semibold mb-2">Upload Source Image</h3>
<p class="text-gray-400 mb-4">Drag & drop your image here or click to browse</p>
<input type="file" id="fileInput" accept="image/*" class="hidden">
<button id="uploadBtn" class="bg-purple-600 hover:bg-purple-700 text-white px-6 py-2 rounded-full transition">Select Image</button>
<div class="mt-4 text-sm text-gray-500">Supports JPG, PNG (Max 10MB)</div>
</div>
<!-- Preview Section -->
<div class="preview-container bg-gray-700 aspect-video relative" id="previewContainer">
<div class="absolute inset-0 flex items-center justify-center" id="previewPlaceholder">
<div class="text-center">
<i class="fas fa-image text-4xl text-gray-500 mb-2"></i>
<p class="text-gray-400">Preview will appear here</p>
</div>
</div>
<canvas id="previewCanvas" class="hidden w-full h-full object-cover"></canvas>
<div class="preview-overlay">
<div class="flex justify-between items-center">
<span id="fileNameDisplay" class="truncate">No image selected</span>
<button id="clearBtn" class="text-gray-300 hover:text-white">
<i class="fas fa-times"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Face Detection Section -->
<div class="mt-8 bg-gray-750 rounded-lg p-6" id="faceDetectionSection" style="display: none;">
<h3 class="text-lg font-semibold mb-4 flex items-center">
<i class="fas fa-user-circle text-purple-500 mr-2"></i>
Face Detection
</h3>
<div class="flex flex-wrap gap-4 mb-4" id="faceMarkersContainer">
<!-- Face markers will be added here -->
</div>
<div class="flex items-center space-x-4">
<div class="flex-1">
<label class="block text-sm text-gray-400 mb-1">Face Consistency Strength</label>
<input type="range" min="0" max="100" value="75" class="w-full slider-thumb" id="consistencySlider">
<div class="flex justify-between text-xs text-gray-500 mt-1">
<span>Low</span>
<span>Medium</span>
<span>High</span>
</div>
</div>
<button id="detectFacesBtn" class="bg-purple-600 hover:bg-purple-700 text-white px-4 py-2 rounded transition">
<i class="fas fa-search mr-2"></i> Detect Faces
</button>
</div>
</div>
<!-- Generation Settings -->
<div class="mt-8 bg-gray-750 rounded-lg p-6">
<h3 class="text-lg font-semibold mb-4 flex items-center">
<i class="fas fa-cog text-purple-500 mr-2"></i>
Video Settings
</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div>
<label class="block text-sm text-gray-400 mb-1">Video Duration</label>
<select class="w-full bg-gray-700 border border-gray-600 rounded px-3 py-2 text-white">
<option>5 seconds</option>
<option selected>10 seconds</option>
<option>15 seconds</option>
<option>30 seconds</option>
</select>
</div>
<div>
<label class="block text-sm text-gray-400 mb-1">Resolution</label>
<select class="w-full bg-gray-700 border border-gray-600 rounded px-3 py-2 text-white">
<option>512x512</option>
<option selected>768x768</option>
<option>1024x1024</option>
</select>
</div>
<div>
<label class="block text-sm text-gray-400 mb-1">FPS</label>
<select class="w-full bg-gray-700 border border-gray-600 rounded px-3 py-2 text-white">
<option>24</option>
<option selected>30</option>
<option>60</option>
</select>
</div>
</div>
<div class="mt-6">
<label class="block text-sm text-gray-400 mb-1">Animation Style</label>
<div class="grid grid-cols-2 md:grid-cols-4 gap-3">
<button class="bg-gray-700 hover:bg-gray-600 px-4 py-2 rounded transition border border-transparent hover:border-purple-500">
Subtle Motion
</button>
<button class="bg-gray-700 hover:bg-gray-600 px-4 py-2 rounded transition border border-transparent hover:border-purple-500">
Fluid Movement
</button>
<button class="bg-purple-600 px-4 py-2 rounded transition border border-purple-500">
Intimate Focus
</button>
<button class="bg-gray-700 hover:bg-gray-600 px-4 py-2 rounded transition border border-transparent hover:border-purple-500">
Extreme Action
</button>
</div>
</div>
</div>
<!-- Generation Controls -->
<div class="mt-8 flex flex-col md:flex-row justify-between items-center gap-4">
<div class="flex items-center space-x-4">
<div class="flex items-center space-x-2">
<input type="checkbox" id="nsfwToggle" checked class="w-4 h-4 text-purple-600 bg-gray-700 border-gray-600 rounded focus:ring-purple-500">
<label for="nsfwToggle" class="text-sm">NSFW Content</label>
</div>
<div class="flex items-center space-x-2">
<input type="checkbox" id="watermarkToggle" class="w-4 h-4 text-purple-600 bg-gray-700 border-gray-600 rounded focus:ring-purple-500">
<label for="watermarkToggle" class="text-sm">Add Watermark</label>
</div>
</div>
<div class="flex space-x-3">
<button id="previewBtn" class="bg-gray-700 hover:bg-gray-600 text-white px-6 py-3 rounded-full transition flex items-center" disabled>
<i class="fas fa-eye mr-2"></i> Preview
</button>
<button id="generateBtn" class="bg-gradient-to-r from-purple-600 to-pink-600 hover:from-purple-700 hover:to-pink-700 text-white px-8 py-3 rounded-full transition flex items-center font-semibold" disabled>
<i class="fas fa-magic mr-2"></i> Generate Video
</button>
</div>
</div>
<!-- Generation Progress -->
<div id="progressSection" class="mt-8 hidden">
<div class="flex justify-between mb-2">
<span class="font-medium">Generating your video...</span>
<span id="progressPercent">0%</span>
</div>
<div class="w-full bg-gray-700 rounded-full h-2.5">
<div id="progressBar" class="progress-bar bg-purple-600 rounded-full h-2.5" style="width: 0%"></div>
</div>
<div class="mt-2 text-sm text-gray-400" id="statusMessage">
Initializing generation process...
</div>
</div>
</div>
</main>
<footer class="mt-12 text-center text-gray-500 text-sm">
<p>© 2023 FaceFX AI. All generated content is for personal use only.</p>
<p class="mt-2">By using this service, you agree to our <a href="#" class="text-purple-400 hover:underline">Terms</a> and <a href="#" class="text-purple-400 hover:underline">Privacy Policy</a>.</p>
</footer>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// DOM Elements
const uploadArea = document.getElementById('uploadArea');
const fileInput = document.getElementById('fileInput');
const uploadBtn = document.getElementById('uploadBtn');
const previewContainer = document.getElementById('previewContainer');
const previewPlaceholder = document.getElementById('previewPlaceholder');
const previewCanvas = document.getElementById('previewCanvas');
const fileNameDisplay = document.getElementById('fileNameDisplay');
const clearBtn = document.getElementById('clearBtn');
const faceDetectionSection = document.getElementById('faceDetectionSection');
const detectFacesBtn = document.getElementById('detectFacesBtn');
const faceMarkersContainer = document.getElementById('faceMarkersContainer');
const previewBtn = document.getElementById('previewBtn');
const generateBtn = document.getElementById('generateBtn');
const progressSection = document.getElementById('progressSection');
const progressBar = document.getElementById('progressBar');
const progressPercent = document.getElementById('progressPercent');
const statusMessage = document.getElementById('statusMessage');
// Variables
let uploadedImage = null;
let detectedFaces = [];
// Event Listeners
uploadBtn.addEventListener('click', () => fileInput.click());
uploadArea.addEventListener('click', () => fileInput.click());
uploadArea.addEventListener('dragover', (e) => {
e.preventDefault();
uploadArea.classList.add('dragover');
});
uploadArea.addEventListener('dragleave', () => {
uploadArea.classList.remove('dragover');
});
uploadArea.addEventListener('drop', (e) => {
e.preventDefault();
uploadArea.classList.remove('dragover');
if (e.dataTransfer.files.length) {
fileInput.files = e.dataTransfer.files;
handleFileUpload(e.dataTransfer.files[0]);
}
});
fileInput.addEventListener('change', () => {
if (fileInput.files.length) {
handleFileUpload(fileInput.files[0]);
}
});
clearBtn.addEventListener('click', () => {
resetUpload();
});
detectFacesBtn.addEventListener('click', detectFaces);
previewBtn.addEventListener('click', previewGeneration);
generateBtn.addEventListener('click', generateVideo);
// Functions
function handleFileUpload(file) {
if (!file.type.match('image.*')) {
alert('Please upload an image file (JPEG, PNG)');
return;
}
if (file.size > 10 * 1024 * 1024) {
alert('File size exceeds 10MB limit');
return;
}
const reader = new FileReader();
reader.onload = function(e) {
uploadedImage = new Image();
uploadedImage.onload = function() {
displayImage();
fileNameDisplay.textContent = file.name;
previewBtn.disabled = false;
generateBtn.disabled = false;
faceDetectionSection.style.display = 'block';
};
uploadedImage.src = e.target.result;
};
reader.readAsDataURL(file);
}
function displayImage() {
previewPlaceholder.classList.add('hidden');
previewCanvas.classList.remove('hidden');
const canvas = previewCanvas;
const ctx = canvas.getContext('2d');
// Set canvas dimensions to match container while maintaining aspect ratio
const containerWidth = previewContainer.clientWidth;
const containerHeight = previewContainer.clientHeight;
canvas.width = containerWidth;
canvas.height = containerHeight;
// Calculate dimensions to maintain aspect ratio
const imgRatio = uploadedImage.width / uploadedImage.height;
const containerRatio = containerWidth / containerHeight;
let drawWidth, drawHeight, offsetX = 0, offsetY = 0;
if (imgRatio > containerRatio) {
// Image is wider than container
drawHeight = containerHeight;
drawWidth = drawHeight * imgRatio;
offsetX = (containerWidth - drawWidth) / 2;
} else {
// Image is taller than container
drawWidth = containerWidth;
drawHeight = drawWidth / imgRatio;
offsetY = (containerHeight - drawHeight) / 2;
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(uploadedImage, offsetX, offsetY, drawWidth, drawHeight);
}
function resetUpload() {
uploadedImage = null;
detectedFaces = [];
previewPlaceholder.classList.remove('hidden');
previewCanvas.classList.add('hidden');
fileNameDisplay.textContent = 'No image selected';
previewBtn.disabled = true;
generateBtn.disabled = true;
faceDetectionSection.style.display = 'none';
faceMarkersContainer.innerHTML = '';
fileInput.value = '';
}
function detectFaces() {
// Simulate face detection
statusMessage.textContent = "Detecting faces in the image...";
progressSection.classList.remove('hidden');
progressBar.style.width = '30%';
progressPercent.textContent = '30%';
// Simulate API call delay
setTimeout(() => {
// For demo purposes, we'll simulate detecting 1 face in the center
const canvas = previewCanvas;
const rect = canvas.getBoundingClientRect();
detectedFaces = [{
x: rect.width / 2,
y: rect.height / 2,
width: 100,
height: 100,
id: 'face-1'
}];
// Create face markers
createFaceMarkers();
progressBar.style.width = '100%';
progressPercent.textContent = '100%';
statusMessage.textContent = "Face detection complete! Found 1 face.";
setTimeout(() => {
progressSection.classList.add('hidden');
progressBar.style.width = '0%';
progressPercent.textContent = '0%';
}, 2000);
}, 1500);
}
function createFaceMarkers() {
faceMarkersContainer.innerHTML = '';
detectedFaces.forEach((face, index) => {
// Add marker to preview
const marker = document.createElement('div');
marker.className = 'face-marker';
marker.style.left = `${face.x - face.width/2}px`;
marker.style.top = `${face.y - face.height/2}px`;
marker.style.width = `${face.width}px`;
marker.style.height = `${face.height}px`;
marker.id = `marker-${face.id}`;
previewContainer.appendChild(marker);
// Add control to face markers container
const faceControl = document.createElement('div');
faceControl.className = 'bg-gray-700 rounded-lg p-3 flex items-center';
faceControl.innerHTML = `
<div class="w-10 h-10 rounded-full bg-purple-900 flex items-center justify-center mr-3">
<i class="fas fa-user text-purple-400"></i>
</div>
<div>
<div class="font-medium">Face ${index + 1}</div>
<div class="text-xs text-gray-400">Consistency: High</div>
</div>
<div class="ml-auto flex space-x-2">
<button class="text-gray-400 hover:text-purple-400 transition" onclick="adjustFaceMarker('${face.id}', 'smaller')">
<i class="fas fa-search-minus"></i>
</button>
<button class="text-gray-400 hover:text-purple-400 transition" onclick="adjustFaceMarker('${face.id}', 'larger')">
<i class="fas fa-search-plus"></i>
</button>
<button class="text-gray-400 hover:text-red-400 transition" onclick="removeFaceMarker('${face.id}')">
<i class="fas fa-times"></i>
</button>
</div>
`;
faceMarkersContainer.appendChild(faceControl);
});
}
function adjustFaceMarker(faceId, action) {
const marker = document.getElementById(`marker-${faceId}`);
if (!marker) return;
const currentWidth = parseInt(marker.style.width);
const currentHeight = parseInt(marker.style.height);
if (action === 'larger') {
marker.style.width = `${currentWidth * 1.1}px`;
marker.style.height = `${currentHeight * 1.1}px`;
marker.style.left = `${parseInt(marker.style.left) - currentWidth * 0.05}px`;
marker.style.top = `${parseInt(marker.style.top) - currentHeight * 0.05}px`;
} else {
marker.style.width = `${currentWidth * 0.9}px`;
marker.style.height = `${currentHeight * 0.9}px`;
marker.style.left = `${parseInt(marker.style.left) + currentWidth * 0.05}px`;
marker.style.top = `${parseInt(marker.style.top) + currentHeight * 0.05}px`;
}
}
function removeFaceMarker(faceId) {
const marker = document.getElementById(`marker-${faceId}`);
if (marker) marker.remove();
detectedFaces = detectedFaces.filter(face => face.id !== faceId);
// Re-render face controls
createFaceMarkers();
if (detectedFaces.length === 0) {
faceMarkersContainer.innerHTML = '<div class="text-gray-400">No faces detected. Try adjusting the detection.</div>';
}
}
function previewGeneration() {
if (!uploadedImage || detectedFaces.length === 0) return;
statusMessage.textContent = "Generating preview animation...";
progressSection.classList.remove('hidden');
let progress = 0;
const interval = setInterval(() => {
progress += 5;
progressBar.style.width = `${progress}%`;
progressPercent.textContent = `${progress}%`;
if (progress >= 100) {
clearInterval(interval);
statusMessage.textContent = "Preview generated! Click Generate Video to create the full version.";
// Simulate showing a preview (in a real app, this would show an actual preview)
setTimeout(() => {
progressSection.classList.add('hidden');
progressBar.style.width = '0%';
progressPercent.textContent = '0%';
alert("Preview generation complete! This is a simulation. In a real app, you would see a short preview of the animation.");
}, 1000);
}
}, 100);
}
function generateVideo() {
if (!uploadedImage || detectedFaces.length === 0) return;
statusMessage.textContent = "Starting video generation with face consistency...";
progressSection.classList.remove('hidden');
let progress = 0;
const messages = [
"Preparing source image...",
"Applying face consistency models...",
"Generating animation frames...",
"Enhancing details...",
"Finalizing video output..."
];
const interval = setInterval(() => {
progress += 2;
if (progress <= 100) {
progressBar.style.width = `${progress}%`;
progressPercent.textContent = `${progress}%`;
// Update status message based on progress
const messageIndex = Math.min(Math.floor(progress / 20), messages.length - 1);
statusMessage.textContent = messages[messageIndex];
}
if (progress >= 100) {
clearInterval(interval);
statusMessage.textContent = "Video generation complete!";
// Simulate completion
setTimeout(() => {
alert("Video generation complete! This is a simulation. In a real app, you would be able to download the generated video.");
progressSection.classList.add('hidden');
progressBar.style.width = '0%';
progressPercent.textContent = '0%';
}, 1500);
}
}, 100);
}
// Make functions available globally for button clicks in face markers
window.adjustFaceMarker = adjustFaceMarker;
window.removeFaceMarker = removeFaceMarker;
// Handle window resize
window.addEventListener('resize', () => {
if (uploadedImage) {
displayImage();
}
});
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=ES14195595/spank" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>