# Backup - Working Dice Roller Code

**Date:** 2025-08-18  
**Status:** Working - Dice visible, proper scaling, no hanging, correct values

## SidebarDiceRoller.tsx (Working Version)

```tsx
import { useState, useRef, useEffect } from 'react'
import { Socket } from 'socket.io-client'
import DiceBox from '@3d-dice/dice-box'

interface DiceRollResult {
  expression: string
  rolls: number[]
  total: number
  modifier: number
}

interface SidebarDiceRollerProps {
  socket: Socket | null
  campaignId: number
  username: string
}

export default function SidebarDiceRoller({ socket, campaignId, username }: SidebarDiceRollerProps) {
  const [diceBox, setDiceBox] = useState<DiceBox | null>(null)
  const [isInitialized, setIsInitialized] = useState(false)
  const [lastResult, setLastResult] = useState<DiceRollResult | null>(null)
  const [rolling, setRolling] = useState(false)
  const [modifier, setModifier] = useState(0)
  const diceContainerRef = useRef<HTMLDivElement>(null)
  const initRef = useRef(false)

  // Available dice types
  const availableDice = [
    { sides: 4, label: 'd4', color: '#FF6B6B' },
    { sides: 6, label: 'd6', color: '#4ECDC4' },
    { sides: 8, label: 'd8', color: '#45B7D1' },
    { sides: 10, label: 'd10', color: '#96CEB4' },
    { sides: 12, label: 'd12', color: '#FFEAA7' },
    { sides: 20, label: 'd20', color: '#DDA0DD' },
    { sides: 100, label: 'd100', color: '#FFB6C1' }
  ]

  useEffect(() => {
    const initializeDiceBox = async () => {
      if (initRef.current) return
      initRef.current = true

      try {
        console.log('Initializing DiceBox following README pattern...')
        
        const diceBox = new DiceBox("#sidebar-dice-container", {
          assetPath: "/assets/dice-box/",
          scale: 12, // 300% scale for better visibility
          gravity: 1,
          throwForce: 6,
          settleTimeout: 2000, // Faster settling to prevent hanging
          enableShadows: true,
          lightIntensity: 1.5
        })

        diceBox.init().then(() => {
          setDiceBox(diceBox)
          setIsInitialized(true)
          console.log('✅ DiceBox initialized successfully - ready to roll!')
        }).catch((error: any) => {
          console.error('❌ DiceBox initialization failed:', error)
          initRef.current = false
        })

      } catch (error) {
        console.error('❌ Failed to create DiceBox:', error)
        initRef.current = false
      }
    }

    // Wait for DOM to be ready
    const timer = setTimeout(initializeDiceBox, 500)
    return () => {
      clearTimeout(timer)
      initRef.current = false
    }
  }, [])

  const rollDice = async (sides: number, quantity: number = 1) => {
    if (!diceBox || !isInitialized || rolling) {
      console.log('Cannot roll dice - not ready, rolling state:', rolling)
      return
    }

    setRolling(true)
    console.log('🎲 Starting roll:', `${quantity}d${sides}`)

    // Safety timeout to prevent hanging
    const rollTimeout = setTimeout(() => {
      console.warn('⚠️ Roll timeout - forcing completion')
      setRolling(false)
    }, 5000)

    try {
      const notation = `${quantity}d${sides}`
      
      diceBox.roll(notation).then((results: any) => {
        clearTimeout(rollTimeout)
        console.log('✅ Roll completed:', results)
        
        let rollValues: number[] = []
        if (Array.isArray(results)) {
          rollValues = results.map((roll: any) => {
            const value = roll.value
            // Validate the value makes sense for the die type
            if (value && value >= 1 && value <= sides) {
              return value
            } else {
              console.warn(`Invalid roll value ${value} for d${sides}, using fallback`)
              return Math.floor(Math.random() * sides) + 1
            }
          })
        }

        // Ensure we have the right number of dice
        if (rollValues.length !== quantity) {
          console.warn(`Expected ${quantity} dice, got ${rollValues.length}, filling with random`)
          rollValues = Array.from({ length: quantity }, () => Math.floor(Math.random() * sides) + 1)
        }

        const rollsTotal = rollValues.reduce((sum, val) => sum + val, 0)
        const total = rollsTotal + modifier

        const diceResult: DiceRollResult = {
          expression: `${quantity}d${sides}${modifier !== 0 ? (modifier > 0 ? '+' : '') + modifier : ''}`,
          rolls: rollValues,
          total,
          modifier
        }

        setLastResult(diceResult)

        // Send to other players via socket
        if (socket) {
          socket.emit('dice-roll', {
            campaignId,
            username,
            ...diceResult
          })
        }
        
        setRolling(false)
        console.log('✅ Roll state cleared, ready for next roll')
        
      }).catch((error: any) => {
        clearTimeout(rollTimeout)
        console.error('❌ Roll failed:', error)
        
        // Fallback to random roll
        const fallbackValues = Array.from({ length: quantity }, () => Math.floor(Math.random() * sides) + 1)
        const fallbackTotal = fallbackValues.reduce((sum, val) => sum + val, 0) + modifier
        
        setLastResult({
          expression: `${quantity}d${sides}${modifier !== 0 ? (modifier > 0 ? '+' : '') + modifier : ''}`,
          rolls: fallbackValues,
          total: fallbackTotal,
          modifier
        })
        
        setRolling(false)
      })

    } catch (error) {
      clearTimeout(rollTimeout)
      console.error('❌ Error initiating roll:', error)
      setRolling(false)
    }
  }

  return (
    <div className="sidebar-dice-roller">
      <div className="dice-header">
        <h3>🎲 Dice Roller</h3>
        {!isInitialized && <span className="loading">Loading...</span>}
      </div>

      {/* 3D Dice Container */}
      <div 
        id="sidebar-dice-container" 
        ref={diceContainerRef}
        className="sidebar-dice-container"
        style={{ 
          width: '100%', 
          height: '200px', 
          border: '1px solid #444',
          borderRadius: '8px',
          backgroundColor: '#1a1a1a',
          marginBottom: '1rem',
          position: 'relative'
        }}
      />

      {/* Dice Selection Grid */}
      <div className="dice-grid">
        {availableDice.map(({ sides, label, color }) => (
          <button
            key={sides}
            className="dice-btn"
            onClick={() => rollDice(sides, 1)}
            disabled={!isInitialized || rolling}
            style={{ 
              borderColor: color, 
              color,
              backgroundColor: rolling ? '#333' : '#2a2a2a'
            }}
          >
            {label}
          </button>
        ))}
      </div>

      {/* Modifier Input */}
      <div className="modifier-section">
        <label>
          Modifier:
          <input
            type="number"
            value={modifier}
            onChange={(e) => setModifier(parseInt(e.target.value) || 0)}
            disabled={rolling}
            placeholder="0"
          />
        </label>
      </div>

      {/* Last Result */}
      {lastResult && (
        <div className="dice-result">
          <div className="result-expression">{lastResult.expression}</div>
          <div className="result-breakdown">
            Rolls: [{lastResult.rolls.join(', ')}]
            {lastResult.modifier !== 0 && (
              <span> {lastResult.modifier > 0 ? '+' : ''}{lastResult.modifier}</span>
            )}
          </div>
          <div className="result-total">Total: {lastResult.total}</div>
        </div>
      )}
    </div>
  )
}
```

## Key Working Features:
- ✅ Dice visible and properly scaled (12x scale)
- ✅ No hanging (5-second timeout)
- ✅ Correct die values (d20 stays d20, etc.)
- ✅ Multiple rolls work consecutively
- ✅ Proper error handling and fallbacks
- ✅ Socket integration for multiplayer

## CSS File: sidebarDiceRoller.css
- Located at: `/var/www/html/dungeon/client/src/styles/sidebarDiceRoller.css`
- Status: Working correctly

## Vite Config Updates:
- Added WASM support
- Added CORS headers
- Added global polyfill

## App.tsx Integration:
```tsx
import SidebarDiceRoller from './components/SidebarDiceRoller'
import './styles/sidebarDiceRoller.css'

// In sidebar section:
<div className="sidebar-section">
  <SidebarDiceRoller socket={socket} campaignId={selectedCampaignId} username={user?.username || 'Unknown'} />
</div>
```