import { useState, useEffect, useRef, useCallback } from "react"; import * as THREE from "three"; /* ─── Brand tokens ─── */ const C = { red:"#E3000F", redD:"#B8000C", yellow:"#FFD700", yellowL:"#FFF8C0", blue:"#0033A0", blueD:"#002280", cream:"#FFFDF5", creamD:"#FFF5E0", wa:"#25D366", waD:"#1da851", txt:"#1a1a2e", txtL:"#666", }; const WA = (msg="Hola! Quisiera hacer un pedido 🍬") => `https://wa.me/5493512469011?text=${encodeURIComponent(msg)}`; /* ─── SVG icons ─── */ const WaIcon = ({ size=24, color="#fff" }) => ( ); /* ══════════════════════════════════════════ THREE.JS CANDY SCENE ══════════════════════════════════════════ */ function CandyScene() { const mountRef = useRef(null); const mouse = useRef({ x: 0, y: 0 }); useEffect(() => { const el = mountRef.current; if (!el) return; const W = el.clientWidth, H = el.clientHeight; /* Scene & Camera */ const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(55, W / H, 0.1, 100); camera.position.set(0, 0.4, 7); /* Renderer */ const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); renderer.setSize(W, H); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); renderer.setClearColor(0x000000, 0); el.appendChild(renderer.domElement); /* Lights */ scene.add(new THREE.AmbientLight(0xffffff, 0.6)); const lA = new THREE.PointLight(0xFFD700, 4, 25); lA.position.set(4, 4, 4); const lB = new THREE.PointLight(0xFF2255, 3, 20); lB.position.set(-4, -2, 3); const lC = new THREE.PointLight(0x0055FF, 2.5, 20); lC.position.set(0, 4, -3); scene.add(lA, lB, lC); /* ── Main Lollipop group ── */ const lolli = new THREE.Group(); /* Candy head – shiny sphere */ const headMat = new THREE.MeshPhongMaterial({ color: 0xFF2244, shininess: 220, specular: 0xffffff, reflectivity: 1, }); const head = new THREE.Mesh(new THREE.SphereGeometry(1.25, 40, 40), headMat); lolli.add(head); /* Stripe rings */ const stripeColors = [0xFFD700, 0xffffff, 0xFF8800, 0xffffff, 0xFFD700, 0xee0022]; stripeColors.forEach((col, i) => { const mat = new THREE.MeshPhongMaterial({ color: col, shininess: 160, transparent: true, opacity: 0.9 }); const ring = new THREE.Mesh(new THREE.TorusGeometry(1.25, 0.07, 8, 52, Math.PI * 0.65), mat); ring.rotation.y = (i / stripeColors.length) * Math.PI * 2; ring.rotation.x = Math.PI / 3.5; lolli.add(ring); }); /* Stick */ const stick = new THREE.Mesh( new THREE.CylinderGeometry(0.085, 0.085, 3.8, 14), new THREE.MeshPhongMaterial({ color: 0xfff8e0, shininess: 100 }) ); stick.position.y = -2.65; lolli.add(stick); /* Spiral on stick via TubeGeometry */ const pts = Array.from({ length: 28 }, (_, i) => { const t = i / 27; return new THREE.Vector3( Math.cos(t * Math.PI * 9) * 0.11, -1.0 - t * 3.5, Math.sin(t * Math.PI * 9) * 0.11 ); }); const spiralTube = new THREE.Mesh( new THREE.TubeGeometry(new THREE.CatmullRomCurve3(pts), 80, 0.045, 8, false), new THREE.MeshPhongMaterial({ color: 0xE3000F, shininess: 120 }) ); lolli.add(spiralTube); /* Wrapper base circle */ const wrapper = new THREE.Mesh( new THREE.TorusGeometry(1.42, 0.055, 8, 64), new THREE.MeshPhongMaterial({ color: 0xFFD700, shininess: 180, transparent: true, opacity: 0.8 }) ); wrapper.rotation.x = Math.PI / 2; lolli.add(wrapper); lolli.position.set(0, 0.3, 0); scene.add(lolli); /* ── Floating candy pieces ── */ const candyPalette = [0xFFD700, 0xE3000F, 0x0033A0, 0xFF69B4, 0x25D366, 0xFF8C00, 0xAA44EE, 0x00CCFF]; const floaters = []; const COUNT = 22; for (let i = 0; i < COUNT; i++) { const kind = i % 3; let geo; if (kind === 0) geo = new THREE.TorusGeometry(0.22, 0.09, 8, 28); else if (kind === 1) geo = new THREE.SphereGeometry(0.18, 14, 14); else geo = new THREE.IcosahedronGeometry(0.2, 0); const mat = new THREE.MeshPhongMaterial({ color: candyPalette[i % candyPalette.length], shininess: 140, specular: 0xffffff, }); const m = new THREE.Mesh(geo, mat); const radius = 3.2 + Math.random() * 2.4; const theta0 = (i / COUNT) * Math.PI * 2; const phi0 = (Math.random() * 0.7 + 0.15) * Math.PI; m.userData = { radius, theta0, phi0, orbitSpeed: 0.18 + Math.random() * 0.45, floatAmp: 0.2 + Math.random() * 0.35, floatOff: Math.random() * Math.PI * 2, rotSp: (Math.random() - 0.5) * 0.06, }; m.position.set( radius * Math.sin(phi0) * Math.cos(theta0), radius * Math.cos(phi0) * 0.55, radius * Math.sin(phi0) * Math.sin(theta0) - 0.5 ); scene.add(m); floaters.push(m); } /* Mouse tracking */ const onMove = (e) => { const r = el.getBoundingClientRect(); mouse.current.x = ((e.clientX - r.left) / r.width - 0.5) * 2; mouse.current.y = ((e.clientY - r.top) / r.height - 0.5) * 2; }; el.addEventListener("mousemove", onMove); /* Touch */ const onTouch = (e) => { const r = el.getBoundingClientRect(); const t = e.touches[0]; mouse.current.x = ((t.clientX - r.left) / r.width - 0.5) * 2; mouse.current.y = ((t.clientY - r.top) / r.height - 0.5) * 2; }; el.addEventListener("touchmove", onTouch, { passive: true }); /* Resize */ const onResize = () => { const w = el.clientWidth, h = el.clientHeight; camera.aspect = w / h; camera.updateProjectionMatrix(); renderer.setSize(w, h); }; window.addEventListener("resize", onResize); /* Animate */ let raf, t = 0; const tick = () => { raf = requestAnimationFrame(tick); t += 0.01; /* Lollipop follows mouse with lag */ lolli.rotation.y += (mouse.current.x * 0.6 - lolli.rotation.y) * 0.04; lolli.rotation.x += (-mouse.current.y * 0.35 - lolli.rotation.x) * 0.04; lolli.rotation.z = Math.sin(t * 0.5) * 0.04; lolli.position.y = 0.3 + Math.sin(t * 0.8) * 0.14; /* Floating candies orbit */ floaters.forEach(m => { const u = m.userData; const angle = u.theta0 + t * u.orbitSpeed; m.position.x = u.radius * Math.sin(u.phi0) * Math.cos(angle); m.position.z = u.radius * Math.sin(u.phi0) * Math.sin(angle) - 0.5; m.position.y = u.radius * Math.cos(u.phi0) * 0.55 + Math.sin(t * u.orbitSpeed + u.floatOff) * u.floatAmp; m.rotation.x += u.rotSp; m.rotation.y += u.rotSp * 0.8; }); /* Lights orbit */ lA.position.x = Math.cos(t * 0.4) * 5; lA.position.z = Math.sin(t * 0.4) * 5; lB.position.x = Math.cos(t * 0.4 + Math.PI) * 4; lB.position.z = Math.sin(t * 0.4 + Math.PI) * 4; renderer.render(scene, camera); }; tick(); return () => { cancelAnimationFrame(raf); el.removeEventListener("mousemove", onMove); el.removeEventListener("touchmove", onTouch); window.removeEventListener("resize", onResize); renderer.dispose(); if (el.contains(renderer.domElement)) el.removeChild(renderer.domElement); }; }, []); return (
); } /* ══════════════════════════════════════════ PARTICLE CANVAS (emoji falling) ══════════════════════════════════════════ */ function ParticleCanvas() { const ref = useRef(null); useEffect(() => { const canvas = ref.current; if (!canvas) return; const ctx = canvas.getContext("2d"); const EMOJIS = ["🍬","🍭","🍫","🍡","🧁","🍩","🎊","⭐","🎀","🌟"]; let W, H, particles = [], raf; const resize = () => { W = canvas.width = canvas.parentElement.offsetWidth; H = canvas.height = canvas.parentElement.offsetHeight; }; const mkPart = (y) => ({ x: Math.random() * (W||800), y: y ?? Math.random() * -200 - 20, emoji: EMOJIS[Math.floor(Math.random() * EMOJIS.length)], size: 14 + Math.random() * 18, speed: 0.3 + Math.random() * 0.7, drift: (Math.random() - 0.5) * 0.4, rot: Math.random() * Math.PI * 2, rotSp: (Math.random() - 0.5) * 0.015, op: 0.25 + Math.random() * 0.45, vx: 0, vy: 0, }); resize(); for (let i = 0; i < 40; i++) particles.push(mkPart(Math.random() * H)); const draw = () => { raf = requestAnimationFrame(draw); ctx.clearRect(0, 0, W, H); particles.forEach((p, i) => { p.vy = p.vy * 0.92 + p.speed * 0.08; p.vx = p.vx * 0.92 + p.drift * 0.08; if (p.vy < p.speed * 0.4) p.vy = p.speed * 0.4; p.x += p.vx; p.y += p.vy; p.rot += p.rotSp; if (p.y > H + 40 || p.x < -60 || p.x > W + 60) particles[i] = mkPart(); ctx.save(); ctx.globalAlpha = p.op; ctx.font = `${p.size}px serif`; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.translate(p.x, p.y); ctx.rotate(p.rot); ctx.fillText(p.emoji, 0, 0); ctx.restore(); }); }; draw(); window.addEventListener("resize", resize); return () => { cancelAnimationFrame(raf); window.removeEventListener("resize", resize); }; }, []); return ( ); } /* ══════════════════════════════════════════ SCROLL REVEAL HOOK ══════════════════════════════════════════ */ function useReveal() { const map = useRef(new Map()); const [visible, setVisible] = useState(new Set()); const register = useCallback((id) => (el) => { if (!el) return; map.current.set(id, el); el.dataset.revealId = id; }, []); useEffect(() => { const io = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting) setVisible(prev => new Set([...prev, e.target.dataset.revealId])); }); }, { threshold: 0.12, rootMargin: "0px 0px -40px 0px" }); map.current.forEach(el => io.observe(el)); return () => io.disconnect(); }, []); const style = (id, delay = 0) => ({ opacity: visible.has(id) ? 1 : 0, transform: visible.has(id) ? "translateY(0) scale(1)" : "translateY(44px) scale(0.95)", transition: `opacity .7s ease ${delay}s, transform .7s cubic-bezier(.34,1.56,.64,1) ${delay}s`, }); return { register, style, visible }; } /* ══════════════════════════════════════════ PARALLAX HOOK ══════════════════════════════════════════ */ function useParallax() { const [sy, setSy] = useState(0); useEffect(() => { let raf; const onScroll = () => { cancelAnimationFrame(raf); raf = requestAnimationFrame(() => setSy(window.scrollY)); }; window.addEventListener("scroll", onScroll, { passive: true }); return () => { window.removeEventListener("scroll", onScroll); cancelAnimationFrame(raf); }; }, []); return sy; } /* ══════════════════════════════════════════ REUSABLE COMPONENTS ══════════════════════════════════════════ */ function WaButton({ href, children, size="md", style:sx={} }) { const base = { display:"inline-flex", alignItems:"center", gap:10, background:`linear-gradient(135deg,${C.wa},#1fba5a)`, color:"#fff", textDecoration:"none", borderRadius:50, fontFamily:"'Baloo 2',cursive", fontWeight:800, boxShadow:`0 6px 28px rgba(37,211,102,.4)`, transition:"transform .18s,box-shadow .18s", cursor:"pointer", }; const sizes = { sm: { fontSize:"0.88rem", padding:"9px 22px" }, md: { fontSize:"1rem", padding:"13px 30px" }, lg: { fontSize:"1.2rem", padding:"18px 44px" }, xl: { fontSize:"1.35rem", padding:"20px 52px" }, }; return ( {e.currentTarget.style.transform="scale(1.05) translateY(-2px)"; e.currentTarget.style.boxShadow="0 12px 40px rgba(37,211,102,.6)";}} onMouseLeave={e=>{e.currentTarget.style.transform=""; e.currentTarget.style.boxShadow=`0 6px 28px rgba(37,211,102,.4)`;}} > {children} ); } function SectionTag({ children, light }) { return (
{children}
); } function SectionTitle({ children, light, center=true }) { return (

{children}

); } /* ══════════════════════════════════════════ MAIN PAGE ══════════════════════════════════════════ */ export default function App() { const sy = useParallax(); const { register, style: rv } = useReveal(); return (
{/* ── Fonts + global CSS ── */} {/* ══ HEADER ══ */}
🍬 Bongi Bom Bon
Pedí ahora Pedí ahora
{/* ══ HERO ══ */}
{/* Particle canvas */} {/* Parallax blobs */}
{/* Content grid: left text | right 3D */}
{/* Left: text */}
🎉 Río Segundo, Córdoba

Las mejores{" "} golosinas
para tu fiesta

Copetín, combos y golosinas al por mayor y menor. Surtimos cumpleaños, eventos y mesas dulces con los mejores precios de la región.

¡Hacé tu pedido por WhatsApp!
★★★★★ +10.000 clientes felices · Respuesta rápida
{/* Right: Three.js */}
{/* Glow ring */}
{/* Scroll hint */}
Deslizá para ver más
{/* ══ PROOF BAR ══ */}
{[ ["🌟","5.0","en Google Maps"], ["🎊","+10.000","clientes felices"], ["⚡","Respuesta","rápida"], ["💰","Mejores","precios"], ].map(([icon, num, label], i) => (
{icon} {num} {label}
))}
{/* ══ POR QUÉ ELEGIRNOS ══ */}
{/* Parallax decorative circle */}
¿Por qué elegirnos? Todo lo que necesitás,{" "} en un solo lugar

Somos el punto de referencia de Río Segundo para golosinas, copetín y todo lo que hace falta para una fiesta memorable.

{[ ["🏷️","Precios Imbatibles","Trabajamos con volumen para darte los mejores precios del mercado, sin sacrificar calidad en ningún producto."], ["🎁","Gran Variedad","Golosinas, chicles, chocolates, copetín salado, alfajores y todo lo que imaginás para tu mesa dulce o evento."], ["💬","Atención Personalizada","Te asesoramos para armar el combo perfecto según tu presupuesto y la cantidad de personas que tenés."], ["⚡","Respuesta Inmediata","Escribinos por WhatsApp y recibís respuesta al toque. Pedidos listos para retirar en Jujuy 868, Río Segundo."], ].map(([icon, title, desc], i) => (
{icon}

{title}

{desc}

))}
{/* ══ PRODUCTOS ══ */}
Nuestros productos Olvidate del estrés:{" "} tenemos todo

Desde golosinas individuales hasta paquetes completos para 200 personas. Vos disfrutá la fiesta, nosotros te la surtimos.

{[ { emoji:"🍬", bg:"linear-gradient(135deg,#FFE8E8,#FFF0C0)", title:"Golosinas & Caramelos", desc:"Amplia selección de marcas nacionales: Arcor, Sugus, Mentitas, gomitas y todo lo dulce.", badge:"⭐ Top", msg:"Hola! Me interesan las golosinas 🍬" }, { emoji:"🎉", bg:"linear-gradient(135deg,#E8F0FF,#F0E8FF)", title:"Mesa Dulce para Cumpleaños", desc:"Surtido especial para cumpleaños infantiles y adultos. Te ayudamos a calcular las cantidades ideales.", badge:"Fiestas", msg:"Hola! Quiero armar una mesa dulce 🎉" }, { emoji:"🥨", bg:"linear-gradient(135deg,#E8FFE8,#F0FFE8)", title:"Copetín & Salados", desc:"Papas fritas, palitos, maníes, galletitas y todo el copetín salado para que no falte nada.", badge:null, msg:"Hola! Me interesa el copetín 🥨" }, { emoji:"🎊", bg:"linear-gradient(135deg,#FFF0E8,#FFE8D0)", title:"Combos para Eventos", desc:"Paquetes cerrados para 50, 100 o 200 personas. Dulce + salado + presentación incluida.", badge:"Popular", msg:"Hola! Quiero info sobre combos 🎊" }, ].map((p, i) => ( ))}
{/* ══ COMBOS ══ */}
{/* Pattern overlay */}
{/* Parallax decoration */}
Combos armados Elegí tu combo
y listo para tu fiesta

Sin vueltas. Elegís, nos avisás por WhatsApp y lo tenés listo para retirar. Así de fácil.

{[ { icon:"🧒", title:"Combo Infantil", items:["Golosinas surtidas x50","Chicles y caramelos","Copetín para 20 niños","Bolsitas de recuerdo"], featured:false, msg:"Hola! Me interesa el Combo Infantil 🧒" }, { icon:"🎂", title:"Combo Cumpleaños", items:["Mesa dulce completa","Golosinas para 50 personas","Copetín salado incluido","Asesoramiento incluido"], featured:true, msg:"Hola! Me interesa el Combo Cumpleaños 🎂" }, { icon:"🏢", title:"Combo Evento Grande", items:["+100 personas","Surtido dulce y salado","Precio mayorista","Cotización personalizada"], featured:false, msg:"Hola! Quiero cotizar un evento grande 🏢" }, ].map((c, i) => (
{e.currentTarget.style.background="rgba(255,255,255,.16)"; e.currentTarget.style.transform="translateY(-8px)";}} onMouseLeave={e=>{e.currentTarget.style.background=c.featured?"rgba(255,215,0,.13)":"rgba(255,255,255,.08)"; e.currentTarget.style.transform="";}} > {c.featured && (
⭐ Más elegido
)}
{c.icon}

{c.title}

    {c.items.map((item, j) => (
  • {item}
  • ))}
Consultar
))}
{/* ══ RESEÑAS ══ */}
Opiniones reales Lo que dicen{" "} nuestros clientes

Todas reseñas reales de Google Maps. Sin filtros, sin inventos. 5 estrellas por mérito propio.

{[ { init:"NB", name:"Lic. Nicolas Bongiorno", text:"Son excelentes! El mejor precio y calidad. No dudés en consultarlos, te ayudan con todo.", col:"linear-gradient(135deg,#E3000F,#ff4d5e)" }, { init:"NG", name:"Nora Gomez", text:"Buena atención. Muy amables. Excelente calidad de productos. Muy recomendable.", col:`linear-gradient(135deg,${C.blue},#0055cc)` }, { init:"GB", name:"Gochy Bongiorno", text:"¡EXCELENTE ATENCIÓN, COMODIDAD, PRECIOS Y COMBOS MUY BUENOS! Vuelvo siempre, sin dudas.", col:"linear-gradient(135deg,#8B5CF6,#A855F7)" }, { init:"SC", name:"Sebastián M. Castellano", text:"Excelente local para fiestas infantiles. Tienen muy buenas promos y una gran variedad.", col:"linear-gradient(135deg,#F59E0B,#EF4444)" }, { init:"ST", name:"Silvina Tissera", text:"Muy buenos productos. Todas las golosinas para los cumpleaños de los niños. Riquísimo y muy buenos precios.", col:"linear-gradient(135deg,#10B981,#059669)" }, ].map((r, i) => (
"
★★★★★

"{r.text}"

{r.init}
{r.name}
Google Maps ✓
))}
{/* ══ CTA FINAL ══ */}
{/* Parallax orb */}
🍭
¿Lista tu fiesta?
¡Nosotros la surtimos!

No importa si son 20 o 200 personas. Escribinos y te armamos el combo perfecto al mejor precio de Río Segundo.

{e.currentTarget.style.transform="scale(1.07)"; e.currentTarget.style.boxShadow="0 16px 60px rgba(0,0,0,.32)";}} onMouseLeave={e=>{e.currentTarget.style.transform=""; e.currentTarget.style.boxShadow="0 8px 40px rgba(0,0,0,.22)";}} > Escribinos por WhatsApp
{["✅ Sin compromiso","⚡ Respuesta en minutos","💰 Mejor precio garantizado","🎉 +100 fiestas realizadas"].map((item, i) => (
{item}
))}
{/* ══ FOOTER ══ */}

© 2025 Bongi Bom Bon · Jujuy 868, Río Segundo, Córdoba · Hecho con para los mejores clientes.

{/* ══ FLOATING WA BUTTON ══ */} {e.currentTarget.style.transform="scale(1.12)"; e.currentTarget.style.animation="none";}} onMouseLeave={e=>{e.currentTarget.style.transform=""; e.currentTarget.style.animation="";}} aria-label="WhatsApp" >
); }