MediaWiki:Common.js: Difference between revisions
From HADES
Jump to navigationJump to search
Possession (talk | contribs) Created page with "/** * ╔═══════════════════════════════════════════════════════════════╗ * ║ HADES WIKI — MediaWiki Theme JavaScript ║ * ║ The Free Encyclopedia of the Underworld ║ * ║ Based on: Hades (2026) by Melanie Martinez ║ * ║ Install in: MediaWiki:Common.js..." |
Possession (talk | contribs) No edit summary |
||
| Line 1: | Line 1: | ||
/* | /* ================================================================ | ||
H A D E S — MediaWiki:Common.js | |||
Ambient visual layer: candles, gothic arches, rose petals, | |||
sacred hearts, damask motifs, wax drips, dust motes | |||
================================================================ */ | |||
(function () { | ( function () { | ||
'use strict'; | 'use strict'; | ||
/* | /* ── FONT PRELOAD ─────────────────────────────────────────── */ | ||
function preloadFonts() { | |||
if ( document.getElementById( 'hades-fonts' ) ) { return; } | |||
var link = document.createElement( 'link' ); | |||
link.id = 'hades-fonts'; | |||
link.rel = 'stylesheet'; | |||
link.href = 'https://fonts.googleapis.com/css2?family=Cinzel+Decorative:wght@400;700;900&family=Cinzel:wght@400;600;700&family=IM+Fell+English:ital@0;1&family=Cormorant+Garamond:ital,wght@0,300;0,400;0,600;1,400&family=UnifrakturMaguntia&family=Playfair+Display+SC:wght@400;700&family=Petit+Formal+Script&display=swap'; | |||
document.head.appendChild( link ); | |||
} | } | ||
/* | /* ── SVG LIBRARY ──────────────────────────────────────────── */ | ||
var SVG = { | |||
// | /* Tall pillar candle with dripping wax */ | ||
candleTall: [ | |||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 200" width="44" height="146">', | |||
/* flame */ | |||
'<g style="animation:h-flame-dance 0.8s ease-in-out infinite;transform-origin:30px 22px">', | |||
'<ellipse cx="30" cy="28" rx="7" ry="14" fill="#ff7010" opacity="0.9"/>', | |||
'<ellipse cx="30" cy="30" rx="4" ry="10" fill="#f8c840" opacity="0.95"/>', | |||
'<ellipse cx="30" cy="32" rx="2" ry="5" fill="#ffffff" opacity="0.7"/>', | |||
/* glow halo */ | |||
'<ellipse cx="30" cy="28" rx="14" ry="18" fill="#f8c840" opacity="0.08"/>', | |||
'</g>', | |||
/* wick */ | |||
'<line x1="30" y1="40" x2="30" y2="50" stroke="#3a2010" stroke-width="1.5"/>', | |||
/* wax body */ | |||
'<rect x="18" y="48" width="24" height="130" rx="3" fill="#f2ede0"/>', | |||
'<rect x="20" y="50" width="4" height="128" rx="1" fill="#ffffff" opacity="0.15"/>', | |||
/* drips */ | |||
'<path d="M22,50 Q20,60 21,75 Q22,82 22,90" stroke="#e8e0cc" stroke-width="3" fill="none" stroke-linecap="round"/>', | |||
'<path d="M36,50 Q38,65 37,78" stroke="#e8e0cc" stroke-width="2.5" fill="none" stroke-linecap="round"/>', | |||
'<path d="M28,48 Q27,58 28,68" stroke="#f0e8d0" stroke-width="2" fill="none" stroke-linecap="round"/>', | |||
'<ellipse cx="21" cy="90" rx="2.5" ry="3.5" fill="#d8d0c0"/>', | |||
'<ellipse cx="37" cy="78" rx="2" ry="3" fill="#d8d0c0"/>', | |||
/* base puddle */ | |||
'<ellipse cx="30" cy="180" rx="18" ry="6" fill="#d8d0c0" opacity="0.6"/>', | |||
'<rect x="16" y="174" width="28" height="8" rx="3" fill="#c8c0b0"/>', | |||
'</svg>' | |||
].join( '' ), | |||
/* Short stubby candle, more wax pooled */ | |||
candleShort: [ | |||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 120" width="36" height="86">', | |||
'<g style="animation:h-flame-dance 1.1s ease-in-out infinite;transform-origin:25px 18px">', | |||
'<ellipse cx="25" cy="22" rx="5" ry="10" fill="#ff7010" opacity="0.85"/>', | |||
'<ellipse cx="25" cy="24" rx="3" ry="7" fill="#f8c840" opacity="0.95"/>', | |||
'<ellipse cx="25" cy="25" rx="1.5" ry="4" fill="#ffffff" opacity="0.6"/>', | |||
'<ellipse cx="25" cy="22" rx="10" ry="14" fill="#f8c840" opacity="0.07"/>', | |||
'</g>', | |||
'<line x1="25" y1="32" x2="25" y2="40" stroke="#3a2010" stroke-width="1.5"/>', | |||
'<rect x="14" y="38" width="22" height="65" rx="4" fill="#f0ece0"/>', | |||
'<rect x="16" y="40" width="3" height="62" rx="1" fill="#ffffff" opacity="0.12"/>', | |||
'<path d="M18,40 Q16,55 17,70 Q17,78 16,85" stroke="#e0d8c4" stroke-width="3" fill="none" stroke-linecap="round"/>', | |||
'<ellipse cx="16" cy="85" rx="2.5" ry="3" fill="#ccc4b0"/>', | |||
/* large wax pool */ | |||
'<ellipse cx="25" cy="106" rx="22" ry="7" fill="#ddd8c8" opacity="0.7"/>', | |||
'<rect x="10" y="100" width="30" height="10" rx="4" fill="#c8c0b0"/>', | |||
'</svg>' | |||
].join( '' ), | |||
/* Cluster of 3 candles on a holder */ | |||
candleCluster: [ | |||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 200" width="100" height="167">', | |||
/* left candle */ | |||
'<g transform="translate(10,20)">', | |||
'<g style="animation:h-flame-dance 0.9s 0.2s ease-in-out infinite;transform-origin:20px 16px">', | |||
'<ellipse cx="20" cy="18" rx="5" ry="11" fill="#ff8020" opacity="0.9"/>', | |||
'<ellipse cx="20" cy="20" rx="3" ry="7" fill="#f8c840"/>', | |||
'<ellipse cx="20" cy="22" rx="1.5" ry="4" fill="#fff" opacity="0.6"/>', | |||
'<ellipse cx="20" cy="18" rx="10" ry="14" fill="#f8c840" opacity="0.07"/>', | |||
'</g>', | |||
'<line x1="20" y1="28" x2="20" y2="35" stroke="#3a2010" stroke-width="1"/>', | |||
'<rect x="12" y="33" width="16" height="100" rx="3" fill="#f2ede0"/>', | |||
'<path d="M14,35 Q12,50 13,70" stroke="#e0d8c4" stroke-width="2.5" fill="none" stroke-linecap="round"/>', | |||
'</g>', | |||
/* centre candle (taller) */ | |||
'<g transform="translate(40,0)">', | |||
'<g style="animation:h-flame-dance 0.7s ease-in-out infinite;transform-origin:20px 18px">', | |||
'<ellipse cx="20" cy="20" rx="6" ry="14" fill="#ff6010" opacity="0.95"/>', | |||
'<ellipse cx="20" cy="23" rx="4" ry="9" fill="#f8c840"/>', | |||
'<ellipse cx="20" cy="25" rx="2" ry="5" fill="#fff" opacity="0.7"/>', | |||
'<ellipse cx="20" cy="20" rx="14" ry="18" fill="#f8c840" opacity="0.08"/>', | |||
'</g>', | |||
'<line x1="20" y1="32" x2="20" y2="40" stroke="#3a2010" stroke-width="1.5"/>', | |||
'<rect x="11" y="38" width="18" height="130" rx="3" fill="#f0ece0"/>', | |||
'<path d="M13,40 Q11,60 12,85" stroke="#e0d8c4" stroke-width="3" fill="none" stroke-linecap="round"/>', | |||
'<ellipse cx="12" cy="85" rx="2.5" ry="3.5" fill="#ccc4b0"/>', | |||
'</g>', | |||
/* right candle */ | |||
'<g transform="translate(76,28)">', | |||
'<g style="animation:h-flame-dance 1.0s 0.5s ease-in-out infinite;transform-origin:18px 15px">', | |||
'<ellipse cx="18" cy="16" rx="4" ry="9" fill="#ff7018" opacity="0.85"/>', | |||
'<ellipse cx="18" cy="18" rx="3" ry="6" fill="#f8c840"/>', | |||
'<ellipse cx="18" cy="20" rx="1.5" ry="3.5" fill="#fff" opacity="0.55"/>', | |||
'<ellipse cx="18" cy="16" rx="9" ry="13" fill="#f8c840" opacity="0.06"/>', | |||
'</g>', | |||
'<line x1="18" y1="25" x2="18" y2="32" stroke="#3a2010" stroke-width="1"/>', | |||
'<rect x="10" y="30" width="15" height="90" rx="3" fill="#f2ede0"/>', | |||
'<path d="M22,32 Q24,48 23,62" stroke="#e0d8c4" stroke-width="2.5" fill="none" stroke-linecap="round"/>', | |||
'</g>', | |||
/* shared base plate */ | |||
'<rect x="4" y="170" width="112" height="14" rx="4" fill="#8a6030"/>', | |||
'<rect x="2" y="183" width="116" height="8" rx="3" fill="#6a4820"/>', | |||
'<ellipse cx="60" cy="191" rx="58" ry="6" fill="#4a3010" opacity="0.5"/>', | |||
'</svg>' | |||
].join( '' ), | |||
/* Gothic pointed arch frame */ | |||
gothicArch: [ | |||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 150" width="90" height="135">', | |||
'<path d="M10,150 L10,70 Q10,5 50,5 Q90,5 90,70 L90,150" fill="none" stroke="#c8860a" stroke-width="1.5" opacity="0.7"/>', | |||
/* inner arch */ | |||
'<path d="M18,150 L18,74 Q18,20 50,20 Q82,20 82,74 L82,150" fill="none" stroke="#e8b030" stroke-width="0.8" opacity="0.4"/>', | |||
/* keystone ornament */ | |||
'<ellipse cx="50" cy="8" rx="6" ry="7" fill="none" stroke="#c8860a" stroke-width="1.2" opacity="0.7"/>', | |||
'<circle cx="50" cy="8" r="2.5" fill="#c8860a" opacity="0.6"/>', | |||
/* column capitals */ | |||
'<rect x="4" y="140" width="14" height="10" rx="1" fill="#8a5a18" opacity="0.5"/>', | |||
'<rect x="82" y="140" width="14" height="10" rx="1" fill="#8a5a18" opacity="0.5"/>', | |||
/* tracery at top */ | |||
'<path d="M35,35 Q50,18 65,35" fill="none" stroke="#c8860a" stroke-width="0.8" opacity="0.35"/>', | |||
'<circle cx="50" cy="30" r="4" fill="none" stroke="#e8b030" stroke-width="0.8" opacity="0.4"/>', | |||
'</svg>' | |||
].join( '' ), | |||
/* Sacred heart */ | |||
sacredHeart: [ | |||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 90" width="70" height="79">', | |||
/* heart body */ | |||
'<path d="M40,70 C20,55 5,45 5,28 C5,16 14,8 25,8 C31,8 37,11 40,16 C43,11 49,8 55,8 C66,8 75,16 75,28 C75,45 60,55 40,70Z" fill="#a84858" opacity="0.8"/>', | |||
/* light overlay */ | |||
'<path d="M25,14 Q30,10 35,16" stroke="#f0b0c0" stroke-width="2" fill="none" opacity="0.5"/>', | |||
/* flames on top */ | |||
'<g transform="translate(33,-2)">', | |||
'<path d="M7,10 Q5,4 7,0 Q9,4 7,10Z" fill="#f8c840" opacity="0.9"/>', | |||
'<path d="M14,12 Q12,5 14,1 Q16,5 14,12Z" fill="#ff7010" opacity="0.85"/>', | |||
'<path d="M21,10 Q19,4 21,0 Q23,4 21,10Z" fill="#f8c840" opacity="0.9"/>', | |||
'</g>', | |||
/* crown */ | |||
'<g transform="translate(22,-5)">', | |||
'<path d="M0,12 L0,0 L9,5 L18,0 L27,5 L36,0 L36,12Z" fill="none" stroke="#e8b030" stroke-width="1" opacity="0.7"/>', | |||
'<circle cx="9" cy="5" r="2" fill="#e8b030" opacity="0.7"/>', | |||
'<circle cx="18" cy="0" r="2.5" fill="#f8d060" opacity="0.8"/>', | |||
'<circle cx="27" cy="5" r="2" fill="#e8b030" opacity="0.7"/>', | |||
'</g>', | |||
/* thorns / ring */ | |||
'<circle cx="40" cy="35" r="18" fill="none" stroke="#3a1e0c" stroke-width="1.5" stroke-dasharray="3,4" opacity="0.6"/>', | |||
'</svg>' | |||
].join( '' ), | |||
/* Baroque damask ornament */ | |||
damask: [ | |||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="90" height="90">', | |||
'<g fill="none" stroke="#c8860a" stroke-width="0.6" opacity="0.8">', | |||
'<ellipse cx="50" cy="50" rx="8" ry="8"/>', | |||
'<ellipse cx="50" cy="22" rx="5" ry="16"/>', | |||
'<ellipse cx="50" cy="78" rx="5" ry="16"/>', | |||
'<ellipse cx="22" cy="50" rx="16" ry="5"/>', | |||
'<ellipse cx="78" cy="50" rx="16" ry="5"/>', | |||
'<path d="M50,34 Q60,42 50,50 Q40,42 50,34Z"/>', | |||
'<path d="M50,66 Q60,58 50,50 Q40,58 50,66Z"/>', | |||
'<path d="M34,50 Q42,60 50,50 Q42,40 34,50Z"/>', | |||
'<path d="M66,50 Q58,60 50,50 Q58,40 66,50Z"/>', | |||
'<circle cx="50" cy="10" r="3"/>', | |||
'<circle cx="50" cy="90" r="3"/>', | |||
'<circle cx="10" cy="50" r="3"/>', | |||
'<circle cx="90" cy="50" r="3"/>', | |||
'<path d="M38,38 Q50,30 62,38 Q70,50 62,62 Q50,70 38,62 Q30,50 38,38Z"/>', | |||
'</g>', | |||
'</svg>' | |||
].join( '' ), | |||
// | /* Rose petal */ | ||
petal: [ | |||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 36" width="18" height="27">', | |||
'<path d="M12,2 Q20,8 20,20 Q20,32 12,34 Q4,32 4,20 Q4,8 12,2Z" fill="#c06070" opacity="0.7"/>', | |||
'<path d="M12,6 Q16,12 15,22" stroke="#e090a0" stroke-width="0.8" fill="none" opacity="0.5"/>', | |||
'</svg>' | |||
].join( '' ), | |||
// | /* Ornate candelabra */ | ||
candelabra: [ | |||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 260" width="130" height="211">', | |||
/* left arm candle */ | |||
'<g transform="translate(4,30)">', | |||
'<g style="animation:h-flame-dance 0.85s 0.1s ease-in-out infinite;transform-origin:18px 16px">', | |||
'<ellipse cx="18" cy="18" rx="5" ry="12" fill="#ff7010" opacity="0.9"/>', | |||
'<ellipse cx="18" cy="20" rx="3" ry="8" fill="#f8c840"/>', | |||
'<ellipse cx="18" cy="22" rx="2" ry="4" fill="#fff" opacity="0.6"/>', | |||
'<ellipse cx="18" cy="18" rx="12" ry="16" fill="#f8c840" opacity="0.06"/>', | |||
'</g>', | |||
'<line x1="18" y1="30" x2="18" y2="36" stroke="#3a2010" stroke-width="1.2"/>', | |||
'<rect x="11" y="34" width="14" height="80" rx="3" fill="#f0ece0"/>', | |||
'<path d="M12,36 Q10,55 11,72" stroke="#e0d8c4" stroke-width="2.5" fill="none" stroke-linecap="round"/>', | |||
'</g>', | |||
/* right arm candle */ | |||
'<g transform="translate(134,30)">', | |||
'<g style="animation:h-flame-dance 1.05s 0.3s ease-in-out infinite;transform-origin:18px 16px">', | |||
'<ellipse cx="18" cy="18" rx="5" ry="12" fill="#ff7010" opacity="0.9"/>', | |||
'<ellipse cx="18" cy="20" rx="3" ry="8" fill="#f8c840"/>', | |||
'<ellipse cx="18" cy="22" rx="2" ry="4" fill="#fff" opacity="0.6"/>', | |||
'<ellipse cx="18" cy="18" rx="12" ry="16" fill="#f8c840" opacity="0.06"/>', | |||
'</g>', | |||
'<line x1="18" y1="30" x2="18" y2="36" stroke="#3a2010" stroke-width="1.2"/>', | |||
'<rect x="11" y="34" width="14" height="80" rx="3" fill="#f0ece0"/>', | |||
'<path d="M24,36 Q26,55 25,72" stroke="#e0d8c4" stroke-width="2.5" fill="none" stroke-linecap="round"/>', | |||
'</g>', | |||
/* centre tall candle */ | |||
'<g transform="translate(62,0)">', | |||
'<g style="animation:h-flame-dance 0.7s ease-in-out infinite;transform-origin:18px 20px">', | |||
'<ellipse cx="18" cy="20" rx="7" ry="16" fill="#ff6010" opacity="0.95"/>', | |||
'<ellipse cx="18" cy="23" rx="4" ry="10" fill="#f8c840"/>', | |||
'<ellipse cx="18" cy="26" rx="2" ry="6" fill="#fff" opacity="0.7"/>', | |||
'<ellipse cx="18" cy="20" rx="16" ry="22" fill="#f8c840" opacity="0.08"/>', | |||
'</g>', | |||
'<line x1="18" y1="36" x2="18" y2="44" stroke="#3a2010" stroke-width="1.5"/>', | |||
'<rect x="10" y="42" width="16" height="120" rx="3" fill="#f2ede0"/>', | |||
'<path d="M11,44 Q9,68 10,95" stroke="#e0d8c4" stroke-width="3" fill="none" stroke-linecap="round"/>', | |||
'<ellipse cx="10" cy="95" rx="2.5" ry="3.5" fill="#ccc4b0"/>', | |||
'</g>', | |||
/* arms */ | |||
'<path d="M80,90 Q30,80 22,60" fill="none" stroke="#8a6030" stroke-width="3" stroke-linecap="round"/>', | |||
'<path d="M80,90 Q130,80 152,60" fill="none" stroke="#8a6030" stroke-width="3" stroke-linecap="round"/>', | |||
/* stem */ | |||
'<rect x="74" y="160" width="12" height="70" rx="4" fill="#7a5020"/>', | |||
'<ellipse cx="80" cy="162" rx="12" ry="6" fill="#8a6030"/>', | |||
/* base */ | |||
'<ellipse cx="80" cy="236" rx="45" ry="12" fill="#6a4020" opacity="0.7"/>', | |||
'<rect x="50" y="228" width="60" height="10" rx="4" fill="#8a5820"/>', | |||
'</svg>' | |||
].join( '' ), | |||
// | /* Mirror silhouette (album cover gothic arch mirror) */ | ||
mirrorSilhouette: [ | |||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 160" width="80" height="128">', | |||
/* outer frame */ | |||
'<path d="M8,160 L8,80 Q8,5 50,5 Q92,5 92,80 L92,160" fill="none" stroke="#8a5a18" stroke-width="3" opacity="0.6"/>', | |||
/* inner mirror */ | |||
'<path d="M16,158 L16,82 Q16,18 50,18 Q84,18 84,82 L84,158" fill="rgba(10,5,2,0.5)" stroke="#c8860a" stroke-width="1" opacity="0.5"/>', | |||
/* glow inside mirror */ | |||
'<path d="M16,158 L16,82 Q16,18 50,18 Q84,18 84,82 L84,158 Z" fill="url(#mirrorGlow)" opacity="0.3"/>', | |||
'<defs><radialGradient id="mirrorGlow" cx="50%" cy="60%"><stop offset="0%" stop-color="#f8c840" stop-opacity="0.15"/><stop offset="100%" stop-color="#f8c840" stop-opacity="0"/></radialGradient></defs>', | |||
/* spire ornaments */ | |||
'<path d="M8,80 L8,50 L14,30 L20,50 L20,80" fill="none" stroke="#8a5a18" stroke-width="1.5" opacity="0.5"/>', | |||
'<path d="M80,80 L80,50 L86,30 L92,50 L92,80" fill="none" stroke="#8a5a18" stroke-width="1.5" opacity="0.5"/>', | |||
/* keystone */ | |||
'<ellipse cx="50" cy="8" rx="7" ry="8" fill="none" stroke="#c8860a" stroke-width="1.5" opacity="0.6"/>', | |||
'<circle cx="50" cy="8" r="3" fill="#c8860a" opacity="0.5"/>', | |||
/* base shelf */ | |||
'<rect x="2" y="152" width="96" height="10" rx="2" fill="#6a4820" opacity="0.5"/>', | |||
/* sacred heart base motif */ | |||
'<path d="M50,148 C44,143 38,140 38,134 C38,130 41,127 45,127 C47,127 49,128 50,130 C51,128 53,127 55,127 C59,127 62,130 62,134 C62,140 56,143 50,148Z" fill="#a84858" opacity="0.4"/>', | |||
'</svg>' | |||
].join( '' ), | |||
// | /* Wax drip trail */ | ||
waxDrip: [ | |||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 120" width="24" height="96">', | |||
'<path d="M15,0 Q18,20 17,35 Q16,55 18,70 Q20,85 15,100 Q10,85 12,70 Q14,55 13,35 Q12,20 15,0Z" fill="#f2ede0" opacity="0.7"/>', | |||
'<ellipse cx="15" cy="100" rx="8" ry="6" fill="#e8e0cc" opacity="0.6"/>', | |||
'</svg>' | |||
].join( '' ), | |||
// | /* Ornate key */ | ||
key: [ | |||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 120" width="30" height="90">', | |||
'<circle cx="20" cy="20" r="14" fill="none" stroke="#c8860a" stroke-width="2" opacity="0.8"/>', | |||
'<circle cx="20" cy="20" r="7" fill="none" stroke="#e8b030" stroke-width="1" opacity="0.6"/>', | |||
'<circle cx="20" cy="20" r="3" fill="#c8860a" opacity="0.7"/>', | |||
'<rect x="18" y="34" width="4" height="80" rx="1" fill="#c8860a" opacity="0.7"/>', | |||
'<rect x="22" y="80" width="12" height="4" rx="1" fill="#c8860a" opacity="0.7"/>', | |||
'<rect x="22" y="94" width="9" height="4" rx="1" fill="#c8860a" opacity="0.7"/>', | |||
'</svg>' | |||
].join( '' ), | |||
// | /* Crown */ | ||
crown: [ | |||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 80" width="100" height="67">', | |||
'<path d="M5,75 L5,35 L25,10 L40,35 L60,5 L80,35 L95,10 L115,35 L115,75 Z" fill="none" stroke="#c8860a" stroke-width="2" stroke-linejoin="round" opacity="0.7"/>', | |||
'<path d="M5,60 L115,60" stroke="#e8b030" stroke-width="1" opacity="0.5"/>', | |||
'<circle cx="25" cy="13" r="4" fill="#e8b030" opacity="0.7"/>', | |||
'<circle cx="60" cy="7" r="5" fill="#f8d060" opacity="0.8"/>', | |||
'<circle cx="95" cy="13" r="4" fill="#e8b030" opacity="0.7"/>', | |||
'<circle cx="40" cy="36" r="3" fill="#d08090" opacity="0.6"/>', | |||
'<circle cx="80" cy="36" r="3" fill="#d08090" opacity="0.6"/>', | |||
'<rect x="5" y="68" width="110" height="8" rx="2" fill="#8a5a18" opacity="0.4"/>', | |||
'</svg>' | |||
].join( '' ), | |||
// | /* Floating rose */ | ||
rose: [ | |||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60" width="48" height="48">', | |||
'<circle cx="30" cy="30" r="10" fill="#a84858" opacity="0.8"/>', | |||
'<path d="M30,20 Q38,24 36,32 Q30,38 22,32 Q20,24 30,20Z" fill="#c06070" opacity="0.7"/>', | |||
'<path d="M30,20 Q22,24 24,32 Q30,38 38,32 Q40,24 30,20Z" fill="#b05060" opacity="0.7"/>', | |||
'<path d="M30,14 Q40,18 40,28 Q40,38 30,42 Q20,38 20,28 Q20,18 30,14Z" fill="none" stroke="#d08090" stroke-width="0.8" opacity="0.5"/>', | |||
'<path d="M30,8 Q44,14 44,30 Q44,46 30,50 Q16,46 16,30 Q16,14 30,8Z" fill="none" stroke="#c06070" stroke-width="0.6" opacity="0.4"/>', | |||
'<path d="M30,50 L30,60" stroke="#3a1e0c" stroke-width="1.5"/>', | |||
'<path d="M24,56 Q30,52 36,56" stroke="#2a1808" stroke-width="1" fill="none"/>', | |||
'</svg>' | |||
].join( '' ) | |||
}; | |||
/* ── HELPERS ──────────────────────────────────────────────── */ | |||
function rand( a, b ) { return Math.random() * ( b - a ) + a; } | |||
function randInt( a, b ) { return Math.floor( rand( a, b + 1 ) ); } | |||
/* ── BUILD LAYER ──────────────────────────────────────────── */ | |||
return | function createLayer() { | ||
var div = document.createElement( 'div' ); | |||
div.className = 'h-ambient'; | |||
div.id = 'hades-ambient'; | |||
document.body.insertBefore( div, document.body.firstChild ); | |||
return div; | |||
} | } | ||
/* | /* ── SPAWN AMBIENT ELEMENT ───────────────────────────────── */ | ||
function spawn( layer, svgKey, cssClass, opts ) { | |||
opts = opts || {}; | |||
function | var el = document.createElement( 'div' ); | ||
el.className = cssClass; | |||
el.innerHTML = SVG[ svgKey ]; | |||
var scale = rand( opts.minScale || 0.5, opts.maxScale || 1.4 ); | |||
el.style.transformOrigin = 'center center'; | |||
el.style.transform = 'scale(' + scale + ')'; | |||
/* Position */ | |||
var edged = ( opts.edged !== false ) && Math.random() < 0.35; | |||
var top, left; | |||
if ( edged ) { | |||
} | var side = randInt( 0, 3 ); | ||
if ( side === 0 ) { top = rand( 0, 8 ); left = rand( 5, 90 ); } | |||
else if ( side === 1 ) { top = rand( 85, 97 ); left = rand( 5, 90 ); } | |||
else if ( side === 2 ) { top = rand( 5, 90 ); left = rand( 0, 6 ); } | |||
else { top = rand( 5, 90 ); left = rand( 88, 97 );} | |||
} else { | |||
top = rand( opts.topMin || 5, opts.topMax || 90 ); | |||
left = rand( opts.leftMin || 5, opts.leftMax || 90 ); | |||
} | |||
el.style.top = top + 'vh'; | |||
el.style.left = left + 'vw'; | |||
/* Animation stagger */ | |||
var delay = rand( 0, 18 ); | |||
var dur = rand( opts.durMin || 5, opts.durMax || 14 ); | |||
el.style.animationDelay = delay + 's'; | |||
el.style.animationDuration = dur + 's'; | |||
if ( opts.opacity ) { el.style.opacity = opts.opacity; } | |||
layer.appendChild( el ); | |||
return el; | |||
} | |||
/* ── ROSE PETAL FALL ─────────────────────────────────────── */ | |||
function spawnPetal( layer ) { | |||
var el = document.createElement( 'div' ); | |||
el.className = 'h-petal'; | |||
el.innerHTML = SVG.petal; | |||
el.style.left = rand( 5, 95 ) + 'vw'; | |||
el.style.top = '-30px'; | |||
el.style.setProperty( '--drift', rand( -40, 60 ) + 'px' ); | |||
el.style.setProperty( '--rot', rand( -180, 360 ) + 'deg' ); | |||
var dur = rand( 8, 18 ); | |||
el.style.animationDuration = dur + 's'; | |||
el.style.animationDelay = rand( 0, 20 ) + 's'; | |||
el.style.opacity = rand( 0.25, 0.55 ); | |||
layer.appendChild( el ); | |||
} | } | ||
/* | /* ── DUST MOTES ──────────────────────────────────────────── */ | ||
function spawnMote( layer ) { | |||
var el = document.createElement( 'div' ); | |||
function | el.className = 'h-mote'; | ||
el.style.left = rand( 10, 90 ) + 'vw'; | |||
el.style.top = rand( 20, 90 ) + 'vh'; | |||
el.style.setProperty( '--mx', rand( -30, 30 ) + 'px' ); | |||
el.style.setProperty( '--my', rand( -80, -120 ) + 'px' ); | |||
var dur = rand( 5, 12 ); | |||
el.style.animationDuration = dur + 's'; | |||
el.style.animationDelay = rand( 0, 15 ) + 's'; | |||
/* Vary colour: gold, rose, cream */ | |||
var colours = [ '#f8d060', '#e8b030', '#d08090', '#f0e8d0' ]; | |||
el.style.background = colours[ randInt( 0, colours.length - 1 ) ]; | |||
el.style.boxShadow = '0 0 ' + rand( 2, 6 ) + 'px currentColor'; | |||
layer.appendChild( el ); | |||
} | |||
/* ── WAX DRIP TRAILS ON CONTENT EDGE ────────────────────── */ | |||
function injectWaxDrips() { | |||
var content = document.getElementById( 'content' ) | |||
|| document.getElementById( 'mw-content-text' ) | |||
|| document.querySelector( '.mw-body' ); | |||
if ( !content ) { return; } | |||
/* Top drip row — candle wax flowing down */ | |||
var topBar = document.createElement( 'div' ); | |||
topBar.style.cssText = [ | |||
'position:absolute', | |||
'top:-1px', | |||
'left:0', | |||
'width:100%', | |||
'height:40px', | |||
'pointer-events:none', | |||
'overflow:hidden', | |||
'z-index:10' | |||
].join( ';' ); | |||
for ( var i = 0; i < 12; i++ ) { | |||
var drip = document.createElement( 'div' ); | |||
drip.innerHTML = SVG.waxDrip; | |||
drip.style.cssText = [ | |||
'position:absolute', | |||
'top:0', | |||
'left:' + ( i * 8.5 + rand( 0, 4 ) ) + '%', | |||
'opacity:' + rand( 0.2, 0.45 ), | |||
'transform:scaleY(0)', | |||
'transform-origin:top center', | |||
'animation:h-wax-drip ' + rand( 2, 5 ) + 's ' + rand( 0, 8 ) + 's ease-in forwards' | |||
].join( ';' ); | |||
topBar.appendChild( drip ); | |||
} | } | ||
// | /* Make content position:relative so absolute children work */ | ||
if ( getComputedStyle( content ).position === 'static' ) { | |||
content.style.position = 'relative'; | |||
} | } | ||
content.appendChild( topBar ); | |||
} | } | ||
/* | /* ── MOUSE PARALLAX ──────────────────────────────────────── */ | ||
function initParallax( layer ) { | |||
var cx = window.innerWidth / 2, cy = window.innerHeight / 2; | |||
function | var tx = 0, ty = 0, cx2 = 0, cy2 = 0; | ||
document.addEventListener( 'mousemove', function ( e ) { | |||
tx = ( e.clientX - cx ) / cx * 12; | |||
ty = ( e.clientY - cy ) / cy * 8; | |||
} ); | |||
( function tick() { | |||
cx2 += ( tx - cx2 ) * 0.03; | |||
cy2 += ( ty - cy2 ) * 0.03; | |||
layer.style.transform = 'translate(' + cx2 + 'px,' + cy2 + 'px)'; | |||
requestAnimationFrame( tick ); | |||
}() ); | |||
}); | |||
} | |||
} | } | ||
/* | /* ── CANDLE CLICK SPARK ──────────────────────────────────── */ | ||
function initClickSpark() { | |||
document.addEventListener( 'click', function ( e ) { | |||
function | var sparks = 6; | ||
for ( var s = 0; s < sparks; s++ ) { | |||
document. | ( function ( i ) { | ||
var sp = document.createElement( 'div' ); | |||
var angle = ( i / sparks ) * Math.PI * 2 + rand( -0.3, 0.3 ); | |||
var dist = rand( 20, 55 ); | |||
sp.style.cssText = [ | |||
'position:fixed', | |||
'pointer-events:none', | |||
'z-index:9994', | |||
'width:' + rand( 3, 6 ) + 'px', | |||
'height:' + rand( 3, 6 ) + 'px', | |||
'border-radius:50%', | |||
'left:' + e.clientX + 'px', | |||
'top:' + e.clientY + 'px', | |||
'background:' + ( Math.random() < 0.5 ? '#f8c840' : '#ff7010' ), | |||
'box-shadow:0 0 6px #f8c840', | |||
'transition:transform 0.5s ease-out,opacity 0.5s ease-out', | |||
'opacity:0.9' | |||
].join( ';' ); | |||
document.body.appendChild( sp ); | |||
requestAnimationFrame( function () { | |||
requestAnimationFrame( function () { | |||
sp.style.transform = 'translate(' + Math.cos( angle ) * dist + 'px,' + Math.sin( angle ) * dist + 'px)'; | |||
sp.style.opacity = '0'; | |||
setTimeout( function () { if ( sp.parentNode ) { sp.parentNode.removeChild( sp ); } }, 550 ); | |||
} ); | |||
} ); | |||
}( s ) ); | |||
}); | } | ||
} ); | |||
} | } | ||
/* | /* ── GOLD CURSOR TRAIL ────────────────────────────────────── */ | ||
function initCursorTrail() { | |||
var LEN = 8; | |||
function | var dots = [], pos = []; | ||
var mx = 0, my = 0; | |||
for ( var i = 0; i < LEN; i++ ) { | |||
var d = document.createElement( 'div' ); | |||
var sz = ( 6 - i * 0.5 ); | |||
d.style.cssText = [ | |||
'position:fixed', | |||
'pointer-events:none', | |||
'z-index:9996', | |||
'width:' + sz + 'px', | |||
'height:' + sz + 'px', | |||
'border-radius:50%', | |||
'opacity:' + ( ( LEN - i ) / LEN * 0.7 ), | |||
'background:' + ( i % 3 === 0 ? '#f8c840' : i % 3 === 1 ? '#c8860a' : '#d08090' ), | |||
'box-shadow:0 0 ' + sz + 'px ' + ( i % 3 === 0 ? '#f8c840' : '#c8860a' ), | |||
'mix-blend-mode:screen' | |||
].join( ';' ); | |||
document.body.appendChild( d ); | |||
dots.push( d ); | |||
}); | pos.push( { x: 0, y: 0 } ); | ||
} | |||
document.addEventListener( 'mousemove', function ( e ) { mx = e.clientX; my = e.clientY; } ); | |||
( function tick() { | |||
pos.unshift( { x: mx, y: my } ); | |||
}); | pos.length = LEN; | ||
}); | for ( var k = 0; k < LEN; k++ ) { | ||
dots[ k ].style.left = ( pos[ k ].x - 3 ) + 'px'; | |||
dots[ k ].style.top = ( pos[ k ].y - 3 ) + 'px'; | |||
} | |||
requestAnimationFrame( tick ); | |||
}() ); | |||
} | } | ||
/* | /* ── CANDLE GLOW ON HEADERS ──────────────────────────────── */ | ||
function animateHeaders() { | |||
var heads = document.querySelectorAll( '.mw-headline, h2, h3' ); | |||
function | heads.forEach( function ( h, i ) { | ||
h.style.animationDelay = ( i * 0.4 ) + 's'; | |||
} ); | |||
} | } | ||
/* | /* ── AMBIENT HAZE ────────────────────────────────────────── */ | ||
function createHaze() { | |||
var hz = document.createElement( 'div' ); | |||
function | hz.id = 'hades-haze'; | ||
document. | hz.style.cssText = [ | ||
'position:fixed', | |||
'inset:0', | |||
'pointer-events:none', | |||
'z-index:1', | |||
'background:' + | |||
'radial-gradient(ellipse 70% 50% at 50% 10%,rgba(200,134,10,0.06) 0%,transparent 70%),' + | |||
'radial-gradient(ellipse 50% 40% at 50% 95%,rgba(168,72,88,0.04) 0%,transparent 65%),' + | |||
'radial-gradient(ellipse 30% 30% at 80% 30%,rgba(248,200,64,0.03) 0%,transparent 60%)', | |||
'animation:h-breathe 10s ease-in-out infinite alternate' | |||
].join( ';' ); | |||
document.body.insertBefore( hz, document.body.firstChild ); | |||
} | } | ||
/* | /* ── MAIN ─────────────────────────────────────────────────── */ | ||
function init() { | |||
if ( typeof mw !== 'undefined' ) { | |||
function | var action = mw.config.get( 'wgAction' ); | ||
if ( action === 'edit' || action === 'submit' ) { return; } | |||
if (! | |||
} | } | ||
preloadFonts(); | |||
createHaze(); | |||
var layer = createLayer(); | |||
/* ── Candles ── */ | |||
for ( var i = 0; i < 5; i++ ) { spawn( layer, 'candleTall', 'h-candle-el', { minScale: 0.4, maxScale: 0.9, edged: true } ); } | |||
for ( var j = 0; j < 5; j++ ) { spawn( layer, 'candleShort', 'h-candle-el', { minScale: 0.5, maxScale: 1.0, edged: true } ); } | |||
for ( var k = 0; k < 3; k++ ) { spawn( layer, 'candleCluster', 'h-candle-el', { minScale: 0.4, maxScale: 0.7, edged: false } ); } | |||
for ( var ci = 0; ci < 2; ci++ ) { spawn( layer, 'candelabra', 'h-candle-el', { minScale: 0.35, maxScale: 0.6, edged: true, opacity: '0.12' } ); } | |||
// | /* ── Gothic arches ── */ | ||
for ( var a = 0; a < 5; a++ ) { spawn( layer, 'gothicArch', 'h-arch-el', { minScale: 0.5, maxScale: 1.2, opacity: '0.1' } ); } | |||
/* ── Mirror silhouettes ── */ | |||
for ( var m = 0; m < 3; m++ ) { spawn( layer, 'mirrorSilhouette', 'h-arch-el', { minScale: 0.4, maxScale: 0.9, opacity: '0.08' } ); } | |||
/* ── Sacred hearts ── */ | |||
for ( var sh = 0; sh < 4; sh++ ) { spawn( layer, 'sacredHeart', 'h-arch-el', { minScale: 0.4, maxScale: 0.9, opacity: '0.1' } ); } | |||
/* ── Crowns ── */ | |||
for ( var cr = 0; cr < 3; cr++ ) { spawn( layer, 'crown', 'h-candle-el', { minScale: 0.5, maxScale: 0.9, opacity: '0.09' } ); } | |||
/* ── Damask ornaments ── */ | |||
for ( var d = 0; d < 6; d++ ) { spawn( layer, 'damask', 'h-damask-el', { minScale: 0.6, maxScale: 1.4, opacity: '0.07' } ); } | |||
/* ── Roses ── */ | |||
for ( var r = 0; r < 5; r++ ) { spawn( layer, 'rose', 'h-candle-el', { minScale: 0.5, maxScale: 1.0, opacity: '0.1' } ); } | |||
/* ── Keys ── */ | |||
for ( var kk = 0; kk < 4; kk++ ) { spawn( layer, 'key', 'h-arch-el', { minScale: 0.4, maxScale: 0.9, opacity: '0.09' } ); } | |||
/* ── Wax drips (scattered) ── */ | |||
for ( var w = 0; w < 8; w++ ) { spawn( layer, 'waxDrip', 'h-candle-el', { minScale: 0.3, maxScale: 0.8, opacity: '0.12' } ); } | |||
/* ── Rose petals falling ── */ | |||
for ( var p = 0; p < 14; p++ ) { spawnPetal( layer ); } | |||
/* ── Dust motes ── */ | |||
for ( var mo = 0; mo < 20; mo++ ) { spawnMote( layer ); } | |||
/* ── Effects ── */ | |||
initParallax( layer ); | |||
initClickSpark(); | |||
initCursorTrail(); | |||
animateHeaders(); | |||
injectWaxDrips(); | |||
// | /* Slowly add new petals over time */ | ||
setInterval( function () { | |||
if ( layer.querySelectorAll( '.h-petal' ).length < 25 ) { spawnPetal( layer ); } | |||
}, | }, 8000 ); | ||
/* Replenish motes */ | |||
setInterval( function () { | |||
if ( layer.querySelectorAll( '.h-mote' ).length < 30 ) { spawnMote( layer ); } | |||
}, 4000 ); | |||
} | } | ||
// | /* ── BOOT ─────────────────────────────────────────────────── */ | ||
if ( | if ( typeof mw !== 'undefined' ) { | ||
mw.loader.using( | mw.loader.using( 'mediawiki.util' ).then( function () { | ||
$( document ).ready( init ); | |||
} ); | |||
}); | |||
} else { | } else { | ||
document.addEventListener('DOMContentLoaded', init); | document.addEventListener( 'DOMContentLoaded', init ); | ||
} | } | ||
}) | }() ); | ||
Latest revision as of 01:20, 15 April 2026
/* ================================================================
H A D E S — MediaWiki:Common.js
Ambient visual layer: candles, gothic arches, rose petals,
sacred hearts, damask motifs, wax drips, dust motes
================================================================ */
( function () {
'use strict';
/* ── FONT PRELOAD ─────────────────────────────────────────── */
function preloadFonts() {
if ( document.getElementById( 'hades-fonts' ) ) { return; }
var link = document.createElement( 'link' );
link.id = 'hades-fonts';
link.rel = 'stylesheet';
link.href = 'https://fonts.googleapis.com/css2?family=Cinzel+Decorative:wght@400;700;900&family=Cinzel:wght@400;600;700&family=IM+Fell+English:ital@0;1&family=Cormorant+Garamond:ital,wght@0,300;0,400;0,600;1,400&family=UnifrakturMaguntia&family=Playfair+Display+SC:wght@400;700&family=Petit+Formal+Script&display=swap';
document.head.appendChild( link );
}
/* ── SVG LIBRARY ──────────────────────────────────────────── */
var SVG = {
/* Tall pillar candle with dripping wax */
candleTall: [
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 200" width="44" height="146">',
/* flame */
'<g style="animation:h-flame-dance 0.8s ease-in-out infinite;transform-origin:30px 22px">',
'<ellipse cx="30" cy="28" rx="7" ry="14" fill="#ff7010" opacity="0.9"/>',
'<ellipse cx="30" cy="30" rx="4" ry="10" fill="#f8c840" opacity="0.95"/>',
'<ellipse cx="30" cy="32" rx="2" ry="5" fill="#ffffff" opacity="0.7"/>',
/* glow halo */
'<ellipse cx="30" cy="28" rx="14" ry="18" fill="#f8c840" opacity="0.08"/>',
'</g>',
/* wick */
'<line x1="30" y1="40" x2="30" y2="50" stroke="#3a2010" stroke-width="1.5"/>',
/* wax body */
'<rect x="18" y="48" width="24" height="130" rx="3" fill="#f2ede0"/>',
'<rect x="20" y="50" width="4" height="128" rx="1" fill="#ffffff" opacity="0.15"/>',
/* drips */
'<path d="M22,50 Q20,60 21,75 Q22,82 22,90" stroke="#e8e0cc" stroke-width="3" fill="none" stroke-linecap="round"/>',
'<path d="M36,50 Q38,65 37,78" stroke="#e8e0cc" stroke-width="2.5" fill="none" stroke-linecap="round"/>',
'<path d="M28,48 Q27,58 28,68" stroke="#f0e8d0" stroke-width="2" fill="none" stroke-linecap="round"/>',
'<ellipse cx="21" cy="90" rx="2.5" ry="3.5" fill="#d8d0c0"/>',
'<ellipse cx="37" cy="78" rx="2" ry="3" fill="#d8d0c0"/>',
/* base puddle */
'<ellipse cx="30" cy="180" rx="18" ry="6" fill="#d8d0c0" opacity="0.6"/>',
'<rect x="16" y="174" width="28" height="8" rx="3" fill="#c8c0b0"/>',
'</svg>'
].join( '' ),
/* Short stubby candle, more wax pooled */
candleShort: [
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 120" width="36" height="86">',
'<g style="animation:h-flame-dance 1.1s ease-in-out infinite;transform-origin:25px 18px">',
'<ellipse cx="25" cy="22" rx="5" ry="10" fill="#ff7010" opacity="0.85"/>',
'<ellipse cx="25" cy="24" rx="3" ry="7" fill="#f8c840" opacity="0.95"/>',
'<ellipse cx="25" cy="25" rx="1.5" ry="4" fill="#ffffff" opacity="0.6"/>',
'<ellipse cx="25" cy="22" rx="10" ry="14" fill="#f8c840" opacity="0.07"/>',
'</g>',
'<line x1="25" y1="32" x2="25" y2="40" stroke="#3a2010" stroke-width="1.5"/>',
'<rect x="14" y="38" width="22" height="65" rx="4" fill="#f0ece0"/>',
'<rect x="16" y="40" width="3" height="62" rx="1" fill="#ffffff" opacity="0.12"/>',
'<path d="M18,40 Q16,55 17,70 Q17,78 16,85" stroke="#e0d8c4" stroke-width="3" fill="none" stroke-linecap="round"/>',
'<ellipse cx="16" cy="85" rx="2.5" ry="3" fill="#ccc4b0"/>',
/* large wax pool */
'<ellipse cx="25" cy="106" rx="22" ry="7" fill="#ddd8c8" opacity="0.7"/>',
'<rect x="10" y="100" width="30" height="10" rx="4" fill="#c8c0b0"/>',
'</svg>'
].join( '' ),
/* Cluster of 3 candles on a holder */
candleCluster: [
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 200" width="100" height="167">',
/* left candle */
'<g transform="translate(10,20)">',
'<g style="animation:h-flame-dance 0.9s 0.2s ease-in-out infinite;transform-origin:20px 16px">',
'<ellipse cx="20" cy="18" rx="5" ry="11" fill="#ff8020" opacity="0.9"/>',
'<ellipse cx="20" cy="20" rx="3" ry="7" fill="#f8c840"/>',
'<ellipse cx="20" cy="22" rx="1.5" ry="4" fill="#fff" opacity="0.6"/>',
'<ellipse cx="20" cy="18" rx="10" ry="14" fill="#f8c840" opacity="0.07"/>',
'</g>',
'<line x1="20" y1="28" x2="20" y2="35" stroke="#3a2010" stroke-width="1"/>',
'<rect x="12" y="33" width="16" height="100" rx="3" fill="#f2ede0"/>',
'<path d="M14,35 Q12,50 13,70" stroke="#e0d8c4" stroke-width="2.5" fill="none" stroke-linecap="round"/>',
'</g>',
/* centre candle (taller) */
'<g transform="translate(40,0)">',
'<g style="animation:h-flame-dance 0.7s ease-in-out infinite;transform-origin:20px 18px">',
'<ellipse cx="20" cy="20" rx="6" ry="14" fill="#ff6010" opacity="0.95"/>',
'<ellipse cx="20" cy="23" rx="4" ry="9" fill="#f8c840"/>',
'<ellipse cx="20" cy="25" rx="2" ry="5" fill="#fff" opacity="0.7"/>',
'<ellipse cx="20" cy="20" rx="14" ry="18" fill="#f8c840" opacity="0.08"/>',
'</g>',
'<line x1="20" y1="32" x2="20" y2="40" stroke="#3a2010" stroke-width="1.5"/>',
'<rect x="11" y="38" width="18" height="130" rx="3" fill="#f0ece0"/>',
'<path d="M13,40 Q11,60 12,85" stroke="#e0d8c4" stroke-width="3" fill="none" stroke-linecap="round"/>',
'<ellipse cx="12" cy="85" rx="2.5" ry="3.5" fill="#ccc4b0"/>',
'</g>',
/* right candle */
'<g transform="translate(76,28)">',
'<g style="animation:h-flame-dance 1.0s 0.5s ease-in-out infinite;transform-origin:18px 15px">',
'<ellipse cx="18" cy="16" rx="4" ry="9" fill="#ff7018" opacity="0.85"/>',
'<ellipse cx="18" cy="18" rx="3" ry="6" fill="#f8c840"/>',
'<ellipse cx="18" cy="20" rx="1.5" ry="3.5" fill="#fff" opacity="0.55"/>',
'<ellipse cx="18" cy="16" rx="9" ry="13" fill="#f8c840" opacity="0.06"/>',
'</g>',
'<line x1="18" y1="25" x2="18" y2="32" stroke="#3a2010" stroke-width="1"/>',
'<rect x="10" y="30" width="15" height="90" rx="3" fill="#f2ede0"/>',
'<path d="M22,32 Q24,48 23,62" stroke="#e0d8c4" stroke-width="2.5" fill="none" stroke-linecap="round"/>',
'</g>',
/* shared base plate */
'<rect x="4" y="170" width="112" height="14" rx="4" fill="#8a6030"/>',
'<rect x="2" y="183" width="116" height="8" rx="3" fill="#6a4820"/>',
'<ellipse cx="60" cy="191" rx="58" ry="6" fill="#4a3010" opacity="0.5"/>',
'</svg>'
].join( '' ),
/* Gothic pointed arch frame */
gothicArch: [
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 150" width="90" height="135">',
'<path d="M10,150 L10,70 Q10,5 50,5 Q90,5 90,70 L90,150" fill="none" stroke="#c8860a" stroke-width="1.5" opacity="0.7"/>',
/* inner arch */
'<path d="M18,150 L18,74 Q18,20 50,20 Q82,20 82,74 L82,150" fill="none" stroke="#e8b030" stroke-width="0.8" opacity="0.4"/>',
/* keystone ornament */
'<ellipse cx="50" cy="8" rx="6" ry="7" fill="none" stroke="#c8860a" stroke-width="1.2" opacity="0.7"/>',
'<circle cx="50" cy="8" r="2.5" fill="#c8860a" opacity="0.6"/>',
/* column capitals */
'<rect x="4" y="140" width="14" height="10" rx="1" fill="#8a5a18" opacity="0.5"/>',
'<rect x="82" y="140" width="14" height="10" rx="1" fill="#8a5a18" opacity="0.5"/>',
/* tracery at top */
'<path d="M35,35 Q50,18 65,35" fill="none" stroke="#c8860a" stroke-width="0.8" opacity="0.35"/>',
'<circle cx="50" cy="30" r="4" fill="none" stroke="#e8b030" stroke-width="0.8" opacity="0.4"/>',
'</svg>'
].join( '' ),
/* Sacred heart */
sacredHeart: [
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 90" width="70" height="79">',
/* heart body */
'<path d="M40,70 C20,55 5,45 5,28 C5,16 14,8 25,8 C31,8 37,11 40,16 C43,11 49,8 55,8 C66,8 75,16 75,28 C75,45 60,55 40,70Z" fill="#a84858" opacity="0.8"/>',
/* light overlay */
'<path d="M25,14 Q30,10 35,16" stroke="#f0b0c0" stroke-width="2" fill="none" opacity="0.5"/>',
/* flames on top */
'<g transform="translate(33,-2)">',
'<path d="M7,10 Q5,4 7,0 Q9,4 7,10Z" fill="#f8c840" opacity="0.9"/>',
'<path d="M14,12 Q12,5 14,1 Q16,5 14,12Z" fill="#ff7010" opacity="0.85"/>',
'<path d="M21,10 Q19,4 21,0 Q23,4 21,10Z" fill="#f8c840" opacity="0.9"/>',
'</g>',
/* crown */
'<g transform="translate(22,-5)">',
'<path d="M0,12 L0,0 L9,5 L18,0 L27,5 L36,0 L36,12Z" fill="none" stroke="#e8b030" stroke-width="1" opacity="0.7"/>',
'<circle cx="9" cy="5" r="2" fill="#e8b030" opacity="0.7"/>',
'<circle cx="18" cy="0" r="2.5" fill="#f8d060" opacity="0.8"/>',
'<circle cx="27" cy="5" r="2" fill="#e8b030" opacity="0.7"/>',
'</g>',
/* thorns / ring */
'<circle cx="40" cy="35" r="18" fill="none" stroke="#3a1e0c" stroke-width="1.5" stroke-dasharray="3,4" opacity="0.6"/>',
'</svg>'
].join( '' ),
/* Baroque damask ornament */
damask: [
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="90" height="90">',
'<g fill="none" stroke="#c8860a" stroke-width="0.6" opacity="0.8">',
'<ellipse cx="50" cy="50" rx="8" ry="8"/>',
'<ellipse cx="50" cy="22" rx="5" ry="16"/>',
'<ellipse cx="50" cy="78" rx="5" ry="16"/>',
'<ellipse cx="22" cy="50" rx="16" ry="5"/>',
'<ellipse cx="78" cy="50" rx="16" ry="5"/>',
'<path d="M50,34 Q60,42 50,50 Q40,42 50,34Z"/>',
'<path d="M50,66 Q60,58 50,50 Q40,58 50,66Z"/>',
'<path d="M34,50 Q42,60 50,50 Q42,40 34,50Z"/>',
'<path d="M66,50 Q58,60 50,50 Q58,40 66,50Z"/>',
'<circle cx="50" cy="10" r="3"/>',
'<circle cx="50" cy="90" r="3"/>',
'<circle cx="10" cy="50" r="3"/>',
'<circle cx="90" cy="50" r="3"/>',
'<path d="M38,38 Q50,30 62,38 Q70,50 62,62 Q50,70 38,62 Q30,50 38,38Z"/>',
'</g>',
'</svg>'
].join( '' ),
/* Rose petal */
petal: [
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 36" width="18" height="27">',
'<path d="M12,2 Q20,8 20,20 Q20,32 12,34 Q4,32 4,20 Q4,8 12,2Z" fill="#c06070" opacity="0.7"/>',
'<path d="M12,6 Q16,12 15,22" stroke="#e090a0" stroke-width="0.8" fill="none" opacity="0.5"/>',
'</svg>'
].join( '' ),
/* Ornate candelabra */
candelabra: [
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 260" width="130" height="211">',
/* left arm candle */
'<g transform="translate(4,30)">',
'<g style="animation:h-flame-dance 0.85s 0.1s ease-in-out infinite;transform-origin:18px 16px">',
'<ellipse cx="18" cy="18" rx="5" ry="12" fill="#ff7010" opacity="0.9"/>',
'<ellipse cx="18" cy="20" rx="3" ry="8" fill="#f8c840"/>',
'<ellipse cx="18" cy="22" rx="2" ry="4" fill="#fff" opacity="0.6"/>',
'<ellipse cx="18" cy="18" rx="12" ry="16" fill="#f8c840" opacity="0.06"/>',
'</g>',
'<line x1="18" y1="30" x2="18" y2="36" stroke="#3a2010" stroke-width="1.2"/>',
'<rect x="11" y="34" width="14" height="80" rx="3" fill="#f0ece0"/>',
'<path d="M12,36 Q10,55 11,72" stroke="#e0d8c4" stroke-width="2.5" fill="none" stroke-linecap="round"/>',
'</g>',
/* right arm candle */
'<g transform="translate(134,30)">',
'<g style="animation:h-flame-dance 1.05s 0.3s ease-in-out infinite;transform-origin:18px 16px">',
'<ellipse cx="18" cy="18" rx="5" ry="12" fill="#ff7010" opacity="0.9"/>',
'<ellipse cx="18" cy="20" rx="3" ry="8" fill="#f8c840"/>',
'<ellipse cx="18" cy="22" rx="2" ry="4" fill="#fff" opacity="0.6"/>',
'<ellipse cx="18" cy="18" rx="12" ry="16" fill="#f8c840" opacity="0.06"/>',
'</g>',
'<line x1="18" y1="30" x2="18" y2="36" stroke="#3a2010" stroke-width="1.2"/>',
'<rect x="11" y="34" width="14" height="80" rx="3" fill="#f0ece0"/>',
'<path d="M24,36 Q26,55 25,72" stroke="#e0d8c4" stroke-width="2.5" fill="none" stroke-linecap="round"/>',
'</g>',
/* centre tall candle */
'<g transform="translate(62,0)">',
'<g style="animation:h-flame-dance 0.7s ease-in-out infinite;transform-origin:18px 20px">',
'<ellipse cx="18" cy="20" rx="7" ry="16" fill="#ff6010" opacity="0.95"/>',
'<ellipse cx="18" cy="23" rx="4" ry="10" fill="#f8c840"/>',
'<ellipse cx="18" cy="26" rx="2" ry="6" fill="#fff" opacity="0.7"/>',
'<ellipse cx="18" cy="20" rx="16" ry="22" fill="#f8c840" opacity="0.08"/>',
'</g>',
'<line x1="18" y1="36" x2="18" y2="44" stroke="#3a2010" stroke-width="1.5"/>',
'<rect x="10" y="42" width="16" height="120" rx="3" fill="#f2ede0"/>',
'<path d="M11,44 Q9,68 10,95" stroke="#e0d8c4" stroke-width="3" fill="none" stroke-linecap="round"/>',
'<ellipse cx="10" cy="95" rx="2.5" ry="3.5" fill="#ccc4b0"/>',
'</g>',
/* arms */
'<path d="M80,90 Q30,80 22,60" fill="none" stroke="#8a6030" stroke-width="3" stroke-linecap="round"/>',
'<path d="M80,90 Q130,80 152,60" fill="none" stroke="#8a6030" stroke-width="3" stroke-linecap="round"/>',
/* stem */
'<rect x="74" y="160" width="12" height="70" rx="4" fill="#7a5020"/>',
'<ellipse cx="80" cy="162" rx="12" ry="6" fill="#8a6030"/>',
/* base */
'<ellipse cx="80" cy="236" rx="45" ry="12" fill="#6a4020" opacity="0.7"/>',
'<rect x="50" y="228" width="60" height="10" rx="4" fill="#8a5820"/>',
'</svg>'
].join( '' ),
/* Mirror silhouette (album cover gothic arch mirror) */
mirrorSilhouette: [
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 160" width="80" height="128">',
/* outer frame */
'<path d="M8,160 L8,80 Q8,5 50,5 Q92,5 92,80 L92,160" fill="none" stroke="#8a5a18" stroke-width="3" opacity="0.6"/>',
/* inner mirror */
'<path d="M16,158 L16,82 Q16,18 50,18 Q84,18 84,82 L84,158" fill="rgba(10,5,2,0.5)" stroke="#c8860a" stroke-width="1" opacity="0.5"/>',
/* glow inside mirror */
'<path d="M16,158 L16,82 Q16,18 50,18 Q84,18 84,82 L84,158 Z" fill="url(#mirrorGlow)" opacity="0.3"/>',
'<defs><radialGradient id="mirrorGlow" cx="50%" cy="60%"><stop offset="0%" stop-color="#f8c840" stop-opacity="0.15"/><stop offset="100%" stop-color="#f8c840" stop-opacity="0"/></radialGradient></defs>',
/* spire ornaments */
'<path d="M8,80 L8,50 L14,30 L20,50 L20,80" fill="none" stroke="#8a5a18" stroke-width="1.5" opacity="0.5"/>',
'<path d="M80,80 L80,50 L86,30 L92,50 L92,80" fill="none" stroke="#8a5a18" stroke-width="1.5" opacity="0.5"/>',
/* keystone */
'<ellipse cx="50" cy="8" rx="7" ry="8" fill="none" stroke="#c8860a" stroke-width="1.5" opacity="0.6"/>',
'<circle cx="50" cy="8" r="3" fill="#c8860a" opacity="0.5"/>',
/* base shelf */
'<rect x="2" y="152" width="96" height="10" rx="2" fill="#6a4820" opacity="0.5"/>',
/* sacred heart base motif */
'<path d="M50,148 C44,143 38,140 38,134 C38,130 41,127 45,127 C47,127 49,128 50,130 C51,128 53,127 55,127 C59,127 62,130 62,134 C62,140 56,143 50,148Z" fill="#a84858" opacity="0.4"/>',
'</svg>'
].join( '' ),
/* Wax drip trail */
waxDrip: [
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 120" width="24" height="96">',
'<path d="M15,0 Q18,20 17,35 Q16,55 18,70 Q20,85 15,100 Q10,85 12,70 Q14,55 13,35 Q12,20 15,0Z" fill="#f2ede0" opacity="0.7"/>',
'<ellipse cx="15" cy="100" rx="8" ry="6" fill="#e8e0cc" opacity="0.6"/>',
'</svg>'
].join( '' ),
/* Ornate key */
key: [
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 120" width="30" height="90">',
'<circle cx="20" cy="20" r="14" fill="none" stroke="#c8860a" stroke-width="2" opacity="0.8"/>',
'<circle cx="20" cy="20" r="7" fill="none" stroke="#e8b030" stroke-width="1" opacity="0.6"/>',
'<circle cx="20" cy="20" r="3" fill="#c8860a" opacity="0.7"/>',
'<rect x="18" y="34" width="4" height="80" rx="1" fill="#c8860a" opacity="0.7"/>',
'<rect x="22" y="80" width="12" height="4" rx="1" fill="#c8860a" opacity="0.7"/>',
'<rect x="22" y="94" width="9" height="4" rx="1" fill="#c8860a" opacity="0.7"/>',
'</svg>'
].join( '' ),
/* Crown */
crown: [
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 80" width="100" height="67">',
'<path d="M5,75 L5,35 L25,10 L40,35 L60,5 L80,35 L95,10 L115,35 L115,75 Z" fill="none" stroke="#c8860a" stroke-width="2" stroke-linejoin="round" opacity="0.7"/>',
'<path d="M5,60 L115,60" stroke="#e8b030" stroke-width="1" opacity="0.5"/>',
'<circle cx="25" cy="13" r="4" fill="#e8b030" opacity="0.7"/>',
'<circle cx="60" cy="7" r="5" fill="#f8d060" opacity="0.8"/>',
'<circle cx="95" cy="13" r="4" fill="#e8b030" opacity="0.7"/>',
'<circle cx="40" cy="36" r="3" fill="#d08090" opacity="0.6"/>',
'<circle cx="80" cy="36" r="3" fill="#d08090" opacity="0.6"/>',
'<rect x="5" y="68" width="110" height="8" rx="2" fill="#8a5a18" opacity="0.4"/>',
'</svg>'
].join( '' ),
/* Floating rose */
rose: [
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60" width="48" height="48">',
'<circle cx="30" cy="30" r="10" fill="#a84858" opacity="0.8"/>',
'<path d="M30,20 Q38,24 36,32 Q30,38 22,32 Q20,24 30,20Z" fill="#c06070" opacity="0.7"/>',
'<path d="M30,20 Q22,24 24,32 Q30,38 38,32 Q40,24 30,20Z" fill="#b05060" opacity="0.7"/>',
'<path d="M30,14 Q40,18 40,28 Q40,38 30,42 Q20,38 20,28 Q20,18 30,14Z" fill="none" stroke="#d08090" stroke-width="0.8" opacity="0.5"/>',
'<path d="M30,8 Q44,14 44,30 Q44,46 30,50 Q16,46 16,30 Q16,14 30,8Z" fill="none" stroke="#c06070" stroke-width="0.6" opacity="0.4"/>',
'<path d="M30,50 L30,60" stroke="#3a1e0c" stroke-width="1.5"/>',
'<path d="M24,56 Q30,52 36,56" stroke="#2a1808" stroke-width="1" fill="none"/>',
'</svg>'
].join( '' )
};
/* ── HELPERS ──────────────────────────────────────────────── */
function rand( a, b ) { return Math.random() * ( b - a ) + a; }
function randInt( a, b ) { return Math.floor( rand( a, b + 1 ) ); }
/* ── BUILD LAYER ──────────────────────────────────────────── */
function createLayer() {
var div = document.createElement( 'div' );
div.className = 'h-ambient';
div.id = 'hades-ambient';
document.body.insertBefore( div, document.body.firstChild );
return div;
}
/* ── SPAWN AMBIENT ELEMENT ───────────────────────────────── */
function spawn( layer, svgKey, cssClass, opts ) {
opts = opts || {};
var el = document.createElement( 'div' );
el.className = cssClass;
el.innerHTML = SVG[ svgKey ];
var scale = rand( opts.minScale || 0.5, opts.maxScale || 1.4 );
el.style.transformOrigin = 'center center';
el.style.transform = 'scale(' + scale + ')';
/* Position */
var edged = ( opts.edged !== false ) && Math.random() < 0.35;
var top, left;
if ( edged ) {
var side = randInt( 0, 3 );
if ( side === 0 ) { top = rand( 0, 8 ); left = rand( 5, 90 ); }
else if ( side === 1 ) { top = rand( 85, 97 ); left = rand( 5, 90 ); }
else if ( side === 2 ) { top = rand( 5, 90 ); left = rand( 0, 6 ); }
else { top = rand( 5, 90 ); left = rand( 88, 97 );}
} else {
top = rand( opts.topMin || 5, opts.topMax || 90 );
left = rand( opts.leftMin || 5, opts.leftMax || 90 );
}
el.style.top = top + 'vh';
el.style.left = left + 'vw';
/* Animation stagger */
var delay = rand( 0, 18 );
var dur = rand( opts.durMin || 5, opts.durMax || 14 );
el.style.animationDelay = delay + 's';
el.style.animationDuration = dur + 's';
if ( opts.opacity ) { el.style.opacity = opts.opacity; }
layer.appendChild( el );
return el;
}
/* ── ROSE PETAL FALL ─────────────────────────────────────── */
function spawnPetal( layer ) {
var el = document.createElement( 'div' );
el.className = 'h-petal';
el.innerHTML = SVG.petal;
el.style.left = rand( 5, 95 ) + 'vw';
el.style.top = '-30px';
el.style.setProperty( '--drift', rand( -40, 60 ) + 'px' );
el.style.setProperty( '--rot', rand( -180, 360 ) + 'deg' );
var dur = rand( 8, 18 );
el.style.animationDuration = dur + 's';
el.style.animationDelay = rand( 0, 20 ) + 's';
el.style.opacity = rand( 0.25, 0.55 );
layer.appendChild( el );
}
/* ── DUST MOTES ──────────────────────────────────────────── */
function spawnMote( layer ) {
var el = document.createElement( 'div' );
el.className = 'h-mote';
el.style.left = rand( 10, 90 ) + 'vw';
el.style.top = rand( 20, 90 ) + 'vh';
el.style.setProperty( '--mx', rand( -30, 30 ) + 'px' );
el.style.setProperty( '--my', rand( -80, -120 ) + 'px' );
var dur = rand( 5, 12 );
el.style.animationDuration = dur + 's';
el.style.animationDelay = rand( 0, 15 ) + 's';
/* Vary colour: gold, rose, cream */
var colours = [ '#f8d060', '#e8b030', '#d08090', '#f0e8d0' ];
el.style.background = colours[ randInt( 0, colours.length - 1 ) ];
el.style.boxShadow = '0 0 ' + rand( 2, 6 ) + 'px currentColor';
layer.appendChild( el );
}
/* ── WAX DRIP TRAILS ON CONTENT EDGE ────────────────────── */
function injectWaxDrips() {
var content = document.getElementById( 'content' )
|| document.getElementById( 'mw-content-text' )
|| document.querySelector( '.mw-body' );
if ( !content ) { return; }
/* Top drip row — candle wax flowing down */
var topBar = document.createElement( 'div' );
topBar.style.cssText = [
'position:absolute',
'top:-1px',
'left:0',
'width:100%',
'height:40px',
'pointer-events:none',
'overflow:hidden',
'z-index:10'
].join( ';' );
for ( var i = 0; i < 12; i++ ) {
var drip = document.createElement( 'div' );
drip.innerHTML = SVG.waxDrip;
drip.style.cssText = [
'position:absolute',
'top:0',
'left:' + ( i * 8.5 + rand( 0, 4 ) ) + '%',
'opacity:' + rand( 0.2, 0.45 ),
'transform:scaleY(0)',
'transform-origin:top center',
'animation:h-wax-drip ' + rand( 2, 5 ) + 's ' + rand( 0, 8 ) + 's ease-in forwards'
].join( ';' );
topBar.appendChild( drip );
}
/* Make content position:relative so absolute children work */
if ( getComputedStyle( content ).position === 'static' ) {
content.style.position = 'relative';
}
content.appendChild( topBar );
}
/* ── MOUSE PARALLAX ──────────────────────────────────────── */
function initParallax( layer ) {
var cx = window.innerWidth / 2, cy = window.innerHeight / 2;
var tx = 0, ty = 0, cx2 = 0, cy2 = 0;
document.addEventListener( 'mousemove', function ( e ) {
tx = ( e.clientX - cx ) / cx * 12;
ty = ( e.clientY - cy ) / cy * 8;
} );
( function tick() {
cx2 += ( tx - cx2 ) * 0.03;
cy2 += ( ty - cy2 ) * 0.03;
layer.style.transform = 'translate(' + cx2 + 'px,' + cy2 + 'px)';
requestAnimationFrame( tick );
}() );
}
/* ── CANDLE CLICK SPARK ──────────────────────────────────── */
function initClickSpark() {
document.addEventListener( 'click', function ( e ) {
var sparks = 6;
for ( var s = 0; s < sparks; s++ ) {
( function ( i ) {
var sp = document.createElement( 'div' );
var angle = ( i / sparks ) * Math.PI * 2 + rand( -0.3, 0.3 );
var dist = rand( 20, 55 );
sp.style.cssText = [
'position:fixed',
'pointer-events:none',
'z-index:9994',
'width:' + rand( 3, 6 ) + 'px',
'height:' + rand( 3, 6 ) + 'px',
'border-radius:50%',
'left:' + e.clientX + 'px',
'top:' + e.clientY + 'px',
'background:' + ( Math.random() < 0.5 ? '#f8c840' : '#ff7010' ),
'box-shadow:0 0 6px #f8c840',
'transition:transform 0.5s ease-out,opacity 0.5s ease-out',
'opacity:0.9'
].join( ';' );
document.body.appendChild( sp );
requestAnimationFrame( function () {
requestAnimationFrame( function () {
sp.style.transform = 'translate(' + Math.cos( angle ) * dist + 'px,' + Math.sin( angle ) * dist + 'px)';
sp.style.opacity = '0';
setTimeout( function () { if ( sp.parentNode ) { sp.parentNode.removeChild( sp ); } }, 550 );
} );
} );
}( s ) );
}
} );
}
/* ── GOLD CURSOR TRAIL ────────────────────────────────────── */
function initCursorTrail() {
var LEN = 8;
var dots = [], pos = [];
var mx = 0, my = 0;
for ( var i = 0; i < LEN; i++ ) {
var d = document.createElement( 'div' );
var sz = ( 6 - i * 0.5 );
d.style.cssText = [
'position:fixed',
'pointer-events:none',
'z-index:9996',
'width:' + sz + 'px',
'height:' + sz + 'px',
'border-radius:50%',
'opacity:' + ( ( LEN - i ) / LEN * 0.7 ),
'background:' + ( i % 3 === 0 ? '#f8c840' : i % 3 === 1 ? '#c8860a' : '#d08090' ),
'box-shadow:0 0 ' + sz + 'px ' + ( i % 3 === 0 ? '#f8c840' : '#c8860a' ),
'mix-blend-mode:screen'
].join( ';' );
document.body.appendChild( d );
dots.push( d );
pos.push( { x: 0, y: 0 } );
}
document.addEventListener( 'mousemove', function ( e ) { mx = e.clientX; my = e.clientY; } );
( function tick() {
pos.unshift( { x: mx, y: my } );
pos.length = LEN;
for ( var k = 0; k < LEN; k++ ) {
dots[ k ].style.left = ( pos[ k ].x - 3 ) + 'px';
dots[ k ].style.top = ( pos[ k ].y - 3 ) + 'px';
}
requestAnimationFrame( tick );
}() );
}
/* ── CANDLE GLOW ON HEADERS ──────────────────────────────── */
function animateHeaders() {
var heads = document.querySelectorAll( '.mw-headline, h2, h3' );
heads.forEach( function ( h, i ) {
h.style.animationDelay = ( i * 0.4 ) + 's';
} );
}
/* ── AMBIENT HAZE ────────────────────────────────────────── */
function createHaze() {
var hz = document.createElement( 'div' );
hz.id = 'hades-haze';
hz.style.cssText = [
'position:fixed',
'inset:0',
'pointer-events:none',
'z-index:1',
'background:' +
'radial-gradient(ellipse 70% 50% at 50% 10%,rgba(200,134,10,0.06) 0%,transparent 70%),' +
'radial-gradient(ellipse 50% 40% at 50% 95%,rgba(168,72,88,0.04) 0%,transparent 65%),' +
'radial-gradient(ellipse 30% 30% at 80% 30%,rgba(248,200,64,0.03) 0%,transparent 60%)',
'animation:h-breathe 10s ease-in-out infinite alternate'
].join( ';' );
document.body.insertBefore( hz, document.body.firstChild );
}
/* ── MAIN ─────────────────────────────────────────────────── */
function init() {
if ( typeof mw !== 'undefined' ) {
var action = mw.config.get( 'wgAction' );
if ( action === 'edit' || action === 'submit' ) { return; }
}
preloadFonts();
createHaze();
var layer = createLayer();
/* ── Candles ── */
for ( var i = 0; i < 5; i++ ) { spawn( layer, 'candleTall', 'h-candle-el', { minScale: 0.4, maxScale: 0.9, edged: true } ); }
for ( var j = 0; j < 5; j++ ) { spawn( layer, 'candleShort', 'h-candle-el', { minScale: 0.5, maxScale: 1.0, edged: true } ); }
for ( var k = 0; k < 3; k++ ) { spawn( layer, 'candleCluster', 'h-candle-el', { minScale: 0.4, maxScale: 0.7, edged: false } ); }
for ( var ci = 0; ci < 2; ci++ ) { spawn( layer, 'candelabra', 'h-candle-el', { minScale: 0.35, maxScale: 0.6, edged: true, opacity: '0.12' } ); }
/* ── Gothic arches ── */
for ( var a = 0; a < 5; a++ ) { spawn( layer, 'gothicArch', 'h-arch-el', { minScale: 0.5, maxScale: 1.2, opacity: '0.1' } ); }
/* ── Mirror silhouettes ── */
for ( var m = 0; m < 3; m++ ) { spawn( layer, 'mirrorSilhouette', 'h-arch-el', { minScale: 0.4, maxScale: 0.9, opacity: '0.08' } ); }
/* ── Sacred hearts ── */
for ( var sh = 0; sh < 4; sh++ ) { spawn( layer, 'sacredHeart', 'h-arch-el', { minScale: 0.4, maxScale: 0.9, opacity: '0.1' } ); }
/* ── Crowns ── */
for ( var cr = 0; cr < 3; cr++ ) { spawn( layer, 'crown', 'h-candle-el', { minScale: 0.5, maxScale: 0.9, opacity: '0.09' } ); }
/* ── Damask ornaments ── */
for ( var d = 0; d < 6; d++ ) { spawn( layer, 'damask', 'h-damask-el', { minScale: 0.6, maxScale: 1.4, opacity: '0.07' } ); }
/* ── Roses ── */
for ( var r = 0; r < 5; r++ ) { spawn( layer, 'rose', 'h-candle-el', { minScale: 0.5, maxScale: 1.0, opacity: '0.1' } ); }
/* ── Keys ── */
for ( var kk = 0; kk < 4; kk++ ) { spawn( layer, 'key', 'h-arch-el', { minScale: 0.4, maxScale: 0.9, opacity: '0.09' } ); }
/* ── Wax drips (scattered) ── */
for ( var w = 0; w < 8; w++ ) { spawn( layer, 'waxDrip', 'h-candle-el', { minScale: 0.3, maxScale: 0.8, opacity: '0.12' } ); }
/* ── Rose petals falling ── */
for ( var p = 0; p < 14; p++ ) { spawnPetal( layer ); }
/* ── Dust motes ── */
for ( var mo = 0; mo < 20; mo++ ) { spawnMote( layer ); }
/* ── Effects ── */
initParallax( layer );
initClickSpark();
initCursorTrail();
animateHeaders();
injectWaxDrips();
/* Slowly add new petals over time */
setInterval( function () {
if ( layer.querySelectorAll( '.h-petal' ).length < 25 ) { spawnPetal( layer ); }
}, 8000 );
/* Replenish motes */
setInterval( function () {
if ( layer.querySelectorAll( '.h-mote' ).length < 30 ) { spawnMote( layer ); }
}, 4000 );
}
/* ── BOOT ─────────────────────────────────────────────────── */
if ( typeof mw !== 'undefined' ) {
mw.loader.using( 'mediawiki.util' ).then( function () {
$( document ).ready( init );
} );
} else {
document.addEventListener( 'DOMContentLoaded', init );
}
}() );