<!-- wp:html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Xyndoria - Dice Battle</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        /* Import Google Fonts: Inter for UI, MedievalSharp for thematic titles */
        @import url('https://fonts.googleapis.com/css2?family=MedievalSharp&family=Inter:wght@400;500;700&display=swap');
        /* Base font for the body - Inter for readability */
        body {
            font-family: 'Inter', sans-serif;
        }
        /* Apply MedievalSharp to the main title */
        h1.text-4xl { /* Targeting the main Xyndoria title */
            font-family: 'MedievalSharp', cursive; /* 'cursive' is a generic fallback, MedievalSharp is primary */
        }
        /* Apply MedievalSharp to Attacker/Defender titles */
        #player1-area h2, 
        #player2-area h2 {
            font-family: 'MedievalSharp', cursive; /* 'cursive' is a generic fallback, MedievalSharp is primary */
        }
        /* Animation for the flame appearance */
        .rolling {
            animation: flame-appear-animation 1s ease-out;
        }
        @keyframes flame-appear-animation {
            0% {
                opacity: 0;
                transform: scale(0.4) translateY(20px);
                filter: brightness(2) saturate(3) hue-rotate(-30deg);
            }
            30% {
                opacity: 0.9;
                transform: scale(1.3) translateY(-15px);
                filter: brightness(2.5) saturate(3.5) hue-rotate(-20deg);
            }
            50% {
                opacity: 0.7;
                transform: scale(1.1) translateY(-10px) rotateZ(3deg);
                filter: brightness(2.2) saturate(3) hue-rotate(-25deg);
            }
            70% {
                opacity: 1;
                transform: scale(0.95) translateY(-5px) rotateZ(-2deg);
                filter: brightness(1.5) saturate(1.5) hue-rotate(-10deg);
            }
            100% {
                opacity: 1;
                transform: scale(1) translateY(0px) rotateZ(0deg);
                filter: brightness(1) saturate(1) hue-rotate(0deg);
            }
        }
        .perspective-800 {
            perspective: 800px;
        }
        .transform-style-preserve-3d {
            transform-style: preserve-3d;
        }
        /* Styling for die selection buttons */
        .die-option {
            transition: background-color 0.2s ease-in-out, transform 0.1s ease;
        }
        /* Ensure SVGs scale within their container */
        .die-visual-container svg {
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body class="bg-slate-900 flex flex-col items-center justify-center min-h-screen text-white p-4 overflow-hidden">
    <h1 class="text-4xl font-bold mb-8 text-center">Dice Roller</h1>
    <div class="flex flex-col md:flex-row justify-around items-start w-full max-w-4xl mx-auto">
        <div id="player1-area" class="flex flex-col items-center mb-8 md:mb-0 md:mr-4 perspective-800 w-full md:w-1/2">
            <h2 class="text-2xl font-semibold mb-3 text-sky-400">Attacker</h2>
            <div id="player1-die-options" class="flex flex-wrap justify-center gap-2 mb-4 pt-1">
                <button data-value="4" class="die-option bg-slate-700 hover:bg-slate-600 text-white font-medium py-2 px-4 rounded-md">D4</button>
                <button data-value="6" class="die-option bg-slate-700 hover:bg-slate-600 text-white font-medium py-2 px-4 rounded-md">D6</button>
                <button data-value="8" class="die-option bg-slate-700 hover:bg-slate-600 text-white font-medium py-2 px-4 rounded-md">D8</button>
                <button data-value="10" class="die-option bg-slate-700 hover:bg-slate-600 text-white font-medium py-2 px-4 rounded-md">D10</button>
                <button data-value="12" class="die-option bg-slate-700 hover:bg-slate-600 text-white font-medium py-2 px-4 rounded-md">D12</button>
            </div>
            <div id="die1-visual" class="die-visual-container w-24 h-24 md:w-32 md:h-32 flex items-center justify-center p-1 transform-style-preserve-3d mb-4">
                {/* SVG spinner will be injected here by JS */}
            </div>
        </div>
        <div id="player2-area" class="flex flex-col items-center md:ml-4 perspective-800 w-full md:w-1/2">
            <h2 class="text-2xl font-semibold mb-3 text-pink-400">Defender</h2>
            <div id="player2-die-options" class="flex flex-wrap justify-center gap-2 mb-4 pt-1">
                <button data-value="4" class="die-option bg-slate-700 hover:bg-slate-600 text-white font-medium py-2 px-4 rounded-md">D4</button>
                <button data-value="6" class="die-option bg-slate-700 hover:bg-slate-600 text-white font-medium py-2 px-4 rounded-md">D6</button>
                <button data-value="8" class="die-option bg-slate-700 hover:bg-slate-600 text-white font-medium py-2 px-4 rounded-md">D8</button>
                <button data-value="10" class="die-option bg-slate-700 hover:bg-slate-600 text-white font-medium py-2 px-4 rounded-md">D10</button>
                <button data-value="12" class="die-option bg-slate-700 hover:bg-slate-600 text-white font-medium py-2 px-4 rounded-md">D12</button>
            </div>
            <div id="die2-visual" class="die-visual-container w-24 h-24 md:w-32 md:h-32 flex items-center justify-center p-1 transform-style-preserve-3d mb-4">
                {/* SVG spinner will be injected here by JS */}
            </div>
        </div>
    </div>
    <div class="w-full flex justify-center">
        <button id="roll-button" class="mt-10 bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-8 rounded-lg text-xl shadow-lg transition-all duration-150 ease-in-out active:scale-95 focus:outline-none focus:ring-2 focus:ring-indigo-400">
            Roll for Battle!
        </button>
    </div>
    <div id="battle-result-area" class="mt-8 text-3xl font-bold h-12 text-center">
    </div>
    <script>
        // Get DOM elements
        const die1VisualElement = document.getElementById('die1-visual');
        const player1DieOptionsContainer = document.getElementById('player1-die-options');
        const die2VisualElement = document.getElementById('die2-visual');
        const player2DieOptionsContainer = document.getElementById('player2-die-options');
        const rollButton = document.getElementById('roll-button');
        const numberColor = "#FFFFFF";
        const numberOutlineColor = "#111827"; 
        const shapeColorPlayer1 = '#4ade80'; 
        const shapeColorPlayer2 = '#c084fc'; 
        const spinnerBaseMetalColor = "#334155"; 
        const spinnerEngravingColor = "#64748b"; 
        const spinnerGemEdgeColor = "#fde047"; 
        const compassBezelColor = "#4a3b31"; 
        const compassFaceColor = "#d4c8b0"; 
        const compassMarkingColor = "#3e2723"; 
        const compassNeedleHighlight = "#f5e5c3"; 
        const gemSettingColor = "#b08d57"; 
        let player1SelectedDieMax = 6;
        let player2SelectedDieMax = 6;
        
        let lastRoll1 = 1;
        let lastRoll2 = 1;
        const selectedOptionClassPlayer1 = 'bg-sky-500';
        const selectedOptionClassPlayer2 = 'bg-pink-500';
        const defaultOptionClass = 'bg-slate-700';
        const hoverOptionClass = 'hover:bg-slate-600';
        let isRolling = false;
        let rollingEffectInterval1 = { id: null };
        let rollingEffectInterval2 = { id: null };
        const animationDuration = 1000;
        const faceChangeInterval = 80;
        /**
         * Sets up the die selection buttons for a player.
         */
        function setupDieSelection(container, onSelectCallback, defaultDieValue, selectedClass, playerIndex) {
            const buttons = container.querySelectorAll('.die-option');
            buttons.forEach(button => {
                if (parseInt(button.dataset.value) === defaultDieValue) {
                    button.classList.remove(defaultOptionClass, hoverOptionClass);
                    button.classList.add(selectedClass);
                }
                button.addEventListener('click', () => {
                    buttons.forEach(btn => {
                        btn.classList.remove(selectedClass);
                        btn.classList.add(defaultOptionClass, hoverOptionClass);
                    });
                    button.classList.remove(defaultOptionClass, hoverOptionClass);
                    button.classList.add(selectedClass);
                    onSelectCallback(parseInt(button.dataset.value));
                    
                    if (playerIndex === 1) {
                        drawFantasySpinner(die1VisualElement, lastRoll1, player1SelectedDieMax, shapeColorPlayer1);
                    } else {
                        drawFantasySpinner(die2VisualElement, lastRoll2, player2SelectedDieMax, shapeColorPlayer2);
                    }
                });
            });
        }
        /**
         * Draws the D&D themed fantasy compass spinner with the rolled number.
         * @param {HTMLElement} dieVisualElement - The div element of the die to draw on.
         * @param {number} number - The number to display.
         * @param {number} dieType - The type of die (max value).
         * @param {string} playerGemColor - The base color for the central gem.
         */
        function drawFantasySpinner(dieVisualElement, number, dieType, playerGemColor) {
            const fontSize = Math.max(20, 45 - (String(number).length * 5));
            const uniqueGradId = `gemGrad-${playerGemColor.replace(/[^a-zA-Z0-9]/g, '')}${Math.random().toString(36).substring(2,7)}`;
            const compassFaceGradId = `compassFaceGrad-${Math.random().toString(36).substring(2,7)}`;
            const legibleFontFamily = "'Inter', Arial, sans-serif"; // Define legible font stack for SVG text
            const svgString = `
                <svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet">
                    <defs>
                        <radialGradient id="${uniqueGradId}" cx="50%" cy="50%" r="70%" fx="50%" fy="40%">
                            <stop offset="0%" style="stop-color:white;stop-opacity:0.8" />
                            <stop offset="50%" style="stop-color:${playerGemColor};stop-opacity:1" />
                            <stop offset="100%" style="stop-color:${playerGemColor};stop-opacity:0.7" />
                        </radialGradient>
                        <linearGradient id="${compassFaceGradId}" x1="0%" y1="0%" x2="100%" y2="100%">
                            <stop offset="0%" style="stop-color:${compassNeedleHighlight};stop-opacity:1" />
                            <stop offset="100%" style="stop-color:${compassFaceColor};stop-opacity:1" />
                        </linearGradient>
                         <filter id="dropshadow" height="130%">
                            <feGaussianBlur in="SourceAlpha" stdDeviation="1"/>
                            <feOffset dx="0.5" dy="0.5" result="offsetblur"/>
                            <feComponentTransfer>
                                <feFuncA type="linear" slope="0.5"/>
                            </feComponentTransfer>
                            <feMerge>
                                <feMergeNode/>
                                <feMergeNode in="SourceGraphic"/>
                            </feMerge>
                        </filter>
                        <path id="runicBorderPath" d="M50,2 
                            C 20,2 2,20 2,50 
                            S 20,98 50,98 
                            S 98,80 98,50 
                            S 80,2 50,2 Z 
                            M50,8 
                            C 24,8 8,24 8,50 
                            S 24,92 50,92 
                            S 92,76 92,50 
                            S 76,8 50,8 Z" fill-rule="evenodd"/>
                        <clipPath id="clipRunic">
                            <use href="#runicBorderPath"/>
                        </clipPath>
                    </defs>
                    <use href="#runicBorderPath" fill="${spinnerBaseMetalColor}" />
                    <use href="#runicBorderPath" fill="none" stroke="${spinnerEngravingColor}" stroke-width="1" />
                    
                    <g clip-path="url(#clipRunic)">
                        ${[...Array(12)].map((_, i) => {
                            const angle = i * 30; 
                            const rOuter = 46;
                            const rInner = 42;
                            const x1 = 50 + rOuter * Math.cos(angle * Math.PI / 180);
                            const y1 = 50 + rOuter * Math.sin(angle * Math.PI / 180);
                            const x2 = 50 + rInner * Math.cos((angle + 5) * Math.PI / 180); 
                            const y2 = 50 + rInner * Math.sin((angle + 5) * Math.PI / 180);
                            const x3 = 50 + rInner * Math.cos((angle - 5) * Math.PI / 180);
                            const y3 = 50 + rInner * Math.sin((angle - 5) * Math.PI / 180);
                            return `<polygon points="${x1},${y1} ${x2},${y2} ${x3},${y3}" fill="${spinnerEngravingColor}99" />`;
                        }).join('')}
                    </g>
                    <circle cx="50" cy="50" r="49" fill="${compassBezelColor}" stroke="#00000033" stroke-width="0.5" /> {/* Outer Bezel */}
                    <circle cx="50" cy="50" r="47" fill="none" stroke="${compassMarkingColor}" stroke-width="1.5" /> {/* Inner Bezel Line */}
                    <circle cx="50" cy="50" r="46" fill="none" stroke="${compassBezelColor}" stroke-width="2" stroke-dasharray="4 2" /> {/* Dashed Detail */}
                    <circle cx="50" cy="50" r="44" fill="url(#${compassFaceGradId})" stroke="${compassMarkingColor}" stroke-width="0.5" /> {/* Compass Face */}
                    <g stroke="${compassMarkingColor}" stroke-width="1.5" fill="${compassMarkingColor}"> {/* Compass Markings */}
                        <polygon points="50,8 47,15 53,15" /> 
                        <text x="50" y="6.5" text-anchor="middle" font-size="4" fill="${compassMarkingColor}" font-weight="bold" font-family="${legibleFontFamily}">N</text>
                        <polygon points="92,50 85,47 85,53" /> 
                        <text x="95" y="51.5" text-anchor="middle" font-size="4" fill="${compassMarkingColor}" font-weight="bold" font-family="${legibleFontFamily}">E</text>
                        <polygon points="50,92 47,85 53,85" /> 
                        <text x="50" y="97" text-anchor="middle" font-size="4" fill="${compassMarkingColor}" font-weight="bold" font-family="${legibleFontFamily}">S</text>
                        <polygon points="8,50 15,47 15,53" /> 
                        <text x="4.5" y="51.5" text-anchor="middle" font-size="4" fill="${compassMarkingColor}" font-weight="bold" font-family="${legibleFontFamily}">W</text>
                        ${[45, 135, 225, 315].map(angle => `
                            <line x1="50" y1="50" 
                                  x2="${50 + 38 * Math.cos(angle * Math.PI / 180)}" 
                                  y2="${50 + 38 * Math.sin(angle * Math.PI / 180)}" 
                                  stroke-width="1" />
                            <circle cx="${50 + 41 * Math.cos(angle * Math.PI / 180)}" 
                                    cy="${50 + 41 * Math.sin(angle * Math.PI / 180)}" 
                                    r="1" fill="${compassMarkingColor}" />
                        `).join('')}
                         ${[...Array(12)].map((_, i) => {
                            const angle = i * 30;
                            if (angle % 90 !== 0) { 
                                return `<line x1="${50 + 40 * Math.cos(angle * Math.PI/180)}" 
                                              y1="${50 + 40 * Math.sin(angle * Math.PI/180)}" 
                                              x2="${50 + 43 * Math.cos(angle * Math.PI/180)}" 
                                              y2="${50 + 43 * Math.sin(angle * Math.PI/180)}" 
                                              stroke-width="0.75" />`;
                            } return '';
                        }).join('')}
                    </g>
                    
                    <circle cx="50" cy="50" r="28" fill="${gemSettingColor}" filter="url(#dropshadow)" /> {/* Gem Setting */}
                    <circle cx="50" cy="50" r="26" fill="none" stroke="${compassNeedleHighlight}" stroke-width="1" /> {/* Gem Setting Highlight */}
                    
                    <circle cx="50" cy="50" r="25" fill="url(#${uniqueGradId})" stroke="${playerGemColor}" stroke-width="0.5"/> {/* Central Gem */}
                    
                    <text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle"
                          font-size="${fontSize}" fill="${numberColor}" font-weight="bold"
                          font-family="${legibleFontFamily}"
                          stroke="${numberOutlineColor}" stroke-width="0.8" paint-order="stroke"
                          style="text-shadow: 0.5px 0.5px 1.5px ${numberOutlineColor}cc; user-select: none;">
                        ${number}
                    </text>
                </svg>
            `;
            dieVisualElement.innerHTML = svgString;
        }
        /**
         * Starts the visual effect of a die rolling (rapidly changing faces).
         */
        function startRollingEffect(dieVisualElement, intervalHolder, maxDieValue, playerColor) {
            if (intervalHolder.id) clearInterval(intervalHolder.id);
            intervalHolder.id = setInterval(() => {
                const randomFace = Math.floor(Math.random() * maxDieValue) + 1;
                drawFantasySpinner(dieVisualElement, randomFace, maxDieValue, playerColor);
            }, faceChangeInterval);
        }
        /**
         * Stops the visual rolling effect and displays the final number on a die.
         */
        function stopRollingEffect(dieVisualElement, intervalHolder, finalNumber, dieType, playerColor) {
            clearInterval(intervalHolder.id);
            intervalHolder.id = null;
            drawFantasySpinner(dieVisualElement, finalNumber, dieType, playerColor);
        }
        /**
         * Handles the dice roll event for the battle.
         */
        function handleRoll() {
            if (isRolling) return;
            isRolling = true;
            rollButton.disabled = true;
            rollButton.textContent = "Rolling...";
            die1VisualElement.classList.add('rolling');
            die2VisualElement.classList.add('rolling');
            startRollingEffect(die1VisualElement, rollingEffectInterval1, player1SelectedDieMax, shapeColorPlayer1);
            startRollingEffect(die2VisualElement, rollingEffectInterval2, player2SelectedDieMax, shapeColorPlayer2);
            setTimeout(() => {
                const finalResult1 = Math.floor(Math.random() * player1SelectedDieMax) + 1;
                const finalResult2 = Math.floor(Math.random() * player2SelectedDieMax) + 1;
                
                lastRoll1 = finalResult1;
                lastRoll2 = finalResult2;
                stopRollingEffect(die1VisualElement, rollingEffectInterval1, finalResult1, player1SelectedDieMax, shapeColorPlayer1);
                stopRollingEffect(die2VisualElement, rollingEffectInterval2, finalResult2, player2SelectedDieMax, shapeColorPlayer2);
                
                die1VisualElement.classList.remove('rolling');
                die2VisualElement.classList.remove('rolling');
                isRolling = false;
                rollButton.disabled = false;
                rollButton.textContent = "Roll for Battle!";
            }, animationDuration);
        }
        rollButton.addEventListener('click', handleRoll);
        // Initial setup
        document.addEventListener('DOMContentLoaded', () => {
            setupDieSelection(player1DieOptionsContainer, (val) => {
                player1SelectedDieMax = val;
                drawFantasySpinner(die1VisualElement, lastRoll1, player1SelectedDieMax, shapeColorPlayer1);
            }, player1SelectedDieMax, 1);
            setupDieSelection(player2DieOptionsContainer, (val) => {
                player2SelectedDieMax = val;
                drawFantasySpinner(die2VisualElement, lastRoll2, player2SelectedDieMax, shapeColorPlayer2);
            }, player2SelectedDieMax, 2);
            drawFantasySpinner(die1VisualElement, lastRoll1, player1SelectedDieMax, shapeColorPlayer1);
            drawFantasySpinner(die2VisualElement, lastRoll2, player2SelectedDieMax, shapeColorPlayer2);
            rollButton.textContent = "Roll for Battle!";
        });
    </script>
</body>
</html>
<!-- /wp:html -->
Xyndoria – Dice Battle

Dice Roller

Attacker

{/* SVG spinner will be injected here by JS */}

Defender

{/* SVG spinner will be injected here by JS */}

2-Player Timer

Player 1

10:00

Player 2

10:00

3-Player Timer

Player 1

10:00

Player 2

10:00

Player 3

10:00

4-Player Timer

Player 1

10:00

Player 2

10:00

Player 3

10:00

Player 4

10:00

Scroll to Top