Spaces:
Running
Running
Add 1 files
Browse files- index.html +211 -20
index.html
CHANGED
|
@@ -259,6 +259,7 @@
|
|
| 259 |
let diceObjects = [];
|
| 260 |
let diceMeshes = [];
|
| 261 |
let diceValues = {};
|
|
|
|
| 262 |
|
| 263 |
// Initialize Three.js and Cannon.js
|
| 264 |
function init() {
|
|
@@ -273,6 +274,9 @@
|
|
| 273 |
// Add directional light
|
| 274 |
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
|
| 275 |
directionalLight.position.set(1, 1, 1).normalize();
|
|
|
|
|
|
|
|
|
|
| 276 |
scene.add(directionalLight);
|
| 277 |
|
| 278 |
// Add point light
|
|
@@ -323,10 +327,37 @@
|
|
| 323 |
// Handle window resize
|
| 324 |
window.addEventListener('resize', onWindowResize);
|
| 325 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 326 |
// Start animation loop
|
| 327 |
animate();
|
| 328 |
}
|
| 329 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 330 |
// Add decorative elements to the scene
|
| 331 |
function addDecorativeElements() {
|
| 332 |
// Add some floating runes
|
|
@@ -346,25 +377,6 @@
|
|
| 346 |
);
|
| 347 |
scene.add(rune);
|
| 348 |
}
|
| 349 |
-
|
| 350 |
-
// Add some floating particles
|
| 351 |
-
const particlesGeometry = new THREE.BufferGeometry();
|
| 352 |
-
const particlesCount = 100;
|
| 353 |
-
const posArray = new Float32Array(particlesCount * 3);
|
| 354 |
-
|
| 355 |
-
for (let i = 0; i < particlesCount * 3; i++) {
|
| 356 |
-
posArray[i] = (Math.random() - 0.5) * 20;
|
| 357 |
-
}
|
| 358 |
-
|
| 359 |
-
particlesGeometry.setAttribute('position', new THREE.BufferAttribute(posArray, 3));
|
| 360 |
-
const particlesMaterial = new THREE.PointsMaterial({
|
| 361 |
-
color: 0x8b5a2b,
|
| 362 |
-
size: 0.05,
|
| 363 |
-
transparent: true,
|
| 364 |
-
opacity: 0.5
|
| 365 |
-
});
|
| 366 |
-
const particlesMesh = new THREE.Points(particlesGeometry, particlesMaterial);
|
| 367 |
-
scene.add(particlesMesh);
|
| 368 |
}
|
| 369 |
|
| 370 |
// Handle window resize
|
|
@@ -501,5 +513,184 @@
|
|
| 501 |
case 8:
|
| 502 |
color = 0x005b96; // Blue
|
| 503 |
break;
|
| 504 |
-
case
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 505 |
</html>
|
|
|
|
| 259 |
let diceObjects = [];
|
| 260 |
let diceMeshes = [];
|
| 261 |
let diceValues = {};
|
| 262 |
+
let isRolling = false;
|
| 263 |
|
| 264 |
// Initialize Three.js and Cannon.js
|
| 265 |
function init() {
|
|
|
|
| 274 |
// Add directional light
|
| 275 |
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
|
| 276 |
directionalLight.position.set(1, 1, 1).normalize();
|
| 277 |
+
directionalLight.castShadow = true;
|
| 278 |
+
directionalLight.shadow.mapSize.width = 1024;
|
| 279 |
+
directionalLight.shadow.mapSize.height = 1024;
|
| 280 |
scene.add(directionalLight);
|
| 281 |
|
| 282 |
// Add point light
|
|
|
|
| 327 |
// Handle window resize
|
| 328 |
window.addEventListener('resize', onWindowResize);
|
| 329 |
|
| 330 |
+
// Set up dice selection
|
| 331 |
+
setupDiceSelection();
|
| 332 |
+
|
| 333 |
+
// Set up roll button
|
| 334 |
+
document.getElementById('rollButton').addEventListener('click', rollDice);
|
| 335 |
+
|
| 336 |
// Start animation loop
|
| 337 |
animate();
|
| 338 |
}
|
| 339 |
|
| 340 |
+
// Set up dice selection
|
| 341 |
+
function setupDiceSelection() {
|
| 342 |
+
const diceSelectors = document.querySelectorAll('.dice-selector');
|
| 343 |
+
|
| 344 |
+
diceSelectors.forEach(selector => {
|
| 345 |
+
selector.addEventListener('click', function() {
|
| 346 |
+
// Remove active class from all selectors
|
| 347 |
+
diceSelectors.forEach(s => s.classList.remove('active'));
|
| 348 |
+
|
| 349 |
+
// Add active class to clicked selector
|
| 350 |
+
this.classList.add('active');
|
| 351 |
+
|
| 352 |
+
// Update selected sides
|
| 353 |
+
selectedSides = parseInt(this.getAttribute('data-sides'));
|
| 354 |
+
});
|
| 355 |
+
});
|
| 356 |
+
|
| 357 |
+
// Activate D20 by default
|
| 358 |
+
document.querySelector('.dice-selector[data-sides="20"]').classList.add('active');
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
// Add decorative elements to the scene
|
| 362 |
function addDecorativeElements() {
|
| 363 |
// Add some floating runes
|
|
|
|
| 377 |
);
|
| 378 |
scene.add(rune);
|
| 379 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 380 |
}
|
| 381 |
|
| 382 |
// Handle window resize
|
|
|
|
| 513 |
case 8:
|
| 514 |
color = 0x005b96; // Blue
|
| 515 |
break;
|
| 516 |
+
case 10:
|
| 517 |
+
color = 0x5e8c31; // Green
|
| 518 |
+
break;
|
| 519 |
+
case 12:
|
| 520 |
+
color = 0x7d26cd; // Purple
|
| 521 |
+
break;
|
| 522 |
+
case 20:
|
| 523 |
+
color = 0xd4af37; // Gold
|
| 524 |
+
break;
|
| 525 |
+
default:
|
| 526 |
+
color = 0xffffff; // White
|
| 527 |
+
}
|
| 528 |
+
|
| 529 |
+
return new THREE.MeshStandardMaterial({
|
| 530 |
+
color: color,
|
| 531 |
+
roughness: 0.3,
|
| 532 |
+
metalness: 0.5,
|
| 533 |
+
emissive: color,
|
| 534 |
+
emissiveIntensity: 0.1
|
| 535 |
+
});
|
| 536 |
+
}
|
| 537 |
+
|
| 538 |
+
// Roll the dice
|
| 539 |
+
function rollDice() {
|
| 540 |
+
if (isRolling) return;
|
| 541 |
+
|
| 542 |
+
isRolling = true;
|
| 543 |
+
|
| 544 |
+
// Clear previous dice
|
| 545 |
+
clearDice();
|
| 546 |
+
|
| 547 |
+
// Get quantity
|
| 548 |
+
const quantity = parseInt(document.getElementById('diceQuantity').value) || 1;
|
| 549 |
+
const modifier = parseInt(document.getElementById('diceModifier').value) || 0;
|
| 550 |
+
|
| 551 |
+
// Hide result display
|
| 552 |
+
document.getElementById('resultDisplay').classList.add('hidden');
|
| 553 |
+
document.getElementById('criticalText').classList.add('hidden');
|
| 554 |
+
|
| 555 |
+
// Create new dice
|
| 556 |
+
for (let i = 0; i < quantity; i++) {
|
| 557 |
+
// Position the dice in a line above the ground
|
| 558 |
+
const x = (i - (quantity - 1) / 2) * 2;
|
| 559 |
+
const position = new CANNON.Vec3(x, 5, 0);
|
| 560 |
+
|
| 561 |
+
// Create physics body
|
| 562 |
+
const body = createDiceBody(selectedSides, position);
|
| 563 |
+
|
| 564 |
+
// Add some random force to make it roll
|
| 565 |
+
body.velocity.set(
|
| 566 |
+
Math.random() * 5 - 2.5,
|
| 567 |
+
Math.random() * 2,
|
| 568 |
+
Math.random() * 5 - 2.5
|
| 569 |
+
);
|
| 570 |
+
|
| 571 |
+
body.angularVelocity.set(
|
| 572 |
+
Math.random() * 5,
|
| 573 |
+
Math.random() * 5,
|
| 574 |
+
Math.random() * 5
|
| 575 |
+
);
|
| 576 |
+
|
| 577 |
+
world.addBody(body);
|
| 578 |
+
diceObjects.push(body);
|
| 579 |
+
|
| 580 |
+
// Create visual mesh
|
| 581 |
+
const geometry = createDiceGeometry(selectedSides);
|
| 582 |
+
const material = createDiceMaterial(selectedSides);
|
| 583 |
+
const mesh = new THREE.Mesh(geometry, material);
|
| 584 |
+
mesh.castShadow = true;
|
| 585 |
+
mesh.receiveShadow = true;
|
| 586 |
+
scene.add(mesh);
|
| 587 |
+
diceMeshes.push(mesh);
|
| 588 |
+
}
|
| 589 |
+
|
| 590 |
+
// Wait for dice to settle
|
| 591 |
+
setTimeout(() => {
|
| 592 |
+
checkDiceResults(quantity, modifier);
|
| 593 |
+
}, 2000);
|
| 594 |
+
}
|
| 595 |
+
|
| 596 |
+
// Clear all dice from scene
|
| 597 |
+
function clearDice() {
|
| 598 |
+
// Remove physics bodies
|
| 599 |
+
diceObjects.forEach(body => {
|
| 600 |
+
world.removeBody(body);
|
| 601 |
+
});
|
| 602 |
+
|
| 603 |
+
// Remove meshes
|
| 604 |
+
diceMeshes.forEach(mesh => {
|
| 605 |
+
scene.remove(mesh);
|
| 606 |
+
if (mesh.geometry) mesh.geometry.dispose();
|
| 607 |
+
if (mesh.material) mesh.material.dispose();
|
| 608 |
+
});
|
| 609 |
+
|
| 610 |
+
diceObjects = [];
|
| 611 |
+
diceMeshes = [];
|
| 612 |
+
diceValues = {};
|
| 613 |
+
}
|
| 614 |
+
|
| 615 |
+
// Check dice results after they've settled
|
| 616 |
+
function checkDiceResults(quantity, modifier) {
|
| 617 |
+
const results = [];
|
| 618 |
+
let total = 0;
|
| 619 |
+
let isCritical = false;
|
| 620 |
+
|
| 621 |
+
// Generate random results (since we can't actually detect dice faces in this simplified version)
|
| 622 |
+
for (let i = 0; i < quantity; i++) {
|
| 623 |
+
const value = Math.floor(Math.random() * selectedSides) + 1;
|
| 624 |
+
results.push(value);
|
| 625 |
+
total += value;
|
| 626 |
+
|
| 627 |
+
// Check for critical (20 on d20)
|
| 628 |
+
if (selectedSides === 20 && value === 20) {
|
| 629 |
+
isCritical = true;
|
| 630 |
+
}
|
| 631 |
+
}
|
| 632 |
+
|
| 633 |
+
// Add modifier
|
| 634 |
+
total += modifier;
|
| 635 |
+
|
| 636 |
+
// Display results
|
| 637 |
+
displayResults(results, total, modifier, isCritical);
|
| 638 |
+
|
| 639 |
+
// Add to history
|
| 640 |
+
addToHistory(results, total, modifier);
|
| 641 |
+
|
| 642 |
+
isRolling = false;
|
| 643 |
+
}
|
| 644 |
+
|
| 645 |
+
// Display the results
|
| 646 |
+
function displayResults(results, total, modifier, isCritical) {
|
| 647 |
+
const resultDisplay = document.getElementById('resultDisplay');
|
| 648 |
+
const totalResult = document.getElementById('totalResult');
|
| 649 |
+
const individualResults = document.getElementById('individualResults');
|
| 650 |
+
const criticalText = document.getElementById('criticalText');
|
| 651 |
+
|
| 652 |
+
// Show total
|
| 653 |
+
totalResult.textContent = total;
|
| 654 |
+
|
| 655 |
+
// Show individual results
|
| 656 |
+
let individualText = `Rolls: ${results.join(', ')}`;
|
| 657 |
+
if (modifier !== 0) {
|
| 658 |
+
individualText += ` + ${modifier}`;
|
| 659 |
+
}
|
| 660 |
+
individualResults.textContent = individualText;
|
| 661 |
+
|
| 662 |
+
// Show critical if applicable
|
| 663 |
+
if (isCritical) {
|
| 664 |
+
criticalText.classList.remove('hidden');
|
| 665 |
+
}
|
| 666 |
+
|
| 667 |
+
// Show the display
|
| 668 |
+
resultDisplay.classList.remove('hidden');
|
| 669 |
+
}
|
| 670 |
+
|
| 671 |
+
// Add roll to history
|
| 672 |
+
function addToHistory(results, total, modifier) {
|
| 673 |
+
const historyContainer = document.getElementById('rollHistory');
|
| 674 |
+
const historyItem = document.createElement('div');
|
| 675 |
+
historyItem.className = 'roll-history-item p-3 bg-gray-800 rounded';
|
| 676 |
+
|
| 677 |
+
let historyText = `D${selectedSides}: ${results.join(' + ')}`;
|
| 678 |
+
if (modifier !== 0) {
|
| 679 |
+
historyText += ` + ${modifier}`;
|
| 680 |
+
}
|
| 681 |
+
historyText += ` = ${total}`;
|
| 682 |
+
|
| 683 |
+
historyItem.textContent = historyText;
|
| 684 |
+
historyContainer.insertBefore(historyItem, historyContainer.firstChild);
|
| 685 |
+
|
| 686 |
+
// Limit history to 10 items
|
| 687 |
+
if (historyContainer.children.length > 10) {
|
| 688 |
+
historyContainer.removeChild(historyContainer.lastChild);
|
| 689 |
+
}
|
| 690 |
+
}
|
| 691 |
+
|
| 692 |
+
// Initialize when DOM is loaded
|
| 693 |
+
document.addEventListener('DOMContentLoaded', init);
|
| 694 |
+
</script>
|
| 695 |
+
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=dricampbell/d-d-dice" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
|
| 696 |
</html>
|