ProjectGenesis's picture
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.
60c16c9 verified
class LootBoxCarousel extends HTMLElement {
constructor() {
super();
this.boxes = [
{ rarity: 'common', value: 5, color: 'green' },
{ rarity: 'common', value: 5, color: 'green' },
{ rarity: 'common', value: 10, color: 'green' },
{ rarity: 'rare', value: 15, color: 'blue' },
{ rarity: 'rare', value: 20, color: 'blue' },
{ rarity: 'epic', value: 30, color: 'purple' },
{ rarity: 'legendary', value: 50, color: 'gold' },
{ rarity: 'epic', value: 25, color: 'purple' },
{ rarity: 'rare', value: 15, color: 'blue' },
{ rarity: 'common', value: 10, color: 'green' }
];
this.selectedIndex = 0;
}
connectedCallback() {
this.attachShadow({ mode: 'open' });
this.render();
}
render() {
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
width: 100%;
position: relative;
height: 180px;
margin-bottom: 20px;
}
.track {
position: relative;
height: 100%;
background: rgba(20, 20, 20, 0.5);
border-radius: 8px;
border: 1px solid rgba(255, 140, 0, 0.2);
box-shadow: inset 0 0 15px rgba(0, 0, 0, 0.5);
overflow: hidden;
}
.track::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(90deg, rgba(255, 140, 0, 0.1) 0%, transparent 50%, rgba(255, 140, 0, 0.1) 100%);
}
.boxes-container {
position: absolute;
display: flex;
height: 100%;
align-items: center;
gap: 20px;
padding: 0 50%;
will-change: transform;
transition: transform 0.1s linear;
}
.loot-box {
width: 100px;
height: 100px;
border-radius: 8px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: relative;
transition: all 0.3s ease;
z-index: 5;
}
.loot-box.common {
background: rgba(30, 30, 30, 0.8);
border: 2px solid var(--premium-green);
box-shadow: 0 0 15px var(--premium-green);
}
.loot-box.rare {
background: rgba(30, 30, 30, 0.8);
border: 2px solid var(--premium-blue);
box-shadow: 0 0 15px var(--premium-blue);
}
.loot-box.epic {
background: rgba(30, 30, 30, 0.8);
border: 2px solid var(--premium-purple);
box-shadow: 0 0 20px var(--premium-purple);
}
.loot-box.legendary {
background: rgba(30, 30, 30, 0.8);
border: 2px solid var(--premium-gold);
box-shadow: 0 0 25px var(--premium-gold);
}
.loot-box.selected {
transform: scale(1.2);
z-index: 10;
}
.loot-box.selected.common {
box-shadow: 0 0 25px var(--premium-green);
}
.loot-box.selected.rare {
box-shadow: 0 0 30px var(--premium-blue);
}
.loot-box.selected.epic {
box-shadow: 0 0 35px var(--premium-purple);
}
.loot-box.selected.legendary {
box-shadow: 0 0 40px var(--premium-gold);
}
.box-icon {
font-size: 24px;
margin-bottom: 5px;
}
.rarity {
font-size: 10px;
text-transform: uppercase;
font-weight: bold;
margin-top: 5px;
}
.selection-window {
position: absolute;
left: 50%;
transform: translateX(-50%);
height: 120px;
width: 120px;
border: 2px solid rgba(255, 140, 0, 0.8);
border-radius: 8px;
box-shadow: 0 0 20px rgba(255, 140, 0, 0.5);
z-index: 4;
pointer-events: none;
}
</style>
<div class="track">
<div class="selection-window"></div>
<div class="boxes-container">
${this.boxes.map((box, index) => `
<div class="loot-box ${box.rarity} ${index === this.selectedIndex ? 'selected' : ''}" data-index="${index}">
<i data-feather="box" class="box-icon"></i>
<span class="rarity">${box.rarity}</span>
</div>
`).join('')}
</div>
</div>
`;
// Initialize feather icons
feather.replace();
}
startSpin() {
const container = this.shadowRoot.querySelector('.boxes-container');
const boxes = this.shadowRoot.querySelectorAll('.loot-box');
// Reset selection
boxes.forEach(box => box.classList.remove('selected'));
// Animate spin
let currentPosition = 0;
let speed = 0;
const maxSpeed = 30;
const deceleration = 0.5;
const targetIndex = Math.floor(Math.random() * this.boxes.length);
const animate = () => {
currentPosition += speed;
speed = Math.max(0, speed - deceleration);
// Apply movement
container.style.transform = `translateX(${currentPosition}px)`;
// Highlight box in center
const centerPosition = -currentPosition - container.offsetWidth / 2 + this.offsetWidth / 2;
const boxWidth = 120; // box width + gap
const centerIndex = Math.round(centerPosition / boxWidth) % this.boxes.length;
const selectedIndex = (centerIndex + this.boxes.length) % this.boxes.length;
boxes.forEach((box, i) => {
box.classList.toggle('selected', i === selectedIndex);
});
// Continue animation until stopped
if (speed > 0) {
requestAnimationFrame(animate);
} else {
// Final selection
this.selectedIndex = targetIndex;
this.render();
}
};
// Initial acceleration
speed = maxSpeed;
animate();
}
getSelectedBox() {
return this.boxes[this.selectedIndex];
}
}
customElements.define('loot-box-carousel', LootBoxCarousel);