Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>AI Adult Content Creator | OnlyFans Toolkit</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"> | |
<script src="https://cdn.jsdelivr.net/npm/face-api.js"></script> | |
<style> | |
.editor-container { | |
background: linear-gradient(135deg, #2b2d42 0%, #1a1a2e 100%); | |
} | |
.tool-btn { | |
transition: all 0.3s ease; | |
} | |
.tool-btn:hover { | |
transform: translateY(-3px); | |
box-shadow: 0 10px 20px rgba(255, 20, 147, 0.3); | |
} | |
.preview-box { | |
box-shadow: 0 20px 25px -5px rgba(0,0,0,0.3), 0 10px 10px -5px rgba(0,0,0,0.1); | |
} | |
.slider-thumb::-webkit-slider-thumb { | |
-webkit-appearance: none; | |
appearance: none; | |
width: 20px; | |
height: 20px; | |
border-radius: 50%; | |
background: #ff1493; | |
cursor: pointer; | |
} | |
.tab-active { | |
border-bottom: 3px solid #ff1493; | |
} | |
.image-thumbnail { | |
transition: all 0.2s ease; | |
} | |
.image-thumbnail:hover { | |
transform: scale(1.05); | |
box-shadow: 0 4px 6px rgba(255, 20, 147, 0.3); | |
} | |
.image-thumbnail.active { | |
border: 2px solid #ff1493; | |
} | |
.prompt-box { | |
min-height: 100px; | |
resize: vertical; | |
} | |
.pose-preview { | |
background-size: contain; | |
background-repeat: no-repeat; | |
background-position: center; | |
} | |
.processing-overlay { | |
position: absolute; | |
top: 0; | |
left: 0; | |
right: 0; | |
bottom: 0; | |
background: rgba(0,0,0,0.8); | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
justify-content: center; | |
color: white; | |
z-index: 10; | |
} | |
.face-landmarks { | |
position: absolute; | |
width: 20px; | |
height: 20px; | |
background: rgba(255, 20, 147, 0.7); | |
border-radius: 50%; | |
transform: translate(-50%, -50%); | |
} | |
.selection-box { | |
position: absolute; | |
border: 2px dashed #ff1493; | |
background: rgba(255, 20, 147, 0.2); | |
z-index: 5; | |
} | |
.predictive-options { | |
position: absolute; | |
background: #2b2d42; | |
border-radius: 4px; | |
box-shadow: 0 2px 10px rgba(0,0,0,0.3); | |
z-index: 20; | |
padding: 5px; | |
border: 1px solid #ff1493; | |
} | |
.predictive-option { | |
padding: 8px 12px; | |
cursor: pointer; | |
border-radius: 3px; | |
color: white; | |
} | |
.predictive-option:hover { | |
background: #ff1493; | |
} | |
.effect-thumb { | |
background-size: cover; | |
background-position: center; | |
} | |
.nsfw-badge { | |
position: absolute; | |
top: 10px; | |
right: 10px; | |
background: #ff1493; | |
color: white; | |
padding: 2px 8px; | |
border-radius: 12px; | |
font-size: 10px; | |
font-weight: bold; | |
} | |
.category-tag { | |
display: inline-block; | |
background: rgba(255, 20, 147, 0.2); | |
color: #ff1493; | |
padding: 2px 8px; | |
border-radius: 12px; | |
font-size: 12px; | |
margin-right: 5px; | |
margin-bottom: 5px; | |
} | |
.face-detection-box { | |
position: absolute; | |
border: 2px solid #00ff00; | |
background: rgba(0, 255, 0, 0.1); | |
z-index: 5; | |
} | |
.face-swap-preview { | |
position: relative; | |
overflow: hidden; | |
} | |
.face-swap-canvas { | |
position: absolute; | |
top: 0; | |
left: 0; | |
} | |
</style> | |
</head> | |
<body class="bg-gray-900 text-gray-100"> | |
<!-- Header --> | |
<header class="bg-gray-800 shadow-sm"> | |
<div class="container mx-auto px-4 py-4 flex justify-between items-center"> | |
<div class="flex items-center space-x-2"> | |
<i class="fas fa-venus-mars text-pink-600 text-2xl"></i> | |
<h1 class="text-xl font-bold">AI Adult Content Creator</h1> | |
</div> | |
<nav class="hidden md:flex space-x-8"> | |
<a href="#" class="text-gray-400 hover:text-pink-500 font-medium">Dashboard</a> | |
<a href="#" class="text-gray-400 hover:text-pink-500 font-medium">Templates</a> | |
<a href="#" class="text-gray-400 hover:text-pink-500 font-medium">Analytics</a> | |
<a href="#" class="text-gray-400 hover:text-pink-500 font-medium">Monetization</a> | |
</nav> | |
<div class="flex items-center space-x-4"> | |
<button class="px-4 py-2 rounded-md text-gray-400 hover:bg-gray-700"> | |
<i class="fas fa-bell text-xl"></i> | |
</button> | |
<button class="px-4 py-2 bg-pink-600 text-white rounded-md hover:bg-pink-700"> | |
<i class="fas fa-rocket mr-2"></i> Premium | |
</button> | |
</div> | |
</div> | |
</header> | |
<!-- Main Content --> | |
<main class="container mx-auto px-4 py-8"> | |
<div class="flex flex-col lg:flex-row gap-8"> | |
<!-- Tools Panel --> | |
<div class="w-full lg:w-1/4 bg-gray-800 rounded-xl shadow-md p-6 h-fit"> | |
<div class="flex border-b border-gray-700 mb-6"> | |
<button id="image-tab" class="tab-active px-4 py-2 font-medium text-pink-500">Photo</button> | |
<button id="video-tab" class="px-4 py-2 font-medium text-gray-400 hover:text-pink-500">Video</button> | |
</div> | |
<div id="image-tools"> | |
<!-- Multi Image Upload --> | |
<div class="mb-6"> | |
<h3 class="font-medium text-gray-300 mb-3">Upload Content</h3> | |
<div class="border-2 border-dashed border-gray-700 rounded-lg p-4 text-center cursor-pointer hover:bg-gray-700 mb-3" id="upload-area"> | |
<i class="fas fa-cloud-upload-alt text-3xl text-gray-500 mb-2"></i> | |
<p class="text-gray-400">Drag & drop NSFW content</p> | |
<p class="text-sm text-gray-500 mt-1">or click to browse</p> | |
<input type="file" id="file-upload" class="hidden" accept="image/*,video/*" multiple> | |
</div> | |
<div id="thumbnail-container" class="grid grid-cols-3 gap-2 mt-2 max-h-40 overflow-y-auto"></div> | |
</div> | |
<!-- AI Prompts --> | |
<div class="mb-6"> | |
<h3 class="font-medium text-gray-300 mb-3">AI Enhancement Prompts</h3> | |
<div class="relative"> | |
<textarea id="ai-prompt" class="w-full border border-gray-700 bg-gray-700 rounded-md p-2 text-sm prompt-box" placeholder="Describe your desired enhancements (e.g. 'make ass bigger', 'enhance curves', 'add toy')"></textarea> | |
<div class="absolute right-2 bottom-2 text-gray-400 text-xs"> | |
<span id="char-count">0</span>/200 | |
</div> | |
</div> | |
<div class="mt-2 grid grid-cols-2 gap-2"> | |
<button onclick="applyPrompt('Enhance curves, make ass bigger, smooth skin, perfect lighting')" class="px-2 py-1 bg-gray-700 text-xs rounded hover:bg-pink-600 hover:text-white">Body Enhance</button> | |
<button onclick="applyPrompt('Add realistic dildo, perfect lighting, professional look')" class="px-2 py-1 bg-gray-700 text-xs rounded hover:bg-pink-600 hover:text-white">Add Toy</button> | |
<button onclick="showFaceSwapModal()" class="px-2 py-1 bg-gray-700 text-xs rounded hover:bg-pink-600 hover:text-white">Face Swap</button> | |
<button onclick="applyPrompt('Smooth skin, remove blemishes, perfect lighting, professional retouch')" class="px-2 py-1 bg-gray-700 text-xs rounded hover:bg-pink-600 hover:text-white">Skin Perfect</button> | |
</div> | |
</div> | |
<!-- Content Categories --> | |
<div class="mb-6"> | |
<h3 class="font-medium text-gray-300 mb-3">Content Categories</h3> | |
<div class="flex flex-wrap"> | |
<span class="category-tag cursor-pointer" onclick="applyPrompt('Solo female, teasing, implied nudity, perfect lighting')">Solo Tease</span> | |
<span class="category-tag cursor-pointer" onclick="applyPrompt('Explicit solo, legs spread, close-up, wet look')">Explicit Solo</span> | |
<span class="category-tag cursor-pointer" onclick="applyPrompt('Butt plug, anal play, bent over, high resolution')">Anal Play</span> | |
<span class="category-tag cursor-pointer" onclick="applyPrompt('Dildo play, penetration, wet look, professional lighting')">Toy Play</span> | |
<span class="category-tag cursor-pointer" onclick="applyPrompt('Lingerie, stockings, high heels, seductive pose')">Lingerie</span> | |
<span class="category-tag cursor-pointer" onclick="applyPrompt('Outdoor, risky, public flash, natural lighting')">Outdoor</span> | |
<span class="category-tag cursor-pointer" onclick="applyPrompt('BDSM, restraints, domination, professional setup')">BDSM</span> | |
<span class="category-tag cursor-pointer" onclick="applyPrompt('Cosplay, fantasy, roleplay, perfect costume')">Cosplay</span> | |
</div> | |
</div> | |
<!-- Body Tools --> | |
<div class="mb-6"> | |
<h3 class="font-medium text-gray-300 mb-3">Body Enhancements</h3> | |
<div class="space-y-4"> | |
<div> | |
<label class="block text-sm text-gray-400 mb-1">Breast Size <span class="text-pink-500" id="breast-value">0%</span></label> | |
<input type="range" class="w-full slider-thumb" id="breast-slider" min="-30" max="50" value="0" oninput="updateBodyParam('breast', this.value)"> | |
<div class="flex justify-between text-xs text-gray-500"> | |
<span>Smaller</span> | |
<span>Larger</span> | |
</div> | |
</div> | |
<div> | |
<label class="block text-sm text-gray-400 mb-1">Ass Size <span class="text-pink-500" id="ass-value">0%</span></label> | |
<input type="range" class="w-full slider-thumb" id="ass-slider" min="-20" max="60" value="0" oninput="updateBodyParam('ass', this.value)"> | |
<div class="flex justify-between text-xs text-gray-500"> | |
<span>Smaller</span> | |
<span>Bubble</span> | |
</div> | |
</div> | |
<div> | |
<label class="block text-sm text-gray-400 mb-1">Waist Slimness <span class="text-pink-500" id="waist-value">0%</span></label> | |
<input type="range" class="w-full slider-thumb" id="waist-slider" min="-30" max="40" value="0" oninput="updateBodyParam('waist', this.value)"> | |
<div class="flex justify-between text-xs text-gray-500"> | |
<span>Thicker</span> | |
<span>Slimmer</span> | |
</div> | |
</div> | |
<div> | |
<label class="block text-sm text-gray-400 mb-1">Pussy Plumpness <span class="text-pink-500" id="pussy-value">0%</span></label> | |
<input type="range" class="w-full slider-thumb" id="pussy-slider" min="-20" max="40" value="0" oninput="updateBodyParam('pussy', this.value)"> | |
<div class="flex justify-between text-xs text-gray-500"> | |
<span>Less</span> | |
<span>More</span> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Toy & Prop Tools --> | |
<div class="mb-6"> | |
<h3 class="font-medium text-gray-300 mb-3">Toys & Props</h3> | |
<div class="grid grid-cols-3 gap-3"> | |
<button class="tool-btn flex flex-col items-center p-3 bg-gray-700 rounded-lg hover:bg-pink-600 hover:text-white" onclick="applyPrompt('Add realistic pink dildo to scene, perfect lighting, professional look')"> | |
<i class="fas fa-dildo text-pink-500 text-xl mb-1"></i> | |
<span class="text-xs">Dildo</span> | |
</button> | |
<button class="tool-btn flex flex-col items-center p-3 bg-gray-700 rounded-lg hover:bg-pink-600 hover:text-white" onclick="applyPrompt('Add jeweled butt plug, make it look realistic, perfect lighting')"> | |
<i class="fas fa-gem text-pink-500 text-xl mb-1"></i> | |
<span class="text-xs">Butt Plug</span> | |
</button> | |
<button class="tool-btn flex flex-col items-center p-3 bg-gray-700 rounded-lg hover:bg-pink-600 hover:text-white" onclick="applyPrompt('Add vibrator to hand, make it look realistic, perfect lighting')"> | |
<i class="fas fa-vibrate text-pink-500 text-xl mb-1"></i> | |
<span class="text-xs">Vibrator</span> | |
</button> | |
<button class="tool-btn flex flex-col items-center p-3 bg-gray-700 rounded-lg hover:bg-pink-600 hover:text-white" onclick="applyPrompt('Add realistic cum effect on body, perfect lighting, professional look')"> | |
<i class="fas fa-tint text-pink-500 text-xl mb-1"></i> | |
<span class="text-xs">Cum Effect</span> | |
</button> | |
<button class="tool-btn flex flex-col items-center p-3 bg-gray-700 rounded-lg hover:bg-pink-600 hover:text-white" onclick="applyPrompt('Add rope bondage to wrists and ankles, realistic texture, perfect lighting')"> | |
<i class="fas fa-hands-bound text-pink-500 text-xl mb-1"></i> | |
<span class="text-xs">Bondage</span> | |
</button> | |
<button class="tool-btn flex flex-col items-center p-3 bg-gray-700 rounded-lg hover:bg-pink-600 hover:text-white" onclick="applyPrompt('Add lace lingerie set, make it look realistic, perfect lighting')"> | |
<i class="fas fa-tshirt text-pink-500 text-xl mb-1"></i> | |
<span class="text-xs">Lingerie</span> | |
</button> | |
</div> | |
</div> | |
<!-- Pose Maker --> | |
<div class="mb-6"> | |
<h3 class="font-medium text-gray-300 mb-3">Pose Generator</h3> | |
<div class="grid grid-cols-3 gap-2 mb-3"> | |
<div class="pose-preview h-16 bg-gray-700 rounded cursor-pointer hover:ring-2 hover:ring-pink-500" onclick="applyPose('bent-over')" style="background-image: url('https://i.imgur.com/JQlE0gP.png')"></div> | |
<div class="pose-preview h-16 bg-gray-700 rounded cursor-pointer hover:ring-2 hover:ring-pink-500" onclick="applyPose('legs-spread')" style="background-image: url('https://i.imgur.com/5XkJQqG.png')"></div> | |
<div class="pose-preview h-16 bg-gray-700 rounded cursor-pointer hover:ring-2 hover:ring-pink-500" onclick="applyPose('doggy')" style="background-image: url('https://i.imgur.com/8zJqWQk.png')"></div> | |
<div class="pose-preview h-16 bg-gray-700 rounded cursor-pointer hover:ring-2 hover:ring-pink-500" onclick="applyPose('missionary')" style="background-image: url('https://i.imgur.com/3mJQkqG.png')"></div> | |
<div class="pose-preview h-16 bg-gray-700 rounded cursor-pointer hover:ring-2 hover:ring-pink-500" onclick="applyPose('squat')" style="background-image: url('https://i.imgur.com/7XkJQqG.png')"></div> | |
<div class="pose-preview h-16 bg-gray-700 rounded cursor-pointer hover:ring-2 hover:ring-pink-500" onclick="applyPose('standing-tease')" style="background-image: url('https://i.imgur.com/9zJqWQk.png')"></div> | |
</div> | |
<button class="w-full py-2 bg-pink-900 text-pink-300 rounded-md text-sm hover:bg-pink-700 hover:text-white" onclick="showCustomPoseModal()"> | |
<i class="fas fa-plus mr-1"></i> Custom Pose | |
</button> | |
</div> | |
<!-- Background Tools --> | |
<div class="mb-6"> | |
<h3 class="font-medium text-gray-300 mb-3">Background</h3> | |
<div class="grid grid-cols-3 gap-3"> | |
<button class="tool-btn flex flex-col items-center p-3 bg-gray-700 rounded-lg hover:bg-pink-600 hover:text-white" onclick="applyPrompt('Change background to luxury bedroom, perfect lighting, professional setup')"> | |
<i class="fas fa-bed text-pink-500 text-xl mb-1"></i> | |
<span class="text-xs">Bedroom</span> | |
</button> | |
<button class="tool-btn flex flex-col items-center p-3 bg-gray-700 rounded-lg hover:bg-pink-600 hover:text-white" onclick="applyPrompt('Change background to hotel room, perfect lighting, professional setup')"> | |
<i class="fas fa-hotel text-pink-500 text-xl mb-1"></i> | |
<span class="text-xs">Hotel</span> | |
</button> | |
<button class="tool-btn flex flex-col items-center p-3 bg-gray-700 rounded-lg hover:bg-pink-600 hover:text-white" onclick="applyPrompt('Change background to outdoor pool, perfect lighting, professional setup')"> | |
<i class="fas fa-umbrella-beach text-pink-500 text-xl mb-1"></i> | |
<span class="text-xs">Outdoor</span> | |
</button> | |
</div> | |
</div> | |
</div> | |
<div id="video-tools" class="hidden"> | |
<!-- Video tools content --> | |
<div class="text-center py-8 text-gray-500"> | |
<i class="fas fa-video text-3xl mb-2"></i> | |
<p>Video editing coming soon!</p> | |
</div> | |
</div> | |
</div> | |
<!-- Editor Area --> | |
<div class="w-full lg:w-2/4 editor-container rounded-xl p-6"> | |
<div class="preview-box bg-gray-800 rounded-lg overflow-hidden relative" style="height: 600px;"> | |
<div class="absolute inset-0 flex items-center justify-center" id="placeholder"> | |
<div class="text-center"> | |
<i class="fas fa-image text-gray-600 text-5xl mb-3"></i> | |
<p class="text-gray-500">Upload NSFW content to start editing</p> | |
</div> | |
</div> | |
<div id="preview-container" class="relative w-full h-full hidden"> | |
<img id="preview-image" src="" alt="" class="w-full h-full object-contain"> | |
<video id="preview-video" controls class="hidden w-full h-full object-contain"></video> | |
<canvas id="face-swap-canvas" class="face-swap-canvas"></canvas> | |
</div> | |
<div id="processing-overlay" class="processing-overlay hidden"> | |
<i class="fas fa-spinner fa-spin text-4xl mb-4 text-pink-500"></i> | |
<p id="processing-text" class="text-xl">Processing your content...</p> | |
<div class="w-full bg-gray-700 rounded-full h-2.5 mt-4 max-w-md"> | |
<div id="progress-bar" class="bg-pink-500 h-2.5 rounded-full" style="width: 0%"></div> | |
</div> | |
<div id="ai-suggestions" class="mt-6 text-center max-w-md hidden"> | |
<h4 class="font-medium mb-2">AI Suggestions</h4> | |
<div class="grid grid-cols-2 gap-2"> | |
<button class="px-3 py-1 bg-pink-700 text-white rounded text-sm hover:bg-pink-600" onclick="applySuggestion('enhance-curves')">Enhance Curves</button> | |
<button class="px-3 py-1 bg-pink-700 text-white rounded text-sm hover:bg-pink-600" onclick="applySuggestion('add-toy')">Add Toy</button> | |
<button class="px-3 py-1 bg-pink-700 text-white rounded text-sm hover:bg-pink-600" onclick="applySuggestion('smooth-skin')">Smooth Skin</button> | |
<button class="px-3 py-1 bg-pink-700 text-white rounded text-sm hover:bg-pink-600" onclick="applySuggestion('sexier-pose')">Sexier Pose</button> | |
</div> | |
</div> | |
</div> | |
<div class="nsfw-badge hidden">NSFW</div> | |
</div> | |
<div class="mt-6 flex flex-wrap justify-center gap-3"> | |
<button id="undo-btn" class="px-4 py-2 bg-gray-700 text-gray-300 rounded-md hover:bg-gray-600 disabled:opacity-50" disabled> | |
<i class="fas fa-undo mr-2"></i> Undo | |
</button> | |
<button id="redo-btn" class="px-4 py-2 bg-gray-700 text-gray-300 rounded-md hover:bg-gray-600 disabled:opacity-50" disabled> | |
<i class="fas fa-redo mr-2"></i> Redo | |
</button> | |
<button id="reset-btn" class="px-4 py-2 bg-gray-700 text-gray-300 rounded-md hover:bg-gray-600" onclick="resetEditor()"> | |
<i class="fas fa-trash-alt mr-2"></i> Reset | |
</button> | |
<button id="auto-enhance-btn" class="px-6 py-2 bg-pink-800 text-pink-200 rounded-md hover:bg-pink-700 hover:text-white" onclick="autoEnhance()"> | |
<i class="fas fa-magic mr-2"></i> Auto-Enhance | |
</button> | |
<button id="process-btn" class="px-6 py-2 bg-pink-600 text-white rounded-md hover:bg-pink-700" onclick="processImage()"> | |
<i class="fas fa-cogs mr-2"></i> Process | |
</button> | |
<button id="save-btn" class="px-6 py-2 bg-purple-600 text-white rounded-md hover:bg-purple-700" onclick="saveImage()"> | |
<i class="fas fa-download mr-2"></i> Save | |
</button> | |
</div> | |
<!-- Predictive AI Suggestions --> | |
<div id="predictive-suggestions" class="mt-6 bg-gray-800 rounded-lg p-4 hidden"> | |
<h3 class="font-medium text-gray-300 mb-3 flex justify-between items-center"> | |
<span>AI Suggestions</span> | |
<button onclick="hidePredictiveSuggestions()" class="text-gray-400 hover:text-white"> | |
<i class="fas fa-times"></i> | |
</button> | |
</h3> | |
<div class="grid grid-cols-2 md:grid-cols-4 gap-3"> | |
<button class="px-3 py-2 bg-gray-700 rounded text-sm hover:bg-pink-600 hover:text-white flex items-center" onclick="applySuggestion('enhance-curves')"> | |
<i class="fas fa-venus mr-2"></i> Enhance Curves | |
</button> | |
<button class="px-3 py-2 bg-gray-700 rounded text-sm hover:bg-pink-600 hover:text-white flex items-center" onclick="applySuggestion('bigger-ass')"> | |
<i class="fas fa-pepper-hot mr-2"></i> Bigger Ass | |
</button> | |
<button class="px-3 py-2 bg-gray-700 rounded text-sm hover:bg-pink-600 hover:text-white flex items-center" onclick="applySuggestion('add-toy')"> | |
<i class="fas fa-dildo mr-2"></i> Add Toy | |
</button> | |
<button class="px-3 py-2 bg-gray-700 rounded text-sm hover:bg-pink-600 hover:text-white flex items-center" onclick="applySuggestion('sexier-pose')"> | |
<i class="fas fa-fire mr-2"></i> Sexier Pose | |
</button> | |
<button class="px-3 py-2 bg-gray-700 rounded text-sm hover:bg-pink-600 hover:text-white flex items-center" onclick="applySuggestion('smooth-skin')"> | |
<i class="fas fa-spa mr-2"></i> Smooth Skin | |
</button> | |
<button class="px-3 py-2 bg-gray-700 rounded text-sm hover:bg-pink-600 hover:text-white flex items-center" onclick="applySuggestion('better-lighting')"> | |
<i class="fas fa-lightbulb mr-2"></i> Better Lighting | |
</button> | |
<button class="px-3 py-2 bg-gray-700 rounded text-sm hover:bg-pink-600 hover:text-white flex items-center" onclick="applySuggestion('add-lingerie')"> | |
<i class="fas fa-tshirt mr-2"></i> Add Lingerie | |
</button> | |
<button class="px-3 py-2 bg-gray-700 rounded text-sm hover:bg-pink-600 hover:text-white flex items-center" onclick="applySuggestion('add-plug')"> | |
<i class="fas fa-gem mr-2"></i> Add Plug | |
</button> | |
</div> | |
</div> | |
</div> | |
<!-- Layers Panel --> | |
<div class="w-full lg:w-1/4 bg-gray-800 rounded-xl shadow-md p-6 h-fit"> | |
<div class="flex justify-between items-center mb-4"> | |
<h3 class="font-medium text-gray-300">Content Library</h3> | |
<button class="text-pink-500 hover:text-pink-300" onclick="document.getElementById('file-upload').click()"> | |
<i class="fas fa-plus"></i> | |
</button> | |
</div> | |
<div id="reference-container" class="space-y-3 max-h-64 overflow-y-auto"> | |
<!-- Reference images will appear here --> | |
</div> | |
<div class="mt-6"> | |
<h3 class="font-medium text-gray-300 mb-3">Quick Edits</h3> | |
<div class="grid grid-cols-2 gap-3"> | |
<button class="px-3 py-2 bg-gray-700 rounded text-sm hover:bg-pink-600 hover:text-white" onclick="quickEdit('blur-background')"> | |
<i class="fas fa-eye-slash mr-1"></i> Blur BG | |
</button> | |
<button class="px-3 py-2 bg-gray-700 rounded text-sm hover:bg-pink-600 hover:text-white" onclick="quickEdit('enhance-nipples')"> | |
<i class="fas fa-dot-circle mr-1"></i> Enhance Nipples | |
</button> | |
<button class="px-3 py-2 bg-gray-700 rounded text-sm hover:bg-pink-600 hover:text-white" onclick="quickEdit('plump-lips')"> | |
<i class="fas fa-lips mr-1"></i> Plump Lips | |
</button> | |
<button class="px-3 py-2 bg-gray-700 rounded text-sm hover:bg-pink-600 hover:text-white" onclick="quickEdit('smooth-skin')"> | |
<i class="fas fa-spa mr-1"></i> Smooth Skin | |
</button> | |
</div> | |
</div> | |
<div class="mt-6"> | |
<h3 class="font-medium text-gray-300 mb-3">OnlyFans Tools</h3> | |
<div class="space-y-3"> | |
<button class="w-full py-2 bg-pink-700 text-white rounded-md text-sm hover:bg-pink-600 flex items-center justify-center" onclick="addWatermark()"> | |
<i class="fas fa-copyright mr-2"></i> Add Watermark | |
</button> | |
<button class="w-full py-2 bg-purple-700 text-white rounded-md text-sm hover:bg-purple-600 flex items-center justify-center" onclick="generateTeaser()"> | |
<i class="fas fa-lock-open mr-2"></i> Create Teaser | |
</button> | |
<button class="w-full py-2 bg-gray-700 text-white rounded-md text-sm hover:bg-gray-600 flex items-center justify-center" onclick="showSocialModal()"> | |
<i class="fas fa-share-alt mr-2"></i> Social Preview | |
</button> | |
</div> | |
</div> | |
<div class="mt-6"> | |
<h3 class="font-medium text-gray-300 mb-3">Export Options</h3> | |
<div class="space-y-3"> | |
<div class="flex items-center"> | |
<input type="radio" id="format-jpg" name="export-format" class="mr-2" checked> | |
<label for="format-jpg" class="text-sm">JPG (Recommended)</label> | |
</div> | |
<div class="flex items-center"> | |
<input type="radio" id="format-png" name="export-format" class="mr-2"> | |
<label for="format-png" class="text-sm">PNG (Lossless)</label> | |
</div> | |
<div class="flex items-center"> | |
<input type="radio" id="format-webp" name="export-format" class="mr-2"> | |
<label for="format-webp" class="text-sm">WebP (Smaller)</label> | |
</div> | |
</div> | |
<div class="mt-3"> | |
<label class="block text-sm text-gray-400 mb-1">Quality</label> | |
<input type="range" id="export-quality" class="w-full slider-thumb" min="50" max="100" value="90"> | |
<div class="flex justify-between text-xs text-gray-500"> | |
<span>Low</span> | |
<span>High</span> | |
</div> | |
</div> | |
<div class="mt-3"> | |
<label class="block text-sm text-gray-400 mb-1">Resolution</label> | |
<select id="export-resolution" class="w-full p-2 border border-gray-700 bg-gray-700 rounded-md text-sm"> | |
<option value="original">Original</option> | |
<option value="1080">1080p (HD)</option> | |
<option value="720">720p</option> | |
<option value="4k">4K (UHD)</option> | |
</select> | |
</div> | |
</div> | |
<div class="mt-6"> | |
<h3 class="font-medium text-gray-300 mb-3">Content Stats</h3> | |
<div class="bg-gray-700 rounded-md p-3 text-sm"> | |
<div class="flex justify-between mb-1"> | |
<span class="text-gray-400">Engagement Score:</span> | |
<span class="text-pink-400" id="engagement-score">--</span> | |
</div> | |
<div class="flex justify-between mb-1"> | |
<span class="text-gray-400">Spicy Level:</span> | |
<span class="text-pink-400" id="spicy-level">--</span> | |
</div> | |
<div class="flex justify-between mb-1"> | |
<span class="text-gray-400">Market Value:</span> | |
<span class="text-pink-400" id="market-value">--</span> | |
</div> | |
<div class="flex justify-between"> | |
<span class="text-gray-400">AI Rating:</span> | |
<span class="text-pink-400" id="ai-rating">--</span> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</main> | |
<!-- Face Swap Modal --> | |
<div id="face-swap-modal" class="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center hidden z-50"> | |
<div class="bg-gray-800 rounded-lg p-6 w-full max-w-2xl border border-pink-500"> | |
<div class="flex justify-between items-center mb-4"> | |
<h3 class="text-lg font-medium text-white">Face Swap</h3> | |
<button onclick="hideFaceSwapModal()" class="text-gray-400 hover:text-white"> | |
<i class="fas fa-times"></i> | |
</button> | |
</div> | |
<div class="grid grid-cols-2 gap-4 mb-4"> | |
<div> | |
<h4 class="text-sm font-medium mb-2 text-gray-300">Source Face</h4> | |
<select id="modal-source-face" class="w-full p-2 border border-gray-700 bg-gray-700 rounded-md text-sm mb-2 text-white" onchange="updateFacePreview('source')"> | |
<option value="" class="text-gray-400">Select reference image</option> | |
</select> | |
<div class="border border-gray-700 rounded-md h-40 bg-gray-700 flex items-center justify-center relative face-swap-preview" id="source-face-preview"> | |
<span class="text-gray-500">No image selected</span> | |
</div> | |
</div> | |
<div> | |
<h4 class="text-sm font-medium mb-2 text-gray-300">Target Face</h4> | |
<select id="modal-target-face" class="w-full p-2 border border-gray-700 bg-gray-700 rounded-md text-sm mb-2 text-white" onchange="updateFacePreview('target')"> | |
<option value="" class="text-gray-400">Select reference image</option> | |
</select> | |
<div class="border border-gray-700 rounded-md h-40 bg-gray-700 flex items-center justify-center relative face-swap-preview" id="target-face-preview"> | |
<span class="text-gray-500">No image selected</span> | |
</div> | |
</div> | |
</div> | |
<div class="mb-4"> | |
<label class="block text-sm text-gray-400 mb-1">Face Alignment Strength</label> | |
<input type="range" id="face-align-strength" class="w-full slider-thumb" min="0" max="100" value="75"> | |
</div> | |
<div class="mb-4"> | |
<label class="block text-sm text-gray-400 mb-1">Skin Tone Matching</label> | |
<input type="range" id="skin-tone-match" class="w-full slider-thumb" min="0" max="100" value="50"> | |
</div> | |
<div class="mb-4"> | |
<label class="block text-sm text-gray-400 mb-1">Blending Intensity</label> | |
<input type="range" id="blend-intensity" class="w-full slider-thumb" min="0" max="100" value="80"> | |
</div> | |
<div class="flex justify-end space-x-3"> | |
<button onclick="hideFaceSwapModal()" class="px-4 py-2 bg-gray-700 text-gray-300 rounded-md hover:bg-gray-600"> | |
Cancel | |
</button> | |
<button onclick="applyModalFaceSwap()" class="px-4 py-2 bg-pink-600 text-white rounded-md hover:bg-pink-700"> | |
Apply Face Swap | |
</button> | |
</div> | |
</div> | |
</div> | |
<!-- Custom Pose Modal --> | |
<div id="custom-pose-modal" class="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center hidden z-50"> | |
<div class="bg-gray-800 rounded-lg p-6 w-full max-w-2xl border border-pink-500"> | |
<div class="flex justify-between items-center mb-4"> | |
<h3 class="text-lg font-medium text-white">Create Custom Pose</h3> | |
<button onclick="hideCustomPoseModal()" class="text-gray-400 hover:text-white"> | |
<i class="fas fa-times"></i> | |
</button> | |
</div> | |
<div class="mb-4"> | |
<label class="block text-sm text-gray-400 mb-1">Pose Description</label> | |
<textarea id="pose-description" class="w-full border border-gray-700 bg-gray-700 rounded-md p-2 text-sm text-white" placeholder="Describe the pose you want (e.g. 'bent over, ass up, looking back')"></textarea> | |
</div> | |
<div class="mb-4"> | |
<label class="block text-sm text-gray-400 mb-1">Pose Strength</label> | |
<input type="range" id="pose-strength" class="w-full slider-thumb" min="0" max="100" value="50"> | |
</div> | |
<div class="mb-4"> | |
<label class="block text-sm text-gray-400 mb-1">Suggestions</label> | |
<div class="grid grid-cols-2 gap-2"> | |
<button class="px-2 py-1 bg-gray-700 text-xs rounded hover:bg-pink-600 hover:text-white" onclick="document.getElementById('pose-description').value = 'bent over, ass up, looking back'">Bent Over</button> | |
<button class="px-2 py-1 bg-gray-700 text-xs rounded hover:bg-pink-600 hover:text-white" onclick="document.getElementById('pose-description').value = 'legs spread, touching self'">Legs Spread</button> | |
<button class="px-2 py-1 bg-gray-700 text-xs rounded hover:bg-pink-600 hover:text-white" onclick="document.getElementById('pose-description').value = 'on knees, chest up, mouth open'">Kneeling</button> | |
<button class="px-2 py-1 bg-gray-700 text-xs rounded hover:bg-pink-600 hover:text-white" onclick="document.getElementById('pose-description').value = 'squatting, showing everything'">Squatting</button> | |
</div> | |
</div> | |
<div class="flex justify-end space-x-3"> | |
<button onclick="hideCustomPoseModal()" class="px-4 py-2 bg-gray-700 text-gray-300 rounded-md hover:bg-gray-600"> | |
Cancel | |
</button> | |
<button onclick="applyCustomPose()" class="px-4 py-2 bg-pink-600 text-white rounded-md hover:bg-pink-700"> | |
Create Pose | |
</button> | |
</div> | |
</div> | |
</div> | |
<!-- Social Preview Modal --> | |
<div id="social-modal" class="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center hidden z-50"> | |
<div class="bg-gray-800 rounded-lg p-6 w-full max-w-2xl border border-pink-500"> | |
<div class="flex justify-between items-center mb-4"> | |
<h3 class="text-lg font-medium text-white">Social Media Preview</h3> | |
<button onclick="hideSocialModal()" class="text-gray-400 hover:text-white"> | |
<i class="fas fa-times"></i> | |
</button> | |
</div> | |
<div class="grid grid-cols-3 gap-4 mb-4"> | |
<div class="bg-gray-900 p-2 rounded text-center"> | |
<div class="h-32 bg-gray-700 rounded mb-2 flex items-center justify-center"> | |
<i class="fas fa-instagram text-2xl text-pink-500"></i> | |
</div> | |
<p class="text-xs text-gray-400">Instagram</p> | |
</div> | |
<div class="bg-gray-900 p-2 rounded text-center"> | |
<div class="h-32 bg-gray-700 rounded mb-2 flex items-center justify-center"> | |
<i class="fas fa-twitter text-2xl text-blue-400"></i> | |
</div> | |
<p class="text-xs text-gray-400">Twitter</p> | |
</div> | |
<div class="bg-gray-900 p-2 rounded text-center"> | |
<div class="h-32 bg-gray-700 rounded mb-2 flex items-center justify-center"> | |
<i class="fas fa-tiktok text-2xl text-white"></i> | |
</div> | |
<p class="text-xs text-gray-400">TikTok</p> | |
</div> | |
</div> | |
<div class="mb-4"> | |
<label class="block text-sm text-gray-400 mb-1">Preview Text</label> | |
<input type="text" class="w-full p-2 border border-gray-700 bg-gray-700 rounded-md text-sm text-white" value="New content coming soon! 🔥"> | |
</div> | |
<div class="flex justify-end space-x-3"> | |
<button onclick="hideSocialModal()" class="px-4 py-2 bg-gray-700 text-gray-300 rounded-md hover:bg-gray-600"> | |
Close | |
</button> | |
<button onclick="copySocialPreview()" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"> | |
Copy Preview | |
</button> | |
</div> | |
</div> | |
</div> | |
<script> | |
// Global variables | |
let uploadedImages = []; | |
let currentImageIndex = 0; | |
let editHistory = []; | |
let currentHistoryIndex = -1; | |
let bodyParams = { | |
breast: 0, | |
ass: 0, | |
waist: 0, | |
pussy: 0 | |
}; | |
let faceDetectionModelsLoaded = false; | |
// Initialize the editor | |
document.addEventListener('DOMContentLoaded', async function() { | |
// Set up character counter for prompt box | |
const promptBox = document.getElementById('ai-prompt'); | |
const charCount = document.getElementById('char-count'); | |
promptBox.addEventListener('input', function() { | |
charCount.textContent = this.value.length; | |
// Show predictive suggestions if typing | |
if(this.value.length > 10 && !this.value.includes('ass') && !this.value.includes('toy') && !this.value.includes('plug')) { | |
showPredictiveSuggestions(); | |
} | |
}); | |
// Initialize sliders with value displays | |
const sliders = ['breast', 'ass', 'waist', 'pussy']; | |
sliders.forEach(slider => { | |
const sliderElement = document.getElementById(`${slider}-slider`); | |
const valueElement = document.getElementById(`${slider}-value`); | |
sliderElement.addEventListener('input', function() { | |
valueElement.textContent = `${this.value}%`; | |
}); | |
}); | |
// Set up undo/redo buttons | |
document.getElementById('undo-btn').addEventListener('click', undo); | |
document.getElementById('redo-btn').addEventListener('click', redo); | |
// Load face detection models | |
await loadFaceDetectionModels(); | |
// Auto-enhance after first upload | |
let firstUpload = true; | |
}); | |
// Load face detection models | |
async function loadFaceDetectionModels() { | |
try { | |
await faceapi.nets.tinyFaceDetector.loadFromUri('/models'); | |
await faceapi.nets.faceLandmark68Net.loadFromUri('/models'); | |
await faceapi.nets.faceRecognitionNet.loadFromUri('/models'); | |
faceDetectionModelsLoaded = true; | |
console.log('Face detection models loaded successfully'); | |
} catch (error) { | |
console.error('Error loading face detection models:', error); | |
} | |
} | |
// File upload functionality | |
const fileUpload = document.getElementById('file-upload'); | |
const uploadArea = document.getElementById('upload-area'); | |
const thumbnailContainer = document.getElementById('thumbnail-container'); | |
const referenceContainer = document.getElementById('reference-container'); | |
const previewImage = document.getElementById('preview-image'); | |
const previewVideo = document.getElementById('preview-video'); | |
const placeholder = document.getElementById('placeholder'); | |
const previewContainer = document.getElementById('preview-container'); | |
const nsfwBadge = document.querySelector('.nsfw-badge'); | |
// Handle drag and drop | |
uploadArea.addEventListener('dragover', (e) => { | |
e.preventDefault(); | |
uploadArea.classList.add('bg-pink-900', 'border-pink-500'); | |
}); | |
uploadArea.addEventListener('dragleave', () => { | |
uploadArea.classList.remove('bg-pink-900', 'border-pink-500'); | |
}); | |
uploadArea.addEventListener('drop', (e) => { | |
e.preventDefault(); | |
uploadArea.classList.remove('bg-pink-900', 'border-pink-500'); | |
if (e.dataTransfer.files.length > 0) { | |
fileUpload.files = e.dataTransfer.files; | |
handleFileUpload(); | |
} | |
}); | |
uploadArea.addEventListener('click', () => fileUpload.click()); | |
fileUpload.addEventListener('change', handleFileUpload); | |
function handleFileUpload() { | |
const files = fileUpload.files; | |
if (!files || files.length === 0) return; | |
for (let i = 0; i < files.length; i++) { | |
const file = files[i]; | |
if (!file.type.startsWith('image/') && !file.type.startsWith('video/')) continue; | |
const reader = new FileReader(); | |
reader.onload = function(event) { | |
const mediaData = { | |
id: Date.now() + i, | |
src: event.target.result, | |
name: file.name, | |
originalSrc: event.target.result, | |
type: file.type.startsWith('image/') ? 'image' : 'video' | |
}; | |
uploadedImages.push(mediaData); | |
// Add to thumbnail container | |
const thumbnail = document.createElement('div'); | |
thumbnail.className = `image-thumbnail relative ${uploadedImages.length === 1 ? 'active' : ''}`; | |
thumbnail.innerHTML = ` | |
${mediaData.type === 'image' ? | |
`<img src="${mediaData.src}" class="w-full h-full object-cover rounded">` : | |
`<video src="${mediaData.src}" class="w-full h-full object-cover rounded"></video>`} | |
<div class="absolute inset-0 flex items-center justify-center bg-black bg-opacity-0 hover:bg-opacity-30 transition-all duration-200"> | |
<button onclick="setActiveImage(${mediaData.id})" class="text-white opacity-0 hover:opacity-100"> | |
<i class="fas fa-check-circle text-xl"></i> | |
</button> | |
</div> | |
`; | |
thumbnailContainer.appendChild(thumbnail); | |
// Add to reference container | |
const referenceItem = document.createElement('div'); | |
referenceItem.className = 'flex items-center p-2 bg-gray-700 rounded-md hover:bg-gray-600'; | |
referenceItem.innerHTML = ` | |
<div class="w-10 h-10 bg-gray-600 rounded-md mr-3 overflow-hidden"> | |
${mediaData.type === 'image' ? | |
`<img src="${mediaData.src}" class="w-full h-full object-cover">` : | |
`<video src="${mediaData.src}" class="w-full h-full object-cover"></video>`} | |
</div> | |
<div class="flex-1 truncate"> | |
<p class="text-sm font-medium truncate">${file.name}</p> | |
<p class="text-xs text-gray-400">${(file.size / 1024).toFixed(1)} KB</p> | |
</div> | |
<button onclick="removeImage(${mediaData.id})" class="text-gray-400 hover:text-pink-500 ml-2"> | |
<i class="fas fa-times"></i> | |
</button> | |
`; | |
referenceContainer.appendChild(referenceItem); | |
// Update select options | |
updateSelectOptions(); | |
// Set first image as active | |
if (uploadedImages.length === 1) { | |
setActiveImage(mediaData.id); | |
nsfwBadge.classList.remove('hidden'); | |
// Auto-enhance on first upload | |
setTimeout(() => { | |
autoEnhance(); | |
}, 500); | |
} | |
// Analyze content for suggestions | |
setTimeout(() => { | |
analyzeContent(); | |
}, 1000); | |
}; | |
reader.readAsDataURL(file); | |
} | |
} | |
function setActiveImage(id) { | |
const imageData = uploadedImages.find(img => img.id === id); | |
if (!imageData) return; | |
currentImageIndex = uploadedImages.findIndex(img => img.id === id); | |
if (imageData.type === 'image') { | |
previewImage.src = imageData.src; | |
previewImage.classList.remove('hidden'); | |
previewVideo.classList.add('hidden'); | |
} else { | |
previewVideo.src = imageData.src; | |
previewVideo.classList.remove('hidden'); | |
previewImage.classList.add('hidden'); | |
} | |
previewContainer.classList.remove('hidden'); | |
placeholder.classList.add('hidden'); | |
// Update active thumbnail | |
document.querySelectorAll('.image-thumbnail').forEach((thumb, index) => { | |
if (index === currentImageIndex) { | |
thumb.classList.add('active'); | |
} else { | |
thumb.classList.remove('active'); | |
} | |
}); | |
// Save to history | |
saveToHistory(); | |
// Analyze content for suggestions | |
analyzeContent(); | |
} | |
function removeImage(id) { | |
const index = uploadedImages.findIndex(img => img.id === id); | |
if (index === -1) return; | |
uploadedImages.splice(index, 1); | |
// Remove from thumbnail container | |
thumbnailContainer.children[index].remove(); | |
// Remove from reference container | |
referenceContainer.children[index].remove(); | |
// Update select options | |
updateSelectOptions(); | |
// If we removed the active image | |
if (currentImageIndex === index) { | |
if (uploadedImages.length > 0) { | |
// Set next available image as active | |
const newIndex = Math.min(index, uploadedImages.length - 1); | |
setActiveImage(uploadedImages[newIndex].id); | |
} else { | |
// No images left | |
previewImage.src = ''; | |
previewVideo.src = ''; | |
previewContainer.classList.add('hidden'); | |
placeholder.classList.remove('hidden'); | |
nsfwBadge.classList.add('hidden'); | |
} | |
} else if (currentImageIndex > index) { | |
currentImageIndex--; | |
} | |
saveToHistory(); | |
} | |
function updateSelectOptions() { | |
const modalSourceFace = document.getElementById('modal-source-face'); | |
const modalTargetFace = document.getElementById('modal-target-face'); | |
// Clear existing options except first | |
[modalSourceFace, modalTargetFace].forEach(select => { | |
while (select.options.length > 1) { | |
select.remove(1); | |
} | |
}); | |
// Add new options | |
uploadedImages.forEach((img, index) => { | |
const option = document.createElement('option'); | |
option.value = img.id; | |
option.textContent = `Image ${index + 1}`; | |
option.className = 'text-white'; | |
const option2 = option.cloneNode(true); | |
modalSourceFace.appendChild(option); | |
modalTargetFace.appendChild(option2); | |
}); | |
} | |
// History management | |
function saveToHistory() { | |
if (uploadedImages.length === 0) return; | |
// Truncate history if we're not at the end | |
if (currentHistoryIndex < editHistory.length - 1) { | |
editHistory = editHistory.slice(0, currentHistoryIndex + 1); | |
} | |
// Save current state | |
const historyItem = { | |
imageSrc: uploadedImages[currentImageIndex].src, | |
bodyParams: {...bodyParams} | |
}; | |
editHistory.push(historyItem); | |
currentHistoryIndex = editHistory.length - 1; | |
// Update undo/redo buttons | |
document.getElementById('undo-btn').disabled = currentHistoryIndex <= 0; | |
document.getElementById('redo-btn').disabled = currentHistoryIndex >= editHistory.length - 1; | |
} | |
function undo() { | |
if (currentHistoryIndex <= 0) return; | |
currentHistoryIndex--; | |
applyHistoryState(); | |
} | |
function redo() { | |
if (currentHistoryIndex >= editHistory.length - 1) return; | |
currentHistoryIndex++; | |
applyHistoryState(); | |
} | |
function applyHistoryState() { | |
const historyItem = editHistory[currentHistoryIndex]; | |
// Update image | |
if (uploadedImages[currentImageIndex].type === 'image') { | |
previewImage.src = historyItem.imageSrc; | |
} else { | |
previewVideo.src = historyItem.imageSrc; | |
} | |
uploadedImages[currentImageIndex].src = historyItem.imageSrc; | |
// Update body params | |
bodyParams = {...historyItem.bodyParams}; | |
document.getElementById('breast-slider').value = bodyParams.breast; | |
document.getElementById('ass-slider').value = bodyParams.ass; | |
document.getElementById('waist-slider').value = bodyParams.waist; | |
document.getElementById('pussy-slider').value = bodyParams.pussy; | |
// Update slider values | |
document.getElementById('breast-value').textContent = `${bodyParams.breast}%`; | |
document.getElementById('ass-value').textContent = `${bodyParams.ass}%`; | |
document.getElementById('waist-value').textContent = `${bodyParams.waist}%`; | |
document.getElementById('pussy-value').textContent = `${bodyParams.pussy}%`; | |
// Update buttons | |
document.getElementById('undo-btn').disabled = currentHistoryIndex <= 0; | |
document.getElementById('redo-btn').disabled = currentHistoryIndex >= editHistory.length - 1; | |
} | |
// Reset button functionality | |
function resetEditor() { | |
if (uploadedImages.length === 0) return; | |
if (uploadedImages[currentImageIndex].type === 'image') { | |
previewImage.src = uploadedImages[currentImageIndex].originalSrc; | |
} else { | |
previewVideo.src = uploadedImages[currentImageIndex].originalSrc; | |
} | |
uploadedImages[currentImageIndex].src = uploadedImages[currentImageIndex].originalSrc; | |
// Reset sliders | |
document.getElementById('breast-slider').value = 0; | |
document.getElementById('ass-slider').value = 0; | |
document.getElementById('waist-slider').value = 0; | |
document.getElementById('pussy-slider').value = 0; | |
bodyParams = { breast: 0, ass: 0, waist: 0, pussy: 0 }; | |
// Update slider values | |
document.getElementById('breast-value').textContent = "0%"; | |
document.getElementById('ass-value').textContent = "0%"; | |
document.getElementById('waist-value').textContent = "0%"; | |
document.getElementById('pussy-value').textContent = "0%"; | |
// Clear history | |
editHistory = []; | |
currentHistoryIndex = -1; | |
document.getElementById('undo-btn').disabled = true; | |
document.getElementById('redo-btn').disabled = true; | |
saveToHistory(); | |
} | |
// Process button functionality | |
async function processImage() { | |
if (!previewImage.src && !previewVideo.src) { | |
alert('Please upload NSFW content first'); | |
return; | |
} | |
const promptBox = document.getElementById('ai-prompt'); | |
const prompt = promptBox.value; | |
if (!prompt && Object.values(bodyParams).every(val => val === 0)) { | |
alert('Please enter a prompt or adjust body parameters'); | |
return; | |
} | |
// Show processing overlay | |
const overlay = document.getElementById('processing-overlay'); | |
const progressBar = document.getElementById('progress-bar'); | |
const processingText = document.getElementById('processing-text'); | |
const aiSuggestions = document.getElementById('ai-suggestions'); | |
overlay.classList.remove('hidden'); | |
processingText.textContent = 'Enhancing your content...'; | |
aiSuggestions.classList.add('hidden'); | |
// Simulate processing with progress | |
let progress = 0; | |
const interval = setInterval(() => { | |
progress += Math.random() * 10; | |
if (progress > 100) progress = 100; | |
progressBar.style.width = `${progress}%`; | |
if (progress === 100) { | |
clearInterval(interval); | |
processingText.textContent = 'Finalizing enhancements...'; | |
setTimeout(() => { | |
overlay.classList.add('hidden'); | |
progressBar.style.width = '0%'; | |
// In a real app, this would call your AI processing API | |
// For demo, we'll just modify the image slightly | |
if (uploadedImages[currentImageIndex].type === 'image') { | |
const canvas = document.createElement('canvas'); | |
const ctx = canvas.getContext('2d'); | |
const img = new Image(); | |
img.onload = function() { | |
canvas.width = img.width; | |
canvas.height = img.height; | |
ctx.drawImage(img, 0, 0); | |
// Apply body enhancements based on sliders | |
if (bodyParams.breast !== 0) { | |
// Simulate breast enhancement | |
ctx.fillStyle = 'rgba(255, 200, 200, 0.1)'; | |
ctx.beginPath(); | |
ctx.ellipse(canvas.width * 0.4, canvas.height * 0.4, | |
canvas.width * 0.1 * (1 + bodyParams.breast/100), | |
canvas.height * 0.15 * (1 + bodyParams.breast/100), | |
0, 0, Math.PI * 2); | |
ctx.fill(); | |
ctx.beginPath(); | |
ctx.ellipse(canvas.width * 0.6, canvas.height * 0.4, | |
canvas.width * 0.1 * (1 + bodyParams.breast/100), | |
canvas.height * 0.15 * (1 + bodyParams.breast/100), | |
0, 0, Math.PI * 2); | |
ctx.fill(); | |
} | |
if (bodyParams.ass !== 0) { | |
// Simulate ass enhancement | |
ctx.fillStyle = 'rgba(200, 200, 255, 0.1)'; | |
ctx.beginPath(); | |
ctx.ellipse(canvas.width * 0.5, canvas.height * 0.6, | |
canvas.width * 0.15 * (1 + bodyParams.ass/100), | |
canvas.height * 0.1 * (1 + bodyParams.ass/100), | |
0, 0, Math.PI * 2); | |
ctx.fill(); | |
} | |
if (bodyParams.waist !== 0) { | |
// Simulate waist enhancement | |
ctx.fillStyle = 'rgba(255, 255, 200, 0.1)'; | |
ctx.beginPath(); | |
ctx.ellipse(canvas.width * 0.5, canvas.height * 0.5, | |
canvas.width * 0.1 * (1 - bodyParams.waist/200), | |
canvas.height * 0.15 * (1 - bodyParams.waist/200), | |
0, 0, Math.PI * 2); | |
ctx.fill(); | |
} | |
if (bodyParams.pussy !== 0) { | |
// Simulate pussy enhancement | |
ctx.fillStyle = 'rgba(255, 150, 200, 0.1)'; | |
ctx.beginPath(); | |
ctx.ellipse(canvas.width * 0.5, canvas.height * 0.7, | |
canvas.width * 0.08 * (1 + bodyParams.pussy/100), | |
canvas.height * 0.05 * (1 + bodyParams.pussy/100), | |
0, 0, Math.PI * 2); | |
ctx.fill(); | |
} | |
// Apply effects based on prompt | |
if (prompt.includes('smooth') || prompt.includes('skin')) { | |
// Simulate skin smoothing | |
ctx.filter = 'blur(1px)'; | |
ctx.drawImage(canvas, 0, 0); | |
ctx.filter = 'none'; | |
} | |
if (prompt.includes('toy') || prompt.includes('dildo') || prompt.includes('vibrator')) { | |
// Simulate adding a toy | |
ctx.fillStyle = '#ff69b4'; | |
ctx.beginPath(); | |
ctx.ellipse(canvas.width * 0.5, canvas.height * 0.7, | |
canvas.width * 0.05, canvas.height * 0.15, | |
Math.PI/4, 0, Math.PI * 2); | |
ctx.fill(); | |
} | |
if (prompt.includes('plug') || prompt.includes('anal')) { | |
// Simulate adding a butt plug | |
ctx.fillStyle = '#9370db'; | |
ctx.beginPath(); | |
ctx.ellipse(canvas.width * 0.5, canvas.height * 0.3, | |
canvas.width * 0.03, canvas.height * 0.03, | |
0, 0, Math.PI * 2); | |
ctx.fill(); | |
// Add jewel to plug | |
ctx.fillStyle = '#ffd700'; | |
ctx.beginPath(); | |
ctx.ellipse(canvas.width * 0.5, canvas.height * 0.28, | |
canvas.width * 0.01, canvas.height * 0.01, | |
0, 0, Math.PI * 2); | |
ctx.fill(); | |
} | |
// Update the image | |
const newSrc = canvas.toDataURL('image/jpeg'); | |
previewImage.src = newSrc; | |
uploadedImages[currentImageIndex].src = newSrc; | |
saveToHistory(); | |
// Show AI suggestions | |
setTimeout(() => { | |
overlay.classList.remove('hidden'); | |
processingText.textContent = 'Enhancement complete!'; | |
aiSuggestions.classList.remove('hidden'); | |
progressBar.style.width = '0%'; | |
// Hide after 5 seconds | |
setTimeout(() => { | |
overlay.classList.add('hidden'); | |
}, 5000); | |
}, 500); | |
}; | |
img.src = previewImage.src; | |
} | |
}, 500); | |
} | |
}, 100); | |
} | |
// Auto-enhance function | |
function autoEnhance() { | |
if (!previewImage.src && !previewVideo.src) { | |
alert('Please upload NSFW content first'); | |
return; | |
} | |
// Set some default enhancements | |
document.getElementById('breast-slider').value = 15; | |
document.getElementById('ass-slider').value = 25; | |
document.getElementById('waist-slider').value = 20; | |
document.getElementById('pussy-slider').value = 10; | |
// Update displayed values | |
document.getElementById('breast-value').textContent = "15%"; | |
document.getElementById('ass-value').textContent = "25%"; | |
document.getElementById('waist-value').textContent = "20%"; | |
document.getElementById('pussy-value').textContent = "10%"; | |
// Update body params | |
bodyParams.breast = 15; | |
bodyParams.ass = 25; | |
bodyParams.waist = 20; | |
bodyParams.pussy = 10; | |
// Set a smart prompt | |
document.getElementById('ai-prompt').value = "Enhance curves, smooth skin, perfect lighting, professional look"; | |
// Process the image | |
processImage(); | |
} | |
// Save button functionality | |
function saveImage() { | |
if (!previewImage.src && !previewVideo.src) { | |
alert('Please upload NSFW content first'); | |
return; | |
} | |
// Get selected format | |
let format = 'jpg'; | |
if (document.getElementById('format-png').checked) format = 'png'; | |
if (document.getElementById('format-webp').checked) format = 'webp'; | |
// Get quality | |
const quality = document.getElementById('export-quality').value; | |
// Simulate download | |
const link = document.createElement('a'); | |
if (previewImage.src) { | |
link.href = previewImage.src; | |
link.download = `onlyfans-content.${format}`; | |
} else { | |
link.href = previewVideo.src; | |
link.download = 'onlyfans-video.mp4'; | |
} | |
document.body.appendChild(link); | |
link.click(); | |
document.body.removeChild(link); | |
// Show confirmation | |
alert(`Content saved as ${format.toUpperCase()} at ${quality}% quality!`); | |
} | |
// Body parameter updates | |
function updateBodyParam(param, value) { | |
bodyParams[param] = parseInt(value); | |
document.getElementById(`${param}-value`).textContent = `${value}%`; | |
saveToHistory(); | |
} | |
// AI Prompt functions | |
function applyPrompt(prompt) { | |
document.getElementById('ai-prompt').value = prompt; | |
document.getElementById('char-count').textContent = prompt.length; | |
processImage(); | |
} | |
// Face Swap Functions | |
async function showFaceSwapModal() { | |
if (uploadedImages.length < 2) { | |
alert('You need at least 2 images to perform face swap'); | |
return; | |
} | |
document.getElementById('face-swap-modal').classList.remove('hidden'); | |
// Load face detection models if not already loaded | |
if (!faceDetectionModelsLoaded) { | |
await loadFaceDetectionModels(); | |
} | |
} | |
function hideFaceSwapModal() { | |
document.getElementById('face-swap-modal').classList.add('hidden'); | |
} | |
async function updateFacePreview(type) { | |
const select = type === 'source' ? | |
document.getElementById('modal-source-face') : | |
document.getElementById('modal-target-face'); | |
const preview = document.getElementById(`${type}-face-preview`); | |
const selectedId = select.value; | |
if (!selectedId) { | |
preview.innerHTML = '<span class="text-gray-500">No image selected</span>'; | |
return; | |
} | |
const imageData = uploadedImages.find(img => img.id == selectedId); | |
if (!imageData) return; | |
// Clear previous preview | |
preview.innerHTML = ''; | |
// Add image to preview | |
const img = document.createElement('img'); | |
img.src = imageData.src; | |
img.className = 'w-full h-full object-contain'; | |
preview.appendChild(img); | |
// Detect faces and draw landmarks | |
if (faceDetectionModelsLoaded) { | |
const detections = await faceapi.detectAllFaces(img, new faceapi.TinyFaceDetectorOptions()) | |
.withFaceLandmarks() | |
.withFaceDescriptors(); | |
if (detections.length > 0) { | |
// Draw face detection boxes | |
detections.forEach(detection => { | |
const box = detection.detection.box; | |
const faceBox = document.createElement('div'); | |
faceBox.className = 'face-detection-box'; | |
faceBox.style.width = `${box.width}px`; | |
faceBox.style.height = `${box.height}px`; | |
faceBox.style.left = `${box.x}px`; | |
faceBox.style.top = `${box.y}px`; | |
preview.appendChild(faceBox); | |
}); | |
// Draw face landmarks | |
detections.forEach(detection => { | |
const landmarks = detection.landmarks; | |
landmarks.positions.forEach(point => { | |
const dot = document.createElement('div'); | |
dot.className = 'face-landmarks'; | |
dot.style.left = `${point.x}px`; | |
dot.style.top = `${point.y}px`; | |
preview.appendChild(dot); | |
}); | |
}); | |
} | |
} | |
} | |
async function applyModalFaceSwap() { | |
const sourceId = document.getElementById('modal-source-face').value; | |
const targetId = document.getElementById('modal-target-face').value; | |
if (!sourceId || !targetId) { | |
alert('Please select both source and target faces'); | |
return; | |
} | |
if (sourceId === targetId) { | |
alert('Source and target faces must be different'); | |
return; | |
} | |
const strength = document.getElementById('face-align-strength').value; | |
const skinTone = document.getElementById('skin-tone-match').value; | |
const blendIntensity = document.getElementById('blend-intensity').value; | |
// Show processing | |
const overlay = document.getElementById('processing-overlay'); | |
const progressBar = document.getElementById('progress-bar'); | |
const processingText = document.getElementById('processing-text'); | |
overlay.classList.remove('hidden'); | |
processingText.textContent = 'Swapping faces...'; | |
// Get the source and target images | |
const sourceImg = uploadedImages.find(img => img.id == sourceId); | |
const targetImg = uploadedImages.find(img => img.id == targetId); | |
// Create canvas elements for face swapping | |
const sourceCanvas = document.createElement('canvas'); | |
const sourceCtx = sourceCanvas.getContext('2d'); | |
const targetCanvas = document.createElement('canvas'); | |
const targetCtx = targetCanvas.getContext('2d'); | |
// Load source image | |
const sourceImage = new Image(); | |
sourceImage.onload = async function() { | |
sourceCanvas.width = sourceImage.width; | |
sourceCanvas.height = sourceImage.height; | |
sourceCtx.drawImage(sourceImage, 0, 0); | |
// Load target image | |
const targetImage = new Image(); | |
targetImage.onload = async function() { | |
targetCanvas.width = targetImage.width; | |
targetCanvas.height = targetImage.height; | |
targetCtx.drawImage(targetImage, 0, 0); | |
// Detect faces in both images | |
</html> |