ProjectGenesis commited on
Commit
60c16c9
·
verified ·
1 Parent(s): 281c1a6

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 files

This 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 CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Nioplay Double Fortune Spin Vault
3
- emoji: 📉
4
- colorFrom: red
5
- colorTo: blue
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
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).
components/loot-box.js ADDED
@@ -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);
components/multiplier-track.js ADDED
@@ -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);
components/reward-popup.js ADDED
@@ -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);
index.html CHANGED
@@ -1,19 +1,81 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>
script.js ADDED
@@ -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
+ });
style.css CHANGED
@@ -1,28 +1,77 @@
1
- body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
4
  }
5
 
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
 
 
 
 
9
  }
10
 
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
  }
17
 
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
 
24
  }
25
 
26
- .card p:last-child {
27
- margin-bottom: 0;
 
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
+ }