Goondex/test-logo-standalone.html
Stu Leak 2b4a2038fa Add JAV studios reference documentation and various UI improvements
- Add comprehensive JAV studios quick reference guide
- Update documentation index with JAV reference
- Add logo animation components and test files
- Update CSS styling for cards, buttons, forms, and theme
- Add utility scripts for configuration and import workflows
- Update templates and UI components

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-28 16:36:38 -05:00

311 lines
11 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<title>Logo Animation Test</title>
<style>
body { background: #1a1a1a; color: white; padding: 2rem; font-family: Arial, sans-serif; }
.logo { margin: 2rem 0; width: 180px; height: 110px; }
.logo svg { width: 100%; height: 100%; display: block; }
.goondex-logo-animated .breast-left,
.goondex-logo-animated .breast-right {
animation: breastBounce 1.6s ease-in-out infinite;
transform-origin: center center;
}
.goondex-logo-animated .breast-right { animation-delay: 0.08s; }
.goondex-logo-animated .nipple-left,
.goondex-logo-animated .nipple-right {
animation: nippleBob 1.6s ease-in-out infinite;
transform-origin: center center;
}
.goondex-logo-animated .nipple-right { animation-delay: 0.12s; }
@keyframes breastBounce {
0% { transform: translateY(0) scale(1); }
12% { transform: translateY(-4px) scaleX(1.01) scaleY(0.985); }
28% { transform: translateY(8px) scaleX(0.99) scaleY(1.03); }
44% { transform: translateY(-3px) scaleX(1.012) scaleY(0.988); }
60% { transform: translateY(4px) scaleX(0.995) scaleY(1.015); }
100% { transform: translateY(0) scale(1); }
}
@keyframes nippleBob {
0%, 100% { transform: translate(0, 0); }
18% { transform: translate(0px, -5px) scale(1.03); }
35% { transform: translate(0px, 6px) scale(0.98); }
55% { transform: translate(0px, -3px) scale(1.02); }
75% { transform: translate(0px, 2px); }
}
button { background: #ff5fa2; color: white; border: none; padding: 0.5rem 1rem; border-radius: 4px; margin-right: 1rem; cursor: pointer; }
.global-loader {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.55);
backdrop-filter: blur(2px);
display: flex;
align-items: center;
justify-content: center;
z-index: 2000;
}
.global-loader .loader-content {
background: #2a2a2a;
padding: 1.5rem 2rem;
border-radius: 12px;
border: 1px solid #444;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
display: flex;
flex-direction: column;
gap: 1rem;
align-items: center;
color: white;
min-width: 280px;
justify-content: center;
}
.global-loader .logo svg {
width: 90px;
height: 55px;
filter: drop-shadow(0 2px 8px rgba(255, 95, 162, 0.3));
}
</style>
</head>
<body>
<h1>Goondex Logo Animation Test</h1>
<div style="margin: 2rem 0;">
<h2>Static Logo:</h2>
<div id="static-logo" class="logo"></div>
</div>
<div style="margin: 2rem 0;">
<h2>Animated Logo:</h2>
<div id="animated-logo" class="logo"></div>
</div>
<div style="margin: 2rem 0;">
<button onclick="startAnimation()">Start Animation</button>
<button onclick="stopAnimation()">Stop Animation</button>
</div>
<div style="margin: 2rem 0;">
<button onclick="testLoader()">Test Loader (3 seconds)</button>
</div>
<div id="global-loader" class="global-loader" style="display:none;">
<div class="loader-content">
<div id="loader-logo" class="logo"></div>
<div>Working...</div>
</div>
</div>
<script>
class LogoAnimator {
constructor() {
this.isAnimating = false;
this.logoElement = null;
}
init(svgElement) {
this.logoElement = svgElement;
this.identifyParts();
}
identifyParts() {
if (!this.logoElement) return;
const nipples = [];
const breasts = [];
// Prefer elements with ids/classes if present
const breastCandidates = [
this.logoElement.querySelector('#breast-left'),
this.logoElement.querySelector('#breast-right')
].filter(Boolean);
const nippleCandidates = [
this.logoElement.querySelector('#nipple-left'),
this.logoElement.querySelector('#nipple-right')
].filter(Boolean);
breasts.push(...breastCandidates);
nipples.push(...nippleCandidates);
// Fallback nipples: first two circles/ellipses
if (nipples.length < 2) {
const circ = Array.from(this.logoElement.querySelectorAll('circle, ellipse'));
while (nipples.length < 2 && circ.length) {
nipples.push(circ.shift());
}
}
// Fallback breasts: first two paths/shapes
if (breasts.length < 2) {
const shapes = Array.from(this.logoElement.querySelectorAll('path, polygon, rect'));
while (breasts.length < 2 && shapes.length) {
breasts.push(shapes.shift());
}
}
// Ultimate fallback: animate whole svg as a single breast pair
if (breasts.length === 0) breasts.push(this.logoElement);
if (breasts.length === 1) breasts.push(this.logoElement);
if (breasts[0]) breasts[0].classList.add('breast-left');
if (breasts[1]) breasts[1].classList.add('breast-right');
if (nipples.length === 0) {
// If no explicit nipples, piggyback on breasts so some motion happens
nipples.push(breasts[0], breasts[1]);
}
nipples.slice(0, 2).forEach((el, idx) => {
if (el) el.classList.add(idx === 0 ? 'nipple-left' : 'nipple-right');
});
}
startBounce() {
if (!this.logoElement || this.isAnimating) return;
this.logoElement.classList.add('goondex-logo-animated');
this.isAnimating = true;
}
stopBounce() {
if (!this.logoElement) return;
this.logoElement.classList.remove('goondex-logo-animated');
this.isAnimating = false;
}
}
// Inline-load the SVG so we can animate internals
// INLINE ANIMATOR (self-contained for this test page)
class LogoAnimator {
constructor() {
this.isAnimating = false;
this.logoElement = null;
}
init(svgElement) {
this.logoElement = svgElement;
this.identifyParts();
}
identifyParts() {
if (!this.logoElement) return;
const nipples = [];
const breasts = [];
const breastCandidates = [
this.logoElement.querySelector('#breast-left'),
this.logoElement.querySelector('#breast-right')
].filter(Boolean);
const nippleCandidates = [
this.logoElement.querySelector('#nipple-left'),
this.logoElement.querySelector('#nipple-right')
].filter(Boolean);
breasts.push(...breastCandidates);
nipples.push(...nippleCandidates);
if (nipples.length < 2) {
const circ = Array.from(this.logoElement.querySelectorAll('circle, ellipse'));
while (nipples.length < 2 && circ.length) nipples.push(circ.shift());
}
if (breasts.length < 2) {
const shapes = Array.from(this.logoElement.querySelectorAll('path, polygon, rect'));
while (breasts.length < 2 && shapes.length) breasts.push(shapes.shift());
}
if (breasts.length === 0) breasts.push(this.logoElement);
if (breasts.length === 1) breasts.push(this.logoElement);
if (breasts[0]) breasts[0].classList.add('breast-left');
if (breasts[1]) breasts[1].classList.add('breast-right');
if (nipples.length === 0) nipples.push(breasts[0], breasts[1]);
nipples.slice(0, 2).forEach((el, idx) => el && el.classList.add(idx === 0 ? 'nipple-left' : 'nipple-right'));
}
startBounce() {
if (!this.logoElement || this.isAnimating) return;
this.logoElement.classList.add('goondex-logo-animated');
this.isAnimating = true;
}
stopBounce() {
if (!this.logoElement) return;
this.logoElement.classList.remove('goondex-logo-animated');
this.isAnimating = false;
}
}
async function loadSVG(urls, targetId) {
const target = document.getElementById(targetId);
if (!target) return null;
for (const url of urls) {
try {
const res = await fetch(url);
if (!res.ok) throw new Error('fetch failed');
const svgText = await res.text();
target.innerHTML = svgText;
const svg = target.querySelector('svg');
return svg;
} catch (e) {
continue;
}
}
// Fallback to img if all fetches fail (no animation possible)
target.innerHTML = `<img src=\"${urls[0]}\" alt=\"Goondex Logo\" width=\"100%\" height=\"100%\">`;
return null;
}
const logoURLs = [
"/static/img/logo/GOONDEX_Titty.svg",
"static/img/logo/GOONDEX_Titty.svg",
"./static/img/logo/GOONDEX_Titty.svg"
];
let animator = null;
let loaderAnimator = null;
async function initLogos() {
const staticSvg = await loadSVG(logoURLs, 'static-logo');
const animatedSvg = await loadSVG(logoURLs, 'animated-logo');
const loaderSvg = await loadSVG(logoURLs, 'loader-logo');
if (animatedSvg) {
animator = new LogoAnimator();
animator.init(animatedSvg);
animator.startBounce();
}
if (loaderSvg) {
loaderAnimator = new LogoAnimator();
loaderAnimator.init(loaderSvg);
}
}
function startAnimation() {
if (animator) animator.startBounce();
}
function stopAnimation() {
if (animator) animator.stopBounce();
}
function testLoader() {
const loader = document.getElementById('global-loader');
loader.style.display = 'flex';
if (loaderAnimator) {
loaderAnimator.startBounce();
}
setTimeout(() => {
loader.style.display = 'none';
if (loaderAnimator) {
loaderAnimator.stopBounce();
}
}, 3000);
}
initLogos();
</script>
</body>
</html>