Create a premium, cinematic “Double Spin Loot Box Module” for an online sweepstakes casino platform called Nioplay. This should be a single, complete hero-style UI scene rendered in a WIDESCREEN 16:9 ASPECT RATIO. The image should not look like a webpage screenshot — instead, it should look like a high-end product UI render designed for presentation and implementation.
Browse filesThis module contains TWO stacked RNG systems:
1) A primary horizontal loot box spin roller (Stake.com style).
2) A secondary horizontal multiplier slider styled as a sleek, glowing meter.
A final REWARD POP-UP must appear once both spins finish.
-----
### OVERALL VISUAL STYLE:
- Theme: Premium sweepstakes gaming mixed with cinematic neon energy.
- Color palette: Deep black and charcoal base, neon orange (#FF8C00) accents, warm gold (#FFCC66 and #FFD700) for highlights.
- Lighting: Subtle volumetric glow behind the tracks, amber light beams, light mist particles, and faint sparks around active elements.
- UI theme: Modern, glassmorphism, futuristic but still clean. No cartoon style. Realistic rendering with premium digital surfaces.
- Depth: Soft shadows, floating elements, layered UI panels, blurred backgrounds.
Background must be:
- A deep black-to-warm radial gradient.
- Soft glowing embers and floating particles.
- No patterns, no clutter.
-----
### 1. HEADER TITLE SECTION:
Place this at the top center or slightly left-aligned within the module.
- Title: “MYSTERY LOOT BOX ROLL”
- All caps, bold, gold-to-warm white gradient fill.
- Soft glow and subtle extruded shadow.
- Subtitle under it:
“Spin across the mystery boxes, unlock a random reward, then boost it with a multiplier roll.”
- Smaller, clean sans-serif, dim warm-grey color.
- To the right: a glassmorphic badge reading:
“Today’s Legendary Chance: +3%”
- Rounded-pill shape, translucent black, thin neon orange rim, soft internal glow.
-----
### 2. PRIMARY LOOT BOX CAROUSEL (TOP SPIN):
This is the main attraction section.
**Structure:**
- A long horizontal track (glassmorphic panel) that extends across most of the 16:9 width.
- The track should feel like a glossy, futuristic shelf or digital rail.
- Slight inner glow and reflective surface.
**Loot Boxes:**
- Display 10–14 boxes shown horizontally.
- Spaced evenly.
- Each box should be floating slightly above the track.
- Box style: metallic + glass hybrid design, with lit seams and embossed SC coin symbol.
- Rarity glows:
- Common: green halo glow
- Rare: cool blue glow
- Epic: purple glow
- Legendary: intense gold/orange glow, brighter outline
- Beneath each box, small rarity labels (e.g., “EPIC”) in tiny uppercase text.
**Selection Window:**
- A vertical glowing frame at the exact center of the track.
- Rounded rectangle, transparent inside, thin neon-orange border.
- Purpose: the selected box must land perfectly centered within this frame.
**Motion Indicators:**
- Slight motion blur on boxes not centered.
- Light streaks or trailing ghosts implying the boxes can slide quickly.
- One box should appear “final selected”: slightly larger, glowing brighter, centered in the selection window, and partially opening with a cinematic burst of light and floating SC coins.
-----
### 3. PRIMARY CTA (BUTTON) + STATUS:
Centered below the loot box track.
- Big button labeled “ROLL”
- Wide, rounded pill.
- Golden-to-orange gradient.
- Strong outer glow.
- Inner highlight.
- Slight depth and shadow.
- Status text below or beside the button:
- Example: “Status: Rolling…” or “Selected: Legendary Loot Box”
- Clean, small, warm-grey text.
-----
### 4. SECONDARY MULTIPLIER SLIDER (METER-STYLE) – UNDERNEATH THE LOOT TRACK:
This is the second RNG component.
**Style:**
- Minimalistic.
- Sleek.
- Meter-like horizontal strip — NOT boxes or icons.
**Structure:**
- A long, thin horizontal track.
- Inside it, a row of glowing “multiplier pills” scrolling horizontally.
- Multipliers (repeat the sequence twice for realism):
- ×1
- ×1.25
- ×1.5
- ×2
- ×3
- ×5
Each multiplier pill:
- Soft pill shape, slightly rounded rectangle.
- Glassmorphism: translucent black with blur.
- Thin white or gold highlight.
- Multiplier text in bold warm-white/gold, glowing faintly.
- Slight reflection and soft shadow.
**Multiplier Selection Window:**
- A small glowing rectangular frame at the center of this track.
- Thin neon-orange border.
- This frame indicates which multiplier is “picked.”
**Motion Visualization:**
- Show horizontal scrolling implied through blur.
- Far left/right pills slightly stretched/blurred to mimic speed.
- The selected pill should be perfectly centered, slightly enlarged, glowing neon orange, and pulsing softly.
-----
### 5. FINAL REWARD POP-UP (MANDATORY):
Once both spins finish, a reward modal must appear in the scene — like a celebration pop-up.
**Pop-up Style:**
- Floating glassmorphism window.
- Centered on screen OR slightly above the CTA area.
- Thick neon-orange rim glow.
- Soft backdrop blur behind it.
**Pop-up Contents:**
- Title: “WIN REVEALED!”
- Bold, gold gradient, glowing.
- Subtext summarizing the combined result:
- “Base Reward: 30 SC”
- “Multiplier: ×2”
- “Final Payout: 60 SC”
- Arrange in a clean, stacked layout.
- The final payout (“60 SC”) should be larger, glowing neon gold/orange, with small floating SC coins around it.
- Optional: confetti particles (warm gold/amber), subtle trails, glowing sparks.
- Include a “Continue” button:
- Small pill, gold gradient, soft glow.
- Not overpowering; just functional.
**Visual Behavior:**
- The pop-up should appear as if it animated into place.
- Slight upward float, fade-in, and glow bloom shown in the render.
-----
### 6. OVERALL COMPOSITION & REQUIREMENTS:
- MUST be rendered in a **16:9 WIDESCREEN** format.
- The scene should appear as a complete UI module.
- Clear hierarchy:
- Loot box spin → Multiplier slider → Result pop-up.
- Use depth, glow, and cinematic design to make it feel like a premium sweepstakes feature inside Nioplay.
- No browser UI, no device frames.
- Image should feel like a polished concept deliverable ready for developers.
The final output should look like the fully designed, production-ready “Double Spin Loot Box Feature” for Nioplay, complete with the loot box spinner, multiplier slider, and reward pop-up all visible in the same 16:9 composition.
- README.md +8 -5
- components/loot-box.js +216 -0
- components/multiplier-track.js +158 -0
- components/reward-popup.js +203 -0
- index.html +81 -19
- script.js +48 -0
- style.css +68 -19
|
@@ -1,10 +1,13 @@
|
|
| 1 |
---
|
| 2 |
-
title: Nioplay Double Fortune Spin Vault
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
-
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: Nioplay Double Fortune Spin Vault 🔮🎰
|
| 3 |
+
colorFrom: blue
|
| 4 |
+
colorTo: yellow
|
| 5 |
+
emoji: 🐳
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
+
tags:
|
| 9 |
+
- deepsite-v3
|
| 10 |
---
|
| 11 |
|
| 12 |
+
# Welcome to your new DeepSite project!
|
| 13 |
+
This project was created with [DeepSite](https://huggingface.co/deepsite).
|
|
@@ -0,0 +1,216 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class LootBoxCarousel extends HTMLElement {
|
| 2 |
+
constructor() {
|
| 3 |
+
super();
|
| 4 |
+
this.boxes = [
|
| 5 |
+
{ rarity: 'common', value: 5, color: 'green' },
|
| 6 |
+
{ rarity: 'common', value: 5, color: 'green' },
|
| 7 |
+
{ rarity: 'common', value: 10, color: 'green' },
|
| 8 |
+
{ rarity: 'rare', value: 15, color: 'blue' },
|
| 9 |
+
{ rarity: 'rare', value: 20, color: 'blue' },
|
| 10 |
+
{ rarity: 'epic', value: 30, color: 'purple' },
|
| 11 |
+
{ rarity: 'legendary', value: 50, color: 'gold' },
|
| 12 |
+
{ rarity: 'epic', value: 25, color: 'purple' },
|
| 13 |
+
{ rarity: 'rare', value: 15, color: 'blue' },
|
| 14 |
+
{ rarity: 'common', value: 10, color: 'green' }
|
| 15 |
+
];
|
| 16 |
+
this.selectedIndex = 0;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
connectedCallback() {
|
| 20 |
+
this.attachShadow({ mode: 'open' });
|
| 21 |
+
this.render();
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
render() {
|
| 25 |
+
this.shadowRoot.innerHTML = `
|
| 26 |
+
<style>
|
| 27 |
+
:host {
|
| 28 |
+
display: block;
|
| 29 |
+
width: 100%;
|
| 30 |
+
position: relative;
|
| 31 |
+
height: 180px;
|
| 32 |
+
margin-bottom: 20px;
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
.track {
|
| 36 |
+
position: relative;
|
| 37 |
+
height: 100%;
|
| 38 |
+
background: rgba(20, 20, 20, 0.5);
|
| 39 |
+
border-radius: 8px;
|
| 40 |
+
border: 1px solid rgba(255, 140, 0, 0.2);
|
| 41 |
+
box-shadow: inset 0 0 15px rgba(0, 0, 0, 0.5);
|
| 42 |
+
overflow: hidden;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
.track::before {
|
| 46 |
+
content: '';
|
| 47 |
+
position: absolute;
|
| 48 |
+
inset: 0;
|
| 49 |
+
background: linear-gradient(90deg, rgba(255, 140, 0, 0.1) 0%, transparent 50%, rgba(255, 140, 0, 0.1) 100%);
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
.boxes-container {
|
| 53 |
+
position: absolute;
|
| 54 |
+
display: flex;
|
| 55 |
+
height: 100%;
|
| 56 |
+
align-items: center;
|
| 57 |
+
gap: 20px;
|
| 58 |
+
padding: 0 50%;
|
| 59 |
+
will-change: transform;
|
| 60 |
+
transition: transform 0.1s linear;
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
.loot-box {
|
| 64 |
+
width: 100px;
|
| 65 |
+
height: 100px;
|
| 66 |
+
border-radius: 8px;
|
| 67 |
+
display: flex;
|
| 68 |
+
flex-direction: column;
|
| 69 |
+
justify-content: center;
|
| 70 |
+
align-items: center;
|
| 71 |
+
position: relative;
|
| 72 |
+
transition: all 0.3s ease;
|
| 73 |
+
z-index: 5;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
.loot-box.common {
|
| 77 |
+
background: rgba(30, 30, 30, 0.8);
|
| 78 |
+
border: 2px solid var(--premium-green);
|
| 79 |
+
box-shadow: 0 0 15px var(--premium-green);
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
.loot-box.rare {
|
| 83 |
+
background: rgba(30, 30, 30, 0.8);
|
| 84 |
+
border: 2px solid var(--premium-blue);
|
| 85 |
+
box-shadow: 0 0 15px var(--premium-blue);
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
.loot-box.epic {
|
| 89 |
+
background: rgba(30, 30, 30, 0.8);
|
| 90 |
+
border: 2px solid var(--premium-purple);
|
| 91 |
+
box-shadow: 0 0 20px var(--premium-purple);
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
.loot-box.legendary {
|
| 95 |
+
background: rgba(30, 30, 30, 0.8);
|
| 96 |
+
border: 2px solid var(--premium-gold);
|
| 97 |
+
box-shadow: 0 0 25px var(--premium-gold);
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
.loot-box.selected {
|
| 101 |
+
transform: scale(1.2);
|
| 102 |
+
z-index: 10;
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
.loot-box.selected.common {
|
| 106 |
+
box-shadow: 0 0 25px var(--premium-green);
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
.loot-box.selected.rare {
|
| 110 |
+
box-shadow: 0 0 30px var(--premium-blue);
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
.loot-box.selected.epic {
|
| 114 |
+
box-shadow: 0 0 35px var(--premium-purple);
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
.loot-box.selected.legendary {
|
| 118 |
+
box-shadow: 0 0 40px var(--premium-gold);
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
.box-icon {
|
| 122 |
+
font-size: 24px;
|
| 123 |
+
margin-bottom: 5px;
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
.rarity {
|
| 127 |
+
font-size: 10px;
|
| 128 |
+
text-transform: uppercase;
|
| 129 |
+
font-weight: bold;
|
| 130 |
+
margin-top: 5px;
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
.selection-window {
|
| 134 |
+
position: absolute;
|
| 135 |
+
left: 50%;
|
| 136 |
+
transform: translateX(-50%);
|
| 137 |
+
height: 120px;
|
| 138 |
+
width: 120px;
|
| 139 |
+
border: 2px solid rgba(255, 140, 0, 0.8);
|
| 140 |
+
border-radius: 8px;
|
| 141 |
+
box-shadow: 0 0 20px rgba(255, 140, 0, 0.5);
|
| 142 |
+
z-index: 4;
|
| 143 |
+
pointer-events: none;
|
| 144 |
+
}
|
| 145 |
+
</style>
|
| 146 |
+
|
| 147 |
+
<div class="track">
|
| 148 |
+
<div class="selection-window"></div>
|
| 149 |
+
<div class="boxes-container">
|
| 150 |
+
${this.boxes.map((box, index) => `
|
| 151 |
+
<div class="loot-box ${box.rarity} ${index === this.selectedIndex ? 'selected' : ''}" data-index="${index}">
|
| 152 |
+
<i data-feather="box" class="box-icon"></i>
|
| 153 |
+
<span class="rarity">${box.rarity}</span>
|
| 154 |
+
</div>
|
| 155 |
+
`).join('')}
|
| 156 |
+
</div>
|
| 157 |
+
</div>
|
| 158 |
+
`;
|
| 159 |
+
|
| 160 |
+
// Initialize feather icons
|
| 161 |
+
feather.replace();
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
startSpin() {
|
| 165 |
+
const container = this.shadowRoot.querySelector('.boxes-container');
|
| 166 |
+
const boxes = this.shadowRoot.querySelectorAll('.loot-box');
|
| 167 |
+
|
| 168 |
+
// Reset selection
|
| 169 |
+
boxes.forEach(box => box.classList.remove('selected'));
|
| 170 |
+
|
| 171 |
+
// Animate spin
|
| 172 |
+
let currentPosition = 0;
|
| 173 |
+
let speed = 0;
|
| 174 |
+
const maxSpeed = 30;
|
| 175 |
+
const deceleration = 0.5;
|
| 176 |
+
const targetIndex = Math.floor(Math.random() * this.boxes.length);
|
| 177 |
+
|
| 178 |
+
const animate = () => {
|
| 179 |
+
currentPosition += speed;
|
| 180 |
+
speed = Math.max(0, speed - deceleration);
|
| 181 |
+
|
| 182 |
+
// Apply movement
|
| 183 |
+
container.style.transform = `translateX(${currentPosition}px)`;
|
| 184 |
+
|
| 185 |
+
// Highlight box in center
|
| 186 |
+
const centerPosition = -currentPosition - container.offsetWidth / 2 + this.offsetWidth / 2;
|
| 187 |
+
const boxWidth = 120; // box width + gap
|
| 188 |
+
|
| 189 |
+
const centerIndex = Math.round(centerPosition / boxWidth) % this.boxes.length;
|
| 190 |
+
const selectedIndex = (centerIndex + this.boxes.length) % this.boxes.length;
|
| 191 |
+
|
| 192 |
+
boxes.forEach((box, i) => {
|
| 193 |
+
box.classList.toggle('selected', i === selectedIndex);
|
| 194 |
+
});
|
| 195 |
+
|
| 196 |
+
// Continue animation until stopped
|
| 197 |
+
if (speed > 0) {
|
| 198 |
+
requestAnimationFrame(animate);
|
| 199 |
+
} else {
|
| 200 |
+
// Final selection
|
| 201 |
+
this.selectedIndex = targetIndex;
|
| 202 |
+
this.render();
|
| 203 |
+
}
|
| 204 |
+
};
|
| 205 |
+
|
| 206 |
+
// Initial acceleration
|
| 207 |
+
speed = maxSpeed;
|
| 208 |
+
animate();
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
getSelectedBox() {
|
| 212 |
+
return this.boxes[this.selectedIndex];
|
| 213 |
+
}
|
| 214 |
+
}
|
| 215 |
+
|
| 216 |
+
customElements.define('loot-box-carousel', LootBoxCarousel);
|
|
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class MultiplierTrack extends HTMLElement {
|
| 2 |
+
constructor() {
|
| 3 |
+
super();
|
| 4 |
+
this.multipliers = [
|
| 5 |
+
{ value: 1 },
|
| 6 |
+
{ value: 1.25 },
|
| 7 |
+
{ value: 1.5 },
|
| 8 |
+
{ value: 2 },
|
| 9 |
+
{ value: 3 },
|
| 10 |
+
{ value: 5 },
|
| 11 |
+
{ value: 1 },
|
| 12 |
+
{ value: 1.25 },
|
| 13 |
+
{ value: 1.5 },
|
| 14 |
+
{ value: 2 },
|
| 15 |
+
{ value: 3 },
|
| 16 |
+
{ value: 5 }
|
| 17 |
+
];
|
| 18 |
+
this.selectedIndex = 0;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
connectedCallback() {
|
| 22 |
+
this.attachShadow({ mode: 'open' });
|
| 23 |
+
this.render();
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
render() {
|
| 27 |
+
this.shadowRoot.innerHTML = `
|
| 28 |
+
<style>
|
| 29 |
+
:host {
|
| 30 |
+
display: block;
|
| 31 |
+
width: 100%;
|
| 32 |
+
position: relative;
|
| 33 |
+
height: 80px;
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
.track {
|
| 37 |
+
position: relative;
|
| 38 |
+
height: 60px;
|
| 39 |
+
background: rgba(20, 20, 20, 0.5);
|
| 40 |
+
border-radius: 30px;
|
| 41 |
+
border: 1px solid rgba(255, 140, 0, 0.2);
|
| 42 |
+
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.5);
|
| 43 |
+
overflow: hidden;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
.multipliers-container {
|
| 47 |
+
position: absolute;
|
| 48 |
+
display: flex;
|
| 49 |
+
height: 100%;
|
| 50 |
+
align-items: center;
|
| 51 |
+
gap: 15px;
|
| 52 |
+
padding: 0 50%;
|
| 53 |
+
will-change: transform;
|
| 54 |
+
transition: transform 0.1s linear;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
.multiplier {
|
| 58 |
+
min-width: 80px;
|
| 59 |
+
height: 40px;
|
| 60 |
+
border-radius: 20px;
|
| 61 |
+
display: flex;
|
| 62 |
+
justify-content: center;
|
| 63 |
+
align-items: center;
|
| 64 |
+
background: rgba(30, 30, 30, 0.8);
|
| 65 |
+
border: 1px solid rgba(255, 215, 0, 0.3);
|
| 66 |
+
color: rgba(255, 215, 0, 0.8);
|
| 67 |
+
font-weight: bold;
|
| 68 |
+
transition: all 0.3s ease;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
.multiplier.selected {
|
| 72 |
+
background: rgba(255, 140, 0, 0.3);
|
| 73 |
+
border: 1px solid rgba(255, 215, 0, 0.8);
|
| 74 |
+
color: white;
|
| 75 |
+
box-shadow: 0 0 15px rgba(255, 140, 0, 0.5);
|
| 76 |
+
transform: scale(1.1);
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
.selection-window {
|
| 80 |
+
position: absolute;
|
| 81 |
+
left: 50%;
|
| 82 |
+
transform: translateX(-50%);
|
| 83 |
+
height: 50px;
|
| 84 |
+
width: 90px;
|
| 85 |
+
border: 2px solid rgba(255, 140, 0, 0.8);
|
| 86 |
+
border-radius: 25px;
|
| 87 |
+
box-shadow: 0 0 15px rgba(255, 140, 0, 0.5);
|
| 88 |
+
z-index: 4;
|
| 89 |
+
pointer-events: none;
|
| 90 |
+
}
|
| 91 |
+
</style>
|
| 92 |
+
|
| 93 |
+
<div class="track">
|
| 94 |
+
<div class="selection-window"></div>
|
| 95 |
+
<div class="multipliers-container">
|
| 96 |
+
${this.multipliers.map((mult, index) => `
|
| 97 |
+
<div class="multiplier ${index === this.selectedIndex ? 'selected' : ''}" data-index="${index}">
|
| 98 |
+
×${mult.value}
|
| 99 |
+
</div>
|
| 100 |
+
`).join('')}
|
| 101 |
+
</div>
|
| 102 |
+
</div>
|
| 103 |
+
`;
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
startSpin() {
|
| 107 |
+
const container = this.shadowRoot.querySelector('.multipliers-container');
|
| 108 |
+
const multipliers = this.shadowRoot.querySelectorAll('.multiplier');
|
| 109 |
+
|
| 110 |
+
// Reset selection
|
| 111 |
+
multipliers.forEach(mult => mult.classList.remove('selected'));
|
| 112 |
+
|
| 113 |
+
// Animate spin
|
| 114 |
+
let currentPosition = 0;
|
| 115 |
+
let speed = 0;
|
| 116 |
+
const maxSpeed = 20;
|
| 117 |
+
const deceleration = 0.3;
|
| 118 |
+
const targetIndex = Math.floor(Math.random() * this.multipliers.length);
|
| 119 |
+
|
| 120 |
+
const animate = () => {
|
| 121 |
+
currentPosition += speed;
|
| 122 |
+
speed = Math.max(0, speed - deceleration);
|
| 123 |
+
|
| 124 |
+
// Apply movement
|
| 125 |
+
container.style.transform = `translateX(${currentPosition}px)`;
|
| 126 |
+
|
| 127 |
+
// Highlight multiplier in center
|
| 128 |
+
const centerPosition = -currentPosition - container.offsetWidth / 2 + this.offsetWidth / 2;
|
| 129 |
+
const multWidth = 95; // multiplier width + gap
|
| 130 |
+
|
| 131 |
+
const centerIndex = Math.round(centerPosition / multWidth) % this.multipliers.length;
|
| 132 |
+
const selectedIndex = (centerIndex + this.multipliers.length) % this.multipliers.length;
|
| 133 |
+
|
| 134 |
+
multipliers.forEach((mult, i) => {
|
| 135 |
+
mult.classList.toggle('selected', i === selectedIndex);
|
| 136 |
+
});
|
| 137 |
+
|
| 138 |
+
// Continue animation until stopped
|
| 139 |
+
if (speed > 0) {
|
| 140 |
+
requestAnimationFrame(animate);
|
| 141 |
+
} else {
|
| 142 |
+
// Final selection
|
| 143 |
+
this.selectedIndex = targetIndex;
|
| 144 |
+
this.render();
|
| 145 |
+
}
|
| 146 |
+
};
|
| 147 |
+
|
| 148 |
+
// Initial acceleration
|
| 149 |
+
speed = maxSpeed;
|
| 150 |
+
animate();
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
getSelectedMultiplier() {
|
| 154 |
+
return this.multipliers[this.selectedIndex];
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
customElements.define('multiplier-track', MultiplierTrack);
|
|
@@ -0,0 +1,203 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class RewardPopup extends HTMLElement {
|
| 2 |
+
constructor() {
|
| 3 |
+
super();
|
| 4 |
+
this.visible = false;
|
| 5 |
+
}
|
| 6 |
+
|
| 7 |
+
connectedCallback() {
|
| 8 |
+
this.attachShadow({ mode: 'open' });
|
| 9 |
+
this.render();
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
render() {
|
| 13 |
+
this.shadowRoot.innerHTML = `
|
| 14 |
+
<style>
|
| 15 |
+
:host {
|
| 16 |
+
display: ${this.visible ? 'block' : 'none'};
|
| 17 |
+
position: fixed;
|
| 18 |
+
top: 0;
|
| 19 |
+
left: 0;
|
| 20 |
+
width: 100%;
|
| 21 |
+
height: 100%;
|
| 22 |
+
background: rgba(0, 0, 0, 0.7);
|
| 23 |
+
backdrop-filter: blur(5px);
|
| 24 |
+
z-index: 100;
|
| 25 |
+
display: flex;
|
| 26 |
+
justify-content: center;
|
| 27 |
+
align-items: center;
|
| 28 |
+
opacity: ${this.visible ? 1 : 0};
|
| 29 |
+
transition: opacity 0.3s ease;
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
.popup {
|
| 33 |
+
background: rgba(20, 20, 20, 0.9);
|
| 34 |
+
border-radius: 16px;
|
| 35 |
+
border: 2px solid var(--premium-glow);
|
| 36 |
+
box-shadow: 0 0 30px rgba(255, 140, 0, 0.5);
|
| 37 |
+
width: 90%;
|
| 38 |
+
max-width: 500px;
|
| 39 |
+
padding: 30px;
|
| 40 |
+
text-align: center;
|
| 41 |
+
position: relative;
|
| 42 |
+
overflow: hidden;
|
| 43 |
+
animation: popIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
@keyframes popIn {
|
| 47 |
+
0% { transform: scale(0.8); opacity: 0; }
|
| 48 |
+
100% { transform: scale(1); opacity: 1; }
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
.popup::before {
|
| 52 |
+
content: '';
|
| 53 |
+
position: absolute;
|
| 54 |
+
top: -50%;
|
| 55 |
+
left: -50%;
|
| 56 |
+
width: 200%;
|
| 57 |
+
height: 200%;
|
| 58 |
+
background: radial-gradient(circle, rgba(255, 140, 0, 0.1) 0%, transparent 70%);
|
| 59 |
+
z-index: -1;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
.title {
|
| 63 |
+
font-size: 28px;
|
| 64 |
+
font-weight: bold;
|
| 65 |
+
margin-bottom: 20px;
|
| 66 |
+
background: linear-gradient(to right, var(--premium-gold), var(--premium-glow));
|
| 67 |
+
-webkit-background-clip: text;
|
| 68 |
+
background-clip: text;
|
| 69 |
+
color: transparent;
|
| 70 |
+
text-shadow: 0 0 10px rgba(255, 215, 0, 0.3);
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
.reward-details {
|
| 74 |
+
margin-bottom: 30px;
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
.reward-line {
|
| 78 |
+
display: flex;
|
| 79 |
+
justify-content: space-between;
|
| 80 |
+
margin-bottom: 10px;
|
| 81 |
+
font-size: 16px;
|
| 82 |
+
color: rgba(255, 255, 255, 0.8);
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
.final-reward {
|
| 86 |
+
font-size: 36px;
|
| 87 |
+
font-weight: bold;
|
| 88 |
+
margin: 20px 0;
|
| 89 |
+
color: var(--premium-gold);
|
| 90 |
+
text-shadow: 0 0 10px rgba(255, 215, 0, 0.5);
|
| 91 |
+
animation: pulse 2s infinite;
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
@keyframes pulse {
|
| 95 |
+
0% { transform: scale(1); }
|
| 96 |
+
50% { transform: scale(1.05); }
|
| 97 |
+
100% { transform: scale(1); }
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
.continue-btn {
|
| 101 |
+
padding: 12px 30px;
|
| 102 |
+
border-radius: 25px;
|
| 103 |
+
background: linear-gradient(to right, var(--premium-gold), var(--premium-glow));
|
| 104 |
+
color: var(--premium-dark);
|
| 105 |
+
font-weight: bold;
|
| 106 |
+
border: none;
|
| 107 |
+
cursor: pointer;
|
| 108 |
+
transition: transform 0.2s, box-shadow 0.2s;
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
.continue-btn:hover {
|
| 112 |
+
transform: translateY(-2px);
|
| 113 |
+
box-shadow: 0 5px 15px rgba(255, 140, 0, 0.4);
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
.confetti {
|
| 117 |
+
position: absolute;
|
| 118 |
+
width: 10px;
|
| 119 |
+
height: 10px;
|
| 120 |
+
background: var(--premium-gold);
|
| 121 |
+
opacity: 0;
|
| 122 |
+
}
|
| 123 |
+
</style>
|
| 124 |
+
|
| 125 |
+
<div class="popup">
|
| 126 |
+
<h2 class="title">WIN REVEALED!</h2>
|
| 127 |
+
|
| 128 |
+
<div class="reward-details">
|
| 129 |
+
<div class="reward-line">
|
| 130 |
+
<span>Base Reward:</span>
|
| 131 |
+
<span id="baseReward">0 SC</span>
|
| 132 |
+
</div>
|
| 133 |
+
<div class="reward-line">
|
| 134 |
+
<span>Multiplier:</span>
|
| 135 |
+
<span id="multiplier">×0</span>
|
| 136 |
+
</div>
|
| 137 |
+
</div>
|
| 138 |
+
|
| 139 |
+
<div class="final-reward" id="finalReward">0 SC</div>
|
| 140 |
+
|
| 141 |
+
<button class="continue-btn" id="continueBtn">Continue</button>
|
| 142 |
+
</div>
|
| 143 |
+
`;
|
| 144 |
+
|
| 145 |
+
// Add event listener for continue button
|
| 146 |
+
if (this.shadowRoot.getElementById('continueBtn')) {
|
| 147 |
+
this.shadowRoot.getElementById('continueBtn').addEventListener('click', () => this.hide());
|
| 148 |
+
}
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
show(data) {
|
| 152 |
+
this.visible = true;
|
| 153 |
+
this.render();
|
| 154 |
+
|
| 155 |
+
// Update reward details
|
| 156 |
+
if (data) {
|
| 157 |
+
this.shadowRoot.getElementById('baseReward').textContent = `${data.baseReward} SC`;
|
| 158 |
+
this.shadowRoot.getElementById('multiplier').textContent = `×${data.multiplier}`;
|
| 159 |
+
this.shadowRoot.getElementById('finalReward').textContent = `${data.finalReward} SC`;
|
| 160 |
+
|
| 161 |
+
// Add rarity class for additional styling
|
| 162 |
+
const finalRewardElement = this.shadowRoot.getElementById('finalReward');
|
| 163 |
+
finalRewardElement.className = 'final-reward ' + data.rarity;
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
// Create confetti effect
|
| 167 |
+
this.createConfetti();
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
hide() {
|
| 171 |
+
this.visible = false;
|
| 172 |
+
this.render();
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
createConfetti() {
|
| 176 |
+
const popup = this.shadowRoot.querySelector('.popup');
|
| 177 |
+
|
| 178 |
+
for (let i = 0; i < 50; i++) {
|
| 179 |
+
const confetti = document.createElement('div');
|
| 180 |
+
confetti.className = 'confetti';
|
| 181 |
+
confetti.style.left = Math.random() * 100 + '%';
|
| 182 |
+
confetti.style.top = -10 + 'px';
|
| 183 |
+
confetti.style.backgroundColor = i % 2 === 0 ? 'var(--premium-gold)' : 'var(--premium-glow)';
|
| 184 |
+
confetti.style.transform = `rotate(${Math.random() * 360}deg)`;
|
| 185 |
+
|
| 186 |
+
popup.appendChild(confetti);
|
| 187 |
+
|
| 188 |
+
// Animate confetti
|
| 189 |
+
const animation = confetti.animate([
|
| 190 |
+
{ top: -10 + 'px', opacity: 1, transform: `rotate(${Math.random() * 360}deg)` },
|
| 191 |
+
{ top: 100 + 'px', opacity: 0, transform: `rotate(${Math.random() * 360}deg)` }
|
| 192 |
+
], {
|
| 193 |
+
duration: 1000 + Math.random() * 2000,
|
| 194 |
+
delay: Math.random() * 1000,
|
| 195 |
+
easing: 'cubic-bezier(0.1, 0.8, 0.9, 1)'
|
| 196 |
+
});
|
| 197 |
+
|
| 198 |
+
animation.onfinish = () => confetti.remove();
|
| 199 |
+
}
|
| 200 |
+
}
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
customElements.define('reward-popup', RewardPopup);
|
|
@@ -1,19 +1,81 @@
|
|
| 1 |
-
<!
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Nioplay - Double Spin Loot Box</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
| 9 |
+
<script src="https://unpkg.com/feather-icons"></script>
|
| 10 |
+
<link rel="stylesheet" href="style.css">
|
| 11 |
+
<script src="components/loot-box.js"></script>
|
| 12 |
+
<script src="components/multiplier-track.js"></script>
|
| 13 |
+
<script src="components/reward-popup.js"></script>
|
| 14 |
+
<script>
|
| 15 |
+
tailwind.config = {
|
| 16 |
+
theme: {
|
| 17 |
+
extend: {
|
| 18 |
+
colors: {
|
| 19 |
+
premium: {
|
| 20 |
+
dark: '#0a0a0a',
|
| 21 |
+
glow: '#FF8C00',
|
| 22 |
+
gold: '#FFD700',
|
| 23 |
+
softgold: '#FFCC66',
|
| 24 |
+
purple: '#8A2BE2',
|
| 25 |
+
blue: '#1E90FF',
|
| 26 |
+
green: '#32CD32'
|
| 27 |
+
}
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
}
|
| 31 |
+
}
|
| 32 |
+
</script>
|
| 33 |
+
</head>
|
| 34 |
+
<body class="bg-premium-dark text-white font-sans overflow-hidden w-full h-screen flex items-center justify-center relative">
|
| 35 |
+
<!-- Background Elements -->
|
| 36 |
+
<div class="absolute inset-0 bg-radial-gradient opacity-90 z-0"></div>
|
| 37 |
+
<div class="absolute inset-0 particle-field z-0"></div>
|
| 38 |
+
|
| 39 |
+
<!-- Main Container -->
|
| 40 |
+
<div class="relative z-10 w-full max-w-6xl mx-auto p-8 rounded-2xl backdrop-blur-lg bg-premium-dark/70 border border-premium-glow/20 shadow-2xl shadow-premium-glow/10">
|
| 41 |
+
<!-- Header Section -->
|
| 42 |
+
<div class="flex flex-col md:flex-row justify-between items-center mb-12">
|
| 43 |
+
<div>
|
| 44 |
+
<h1 class="text-4xl font-bold bg-gradient-to-r from-premium-gold to-premium-softgold bg-clip-text text-transparent tracking-wider uppercase drop-shadow-lg">
|
| 45 |
+
Mystery Loot Box Roll
|
| 46 |
+
</h1>
|
| 47 |
+
<p class="text-premium-glow/70 mt-2">
|
| 48 |
+
Spin across the mystery boxes, unlock a random reward, then boost it with a multiplier roll.
|
| 49 |
+
</p>
|
| 50 |
+
</div>
|
| 51 |
+
<div class="mt-4 md:mt-0 px-6 py-2 rounded-full bg-premium-dark/50 border border-premium-glow/30 backdrop-blur-sm">
|
| 52 |
+
<span class="text-premium-glow font-medium">Today's Legendary Chance: +3%</span>
|
| 53 |
+
</div>
|
| 54 |
+
</div>
|
| 55 |
+
|
| 56 |
+
<!-- Loot Box Carousel -->
|
| 57 |
+
<loot-box-carousel></loot-box-carousel>
|
| 58 |
+
|
| 59 |
+
<!-- Roll Button -->
|
| 60 |
+
<div class="flex flex-col items-center mt-10">
|
| 61 |
+
<button id="rollButton" class="px-12 py-4 rounded-full bg-gradient-to-r from-premium-gold to-premium-glow text-premium-dark font-bold text-xl uppercase tracking-wider shadow-lg hover:shadow-premium-glow/40 transition-all duration-300 relative overflow-hidden group">
|
| 62 |
+
<span class="relative z-10">Roll</span>
|
| 63 |
+
<span class="absolute inset-0 bg-gradient-to-r from-premium-glow to-premium-gold opacity-0 group-hover:opacity-100 transition-opacity duration-300"></span>
|
| 64 |
+
</button>
|
| 65 |
+
<p id="statusText" class="text-premium-glow/80 mt-3 text-sm">Ready to spin</p>
|
| 66 |
+
</div>
|
| 67 |
+
|
| 68 |
+
<!-- Multiplier Track -->
|
| 69 |
+
<multiplier-track class="mt-16"></multiplier-track>
|
| 70 |
+
</div>
|
| 71 |
+
|
| 72 |
+
<!-- Reward Popup (Hidden by default) -->
|
| 73 |
+
<reward-popup></reward-popup>
|
| 74 |
+
|
| 75 |
+
<script src="script.js"></script>
|
| 76 |
+
<script>
|
| 77 |
+
feather.replace();
|
| 78 |
+
</script>
|
| 79 |
+
<script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
|
| 80 |
+
</body>
|
| 81 |
+
</html>
|
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 2 |
+
const rollButton = document.getElementById('rollButton');
|
| 3 |
+
const statusText = document.getElementById('statusText');
|
| 4 |
+
const rewardPopup = document.querySelector('reward-popup');
|
| 5 |
+
|
| 6 |
+
// Simulate loot box spin
|
| 7 |
+
rollButton.addEventListener('click', () => {
|
| 8 |
+
// Disable button during animation
|
| 9 |
+
rollButton.disabled = true;
|
| 10 |
+
statusText.textContent = "Rolling...";
|
| 11 |
+
|
| 12 |
+
// Get components
|
| 13 |
+
const lootBoxCarousel = document.querySelector('loot-box-carousel');
|
| 14 |
+
const multiplierTrack = document.querySelector('multiplier-track');
|
| 15 |
+
|
| 16 |
+
// Start both animations
|
| 17 |
+
lootBoxCarousel.startSpin();
|
| 18 |
+
multiplierTrack.startSpin();
|
| 19 |
+
|
| 20 |
+
// After animations complete, show reward
|
| 21 |
+
setTimeout(() => {
|
| 22 |
+
const selectedBox = lootBoxCarousel.getSelectedBox();
|
| 23 |
+
const selectedMultiplier = multiplierTrack.getSelectedMultiplier();
|
| 24 |
+
|
| 25 |
+
// Calculate reward
|
| 26 |
+
const baseReward = selectedBox.value;
|
| 27 |
+
const multiplier = selectedMultiplier.value;
|
| 28 |
+
const finalReward = baseReward * multiplier;
|
| 29 |
+
|
| 30 |
+
// Update status
|
| 31 |
+
statusText.textContent = `Selected: ${selectedBox.rarity} Loot Box (${baseReward} SC) ×${multiplier}`;
|
| 32 |
+
|
| 33 |
+
// Show reward popup
|
| 34 |
+
rewardPopup.show({
|
| 35 |
+
baseReward,
|
| 36 |
+
multiplier,
|
| 37 |
+
finalReward,
|
| 38 |
+
rarity: selectedBox.rarity
|
| 39 |
+
});
|
| 40 |
+
|
| 41 |
+
// Re-enable button
|
| 42 |
+
rollButton.disabled = false;
|
| 43 |
+
}, 5000); // Match this with animation duration
|
| 44 |
+
});
|
| 45 |
+
|
| 46 |
+
// Initialize reward popup as hidden
|
| 47 |
+
rewardPopup.hide();
|
| 48 |
+
});
|
|
@@ -1,28 +1,77 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
}
|
| 5 |
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
}
|
| 10 |
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
margin-bottom: 10px;
|
| 15 |
-
margin-top: 5px;
|
| 16 |
}
|
| 17 |
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
|
|
|
| 24 |
}
|
| 25 |
|
| 26 |
-
|
| 27 |
-
|
|
|
|
| 28 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Background Effects */
|
| 2 |
+
.bg-radial-gradient {
|
| 3 |
+
background: radial-gradient(ellipse at center, #1a1a1a 0%, #0a0a0a 70%, #000000 100%);
|
| 4 |
}
|
| 5 |
|
| 6 |
+
.particle-field {
|
| 7 |
+
background-image:
|
| 8 |
+
radial-gradient(1px 1px at 10% 20%, rgba(255, 140, 0, 0.4), transparent),
|
| 9 |
+
radial-gradient(1px 1px at 30% 50%, rgba(255, 215, 0, 0.3), transparent),
|
| 10 |
+
radial-gradient(1px 1px at 70% 80%, rgba(255, 140, 0, 0.4), transparent);
|
| 11 |
+
background-size: 200px 200px;
|
| 12 |
+
animation: particles 15s linear infinite;
|
| 13 |
}
|
| 14 |
|
| 15 |
+
@keyframes particles {
|
| 16 |
+
0% { background-position: 0% 0%; }
|
| 17 |
+
100% { background-position: 100% 100%; }
|
|
|
|
|
|
|
| 18 |
}
|
| 19 |
|
| 20 |
+
/* Glassmorphism Effect */
|
| 21 |
+
.glass-effect {
|
| 22 |
+
background: rgba(15, 15, 15, 0.6);
|
| 23 |
+
backdrop-filter: blur(10px);
|
| 24 |
+
-webkit-backdrop-filter: blur(10px);
|
| 25 |
+
border: 1px solid rgba(255, 215, 0, 0.1);
|
| 26 |
+
box-shadow: 0 8px 32px 0 rgba(255, 140, 0, 0.05);
|
| 27 |
}
|
| 28 |
|
| 29 |
+
/* Glow Effects */
|
| 30 |
+
.glow-effect {
|
| 31 |
+
filter: drop-shadow(0 0 8px rgba(255, 140, 0, 0.7));
|
| 32 |
}
|
| 33 |
+
|
| 34 |
+
.text-glow {
|
| 35 |
+
text-shadow: 0 0 10px rgba(255, 215, 0, 0.7);
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
/* Animation for selected elements */
|
| 39 |
+
@keyframes pulse-glow {
|
| 40 |
+
0% { box-shadow: 0 0 0 0 rgba(255, 215, 0, 0.7); }
|
| 41 |
+
70% { box-shadow: 0 0 0 10px rgba(255, 215, 0, 0); }
|
| 42 |
+
100% { box-shadow: 0 0 0 0 rgba(255, 215, 0, 0); }
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
.pulse {
|
| 46 |
+
animation: pulse-glow 2s infinite;
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
/* Track Styles */
|
| 50 |
+
.track {
|
| 51 |
+
position: relative;
|
| 52 |
+
height: 120px;
|
| 53 |
+
background: rgba(20, 20, 20, 0.5);
|
| 54 |
+
border-radius: 8px;
|
| 55 |
+
border: 1px solid rgba(255, 140, 0, 0.2);
|
| 56 |
+
box-shadow: inset 0 0 15px rgba(0, 0, 0, 0.5);
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
.track::before {
|
| 60 |
+
content: '';
|
| 61 |
+
position: absolute;
|
| 62 |
+
inset: 0;
|
| 63 |
+
background: linear-gradient(90deg, rgba(255, 140, 0, 0.1) 0%, transparent 50%, rgba(255, 140, 0, 0.1) 100%);
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
/* Selection Window */
|
| 67 |
+
.selection-window {
|
| 68 |
+
position: absolute;
|
| 69 |
+
left: 50%;
|
| 70 |
+
transform: translateX(-50%);
|
| 71 |
+
height: 100%;
|
| 72 |
+
width: 100px;
|
| 73 |
+
border: 2px solid rgba(255, 140, 0, 0.8);
|
| 74 |
+
border-radius: 8px;
|
| 75 |
+
box-shadow: 0 0 20px rgba(255, 140, 0, 0.5);
|
| 76 |
+
z-index: 10;
|
| 77 |
+
}
|