Galeria paisajes 3D Carrito de compras
- samuel gaitan
- 29 ago
- 6 Min. de lectura
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Galería de Paisajes 3D</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
color: white;
min-height: 100vh;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.header {
text-align: center;
margin-bottom: 40px;
}
.header h1 {
font-size: 3rem;
margin-bottom: 10px;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 30px;
margin-bottom: 40px;
}
.artwork-card {
background: rgba(0, 0, 0, 0.3);
border-radius: 20px;
padding: 20px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
transition: transform 0.3s ease;
}
.artwork-card:hover {
transform: translateY(-5px);
}
.canvas-container {
width: 100%;
height: 250px;
border-radius: 15px;
overflow: hidden;
margin-bottom: 15px;
background: #000;
}
.artwork-info h3 {
font-size: 1.5rem;
margin-bottom: 10px;
color: #FFD700;
}
.artwork-info p {
color: #B0C4DE;
margin-bottom: 15px;
}
.price {
font-size: 1.5rem;
font-weight: bold;
color: #00FF7F;
margin-bottom: 15px;
}
.btn {
padding: 12px 24px;
border: none;
border-radius: 10px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
margin: 5px;
}
.btn-buy {
color: white;
}
.btn-buy:hover {
transform: scale(1.05);
box-shadow: 0 5px 15px rgba(255, 107, 107, 0.4);
}
.btn-download {
color: white;
}
.btn-download:hover {
transform: scale(1.05);
box-shadow: 0 5px 15px rgba(50, 205, 50, 0.4);
}
.cart-sidebar {
position: fixed;
right: 20px;
top: 20px;
width: 300px;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(15px);
border-radius: 20px;
padding: 20px;
border: 1px solid rgba(255, 255, 255, 0.2);
z-index: 1000;
}
.cart-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 15px;
}
.cart-item {
background: rgba(255, 255, 255, 0.1);
padding: 10px;
border-radius: 10px;
margin-bottom: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
.cart-total {
border-top: 2px solid #FFD700;
padding-top: 15px;
margin-top: 15px;
font-size: 1.2rem;
font-weight: bold;
}
.hit-counter {
text-align: center;
background: rgba(0, 255, 127, 0.2);
padding: 15px;
border-radius: 15px;
margin-top: 20px;
}
.hit-counter .count {
font-size: 2rem;
font-weight: bold;
color: #00FF7F;
}
.thanks-message {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
padding: 30px;
border-radius: 20px;
text-align: center;
font-size: 1.5rem;
font-weight: bold;
z-index: 2000;
animation: fadeInOut 3s ease-in-out;
}
@keyframes fadeInOut {
0%, 100% { opacity: 0; transform: translate(-50%, -50%) scale(0.8); }
50% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
.hidden {
display: none;
}
</style>
</head>
<body>
<div class="container">
<header class="header">
<h1>🎨 Galería de Paisajes 3D</h1>
<p>Arte digital generativo único - Colección exclusiva</p>
</header>
<div class="gallery" id="gallery"></div>
</div>
<!-- Carrito lateral -->
<div class="cart-sidebar">
<div class="cart-header">
<span style="font-size: 1.5rem;">🛒</span>
<h3>Carrito (<span id="cart-count">0</span>)</h3>
</div>
<div id="cart-items"></div>
<div class="cart-total">
Total: $<span id="cart-total">0</span> COP
</div>
<div class="hit-counter">
<div>💎 Hit Counter</div>
<div class="count" id="hit-count">0</div>
<div style="font-size: 0.8rem;">Compras realizadas</div>
</div>
</div>
<!-- Mensaje de agradecimiento -->
<div id="thanks-message" class="thanks-message hidden">
<div>¡Gracias por tu donación! 🎉</div>
<div style="font-size: 1rem; margin-top: 10px;">Tu compra apoya el arte digital</div>
</div>
<script>
// Estado global
let cart = [];
let hitCount = 0;
let renderers = [];
const artworks = [
{
id: 1,
name: "Amanecer Dorado",
price: 45000,
description: "Hermoso paisaje con sol naciente entre montañas",
scene: 'sunrise'
},
{
id: 2,
name: "Noche Serena",
price: 52000,
description: "Paisaje nocturno con luna llena y montañas silenciosas",
scene: 'moonlight'
},
{
id: 3,
name: "Atardecer Místico",
price: 48000,
description: "Montañas al atardecer con colores cálidos",
scene: 'sunset'
},
{
id: 4,
name: "Valle Esmeralda",
price: 55000,
description: "Valle verde con río y montañas azules",
scene: 'valley'
}
];
// Funciones para crear escenas
function createSunriseScene(scene) {
// Cielo degradado
const skyGeometry = new THREE.SphereGeometry(50, 32, 32);
const skyMaterial = new THREE.MeshBasicMaterial({
color: 0x87CEEB,
side: THREE.BackSide
});
const sky = new THREE.Mesh(skyGeometry, skyMaterial);
scene.add(sky);
// Sol
const sunGeometry = new THREE.SphereGeometry(2, 16, 16);
const sunMaterial = new THREE.MeshBasicMaterial({
color: 0xFFD700,
emissive: 0xFFA500,
emissiveIntensity: 0.5
});
const sun = new THREE.Mesh(sunGeometry, sunMaterial);
sun.position.set(15, 10, -20);
scene.add(sun);
// Montañas
for (let i = 0; i < 4; i++) {
const mountainGeometry = new THREE.ConeGeometry(4 + Math.random() * 2, 8 + Math.random() * 4, 8);
const mountainMaterial = new THREE.MeshLambertMaterial({
color: new THREE.Color().setHSL(0.25, 0.3, 0.3 + Math.random() * 0.2)
});
const mountain = new THREE.Mesh(mountainGeometry, mountainMaterial);
mountain.position.set((i - 2) * 8, 0, -15 - Math.random() * 5);
scene.add(mountain);
}
// Luces
const ambientLight = new THREE.AmbientLight(0x404040, 0.6);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xFFE4B5, 0.8);
directionalLight.position.copy(sun.position);
scene.add(directionalLight);
}
function createMoonlightScene(scene) {
// Cielo nocturno
const skyGeometry = new THREE.SphereGeometry(50, 32, 32);
const skyMaterial = new THREE.MeshBasicMaterial({
color: 0x0B1426,
side: THREE.BackSide
});
const sky = new THREE.Mesh(skyGeometry, skyMaterial);
scene.add(sky);
// Luna
const moonGeometry = new THREE.SphereGeometry(1.5, 16, 16);
const moonMaterial = new THREE.MeshBasicMaterial({
color: 0xF5F5DC,
emissive: 0xF5F5DC,
emissiveIntensity: 0.3
});
const moon = new THREE.Mesh(moonGeometry, moonMaterial);
moon.position.set(-10, 15, -20);
scene.add(moon);
// Estrellas
for (let i = 0; i < 50; i++) {
const starGeometry = new THREE.SphereGeometry(0.05, 4, 4);
const starMaterial = new THREE.MeshBasicMaterial({ color: 0xFFFFFF });
const star = new THREE.Mesh(starGeometry, starMaterial);
star.position.set(
(Math.random() - 0.5) * 100,
Math.random() * 30 + 5,
(Math.random() - 0.5) * 100
);
scene.add(star);
}
// Montañas nocturnas
for (let i = 0; i < 3; i++) {
const mountainGeometry = new THREE.ConeGeometry(5 + Math.random() * 3, 10 + Math.random() * 5, 8);
const mountainMaterial = new THREE.MeshLambertMaterial({ color: 0x1a1a2e });
const mountain = new THREE.Mesh(mountainGeometry, mountainMaterial);
mountain.position.set((i - 1) * 12, 0, -18 - Math.random() * 8);
scene.add(mountain);
}
const ambientLight = new THREE.AmbientLight(0x404080, 0.4);
scene.add(ambientLight);
const moonLight = new THREE.DirectionalLight(0xF5F5DC, 0.5);
moonLight.position.copy(moon.position);
scene.add(moonLight);
}
function createSunsetScene(scene) {
// Cielo atardecer
const skyGeometry = new THREE.SphereGeometry(50, 32, 32);
const skyMaterial = new THREE.MeshBasicMaterial({
color: 0xFF6347,
side: THREE.BackSide
});
const sky = new THREE.Mesh(skyGeometry, skyMaterial);
scene.add(sky);
// Sol atardecer
const sunGeometry = new THREE.SphereGeometry(2.5, 16, 16);
const sunMaterial = new THREE.MeshBasicMaterial({
color: 0xFF4500,
emissive: 0xFF6347,
emissiveIntensity: 0.6
});
const sun = new THREE.Mesh(sunGeometry, sunMaterial);
sun.position.set(-18, 6, -25);
scene.add(sun);
// Montañas silueta
for (let i = 0; i < 5; i++) {
const mountainGeometry = new THREE.ConeGeometry(3 + Math.random() * 3, 6 + Math.random() * 6, 6);
const mountainMaterial = new THREE.MeshBasicMaterial({ color: 0x2F1B69 });
const mountain = new THREE.Mesh(mountainGeometry, mountainMaterial);
mountain.position.set((i - 2) * 8, 0, -15 - Math.random() * 10);
scene.add(mountain);
}
const ambientLight = new THREE.AmbientLight(0x8B4513, 0.5);
scene.add(ambientLight);
}
function createValleyScene(scene) {
// Cielo día
const skyGeometry = new THREE.SphereGeometry(50, 32, 32);
const skyMaterial = new THREE.MeshBasicMaterial({
color: 0x87CEEB,
side: THREE.BackSide
});
const sky = new THREE.Mesh(skyGeometry, skyMaterial);
scene.add(sky);
// Sol
const sunGeometry = new THREE.SphereGeometry(1.8, 16, 16);
const sunMaterial = new THREE.MeshBasicMaterial({
color: 0xFFFF00,
emissive: 0xFFFF00,
emissiveIntensity: 0.4
});
const sun = new THREE.Mesh(sunGeometry, sunMaterial);
sun.position.set(0, 18, -30);
scene.add(sun);
// Montañas verdes
for (let i = 0; i < 6; i++) {
const mountainGeometry = new THREE.ConeGeometry(4 + Math.random() * 3, 9 + Math.random() * 4, 8);
const mountainMaterial = new THREE.MeshLambertMaterial({
color: new THREE.Color().setHSL(0.25, 0.7, 0.4 + Math.random() * 0.2)
});
const mountain = new THREE.Mesh(mountainGeometry, mountainMaterial);
mountain.position.set((i - 2.5) * 8, 0, -18 - Math.random() * 8);
scene.add(mountain);
}
// Río
const riverGeometry = new THREE.PlaneGeometry(60, 3);
const riverMaterial = new THREE.MeshLambertMaterial({
color: 0x4169E1,
transparent: true,
opacity: 0.7
});
const river = new THREE.Mesh(riverGeometry, riverMaterial);
river.rotation.x = -Math.PI / 2;
river.position.y = -3;
scene.add(river);
const ambientLight = new THREE.AmbientLight(0x404040, 0.7);
scene.add(ambientLight);
const sunLight = new THREE.DirectionalLight(0xFFFFFF, 0.8);
sunLight.position.copy(sun.position);
scene.add(sunLight);
}
function createArtworkCanvas(artwork, container) {
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, container.offsetWidth / container.offsetHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true });
renderer.setSize(container.offsetWidth, container.offsetHeight);
renderer.setClearColor(0x000000);
container.appendChild(renderer.domElement);
camera.position.set(0, 8, 20);
camera.lookAt(0, 0, 0);
// Crear escena según el tipo
switch (artwork.scene) {
case 'sunrise':
createSunriseScene(scene);
break;
case 'moonlight':
createMoonlightScene(scene);
break;
case 'sunset':
createSunsetScene(scene);
break;
case 'valley':
createValleyScene(scene);
break;
}
// Animación
function animate() {
requestAnimationFrame(animate);
camera.position.x = Math.sin(Date.now() * 0.0003) * 1.5;
renderer.render(scene, camera);
}
animate();
return { renderer, scene, camera };
}
function addToCart(artwork) {
cart.push(artwork);
hitCount++;
updateCartDisplay();
updateHitCounter();
showThanksMessage();
}
function updateCartDisplay() {
const cartItems = document.getElementById('cart-items');
const cartCount = document.getElementById('cart-count');
const cartTotal = document.getElementById('cart-total');
cartItems.innerHTML = '';
if (cart.length === 0) {
cartItems.innerHTML = '<div style="color: #888; text-align: center;">Carrito vacío</div>';
} else {
cart.forEach((item, index) => {
const cartItem = document.createElement('div');
cartItem.className = 'cart-item';
cartItem.innerHTML = `
<div>
<div style="font-weight: bold; font-size: 0.9rem;">${item.name}</div>
<div style="color: #FFD700;">$${item.price.toLocaleString('es-CO')}</div>
</div>
<button onclick="removeFromCart(${index})" style="background: #FF4444; color: white; border: none; border-radius: 5px; padding: 5px; cursor: pointer;">✕</button>
`;
cartItems.appendChild(cartItem);
});
}
cartCount.textContent = cart.length;
cartTotal.textContent = cart.reduce((total, item) => total + item.price, 0).toLocaleString('es-CO');
}
function removeFromCart(index) {
cart.splice(index, 1);
updateCartDisplay();
}
function updateHitCounter() {
document.getElementById('hit-count').textContent = hitCount;
}
function showThanksMessage() {
const thanksMsg = document.getElementById('thanks-message');
thanksMsg.classList.remove('hidden');
setTimeout(() => {
thanksMsg.classList.add('hidden');
}, 3000);
}
function exportImage(artworkId) {
const renderer = renderers[artworkId - 1];
if (renderer) {
const canvas = renderer.domElement;
const link = document.createElement('a');
const artwork = artworks.find(art => art.id === artworkId);
link.download = `${artwork.name.replace(/\s+/g, '_')}.png`;
link.href = canvas.toDataURL('image/png');
link.click();
}
}
function createGallery() {
const gallery = document.getElementById('gallery');
artworks.forEach((artwork) => {
const card = document.createElement('div');
card.className = 'artwork-card';
card.innerHTML = `
<div class="canvas-container" id="canvas-${artwork.id}"></div>
<div class="artwork-info">
<h3>${artwork.name}</h3>
<p>${artwork.description}</p>
<div class="price">$${artwork.price.toLocaleString('es-CO')} COP</div>
<div>
<button class="btn btn-buy" onclick="addToCart(${JSON.stringify(artwork).replace(/"/g, '"')})">
🛒 Comprar Ahora
</button>
<button class="btn btn-download" onclick="exportImage(${artwork.id})">
📥 Descargar PNG
</button>
</div>
</div>
`;
gallery.appendChild(card);
// Crear canvas 3D para esta obra
const container = document.getElementById(`canvas-${artwork.id}`);
const { renderer } = createArtworkCanvas(artwork, container);
renderers.push(renderer);
});
}
// Inicializar la galería cuando se carga la página
window.addEventListener('load', () => {
createGallery();
updateCartDisplay();
updateHitCounter();
});
// Manejar redimensionamiento
window.addEventListener('resize', () => {
// Actualizar tamaños de canvas si es necesario
renderers.forEach((renderer, index) => {
const container = document.getElementById(`canvas-${index + 1}`);
if (container && renderer) {
renderer.setSize(container.offsetWidth, container.offsetHeight);
}
});
});
</script>
</body>
</html>




Comentarios