// hero-v2.jsx — variante de HERO con mockups reales en lugar del "#1". // Sólo lo carga "Eurekant Website hero.html". function injectHeroRealStyles() { if (document.getElementById('hero-real-styles')) return; const s = document.createElement('style'); s.id = 'hero-real-styles'; s.textContent = ` @property --hrBorderAngle { syntax: ''; inherits: false; initial-value: 0deg; } @keyframes hrBorderRotate { to { --hrBorderAngle: 360deg; } } @keyframes hrBtnShimmer { 0%, 75% { background-position: 200% center; opacity: 0; } 80% { opacity: 1; } 95%, 100%{ background-position: -100% center; opacity: 0; } } @keyframes hrBtnArrow { 0%, 60%, 100% { transform: translateX(0); } 80% { transform: translateX(5px); } } @keyframes hrFloatA { 0%,100% { transform: translateY(0) rotate(0deg); } 50% { transform: translateY(-14px) rotate(-0.4deg); } } @keyframes hrFloatB { 0%,100% { transform: translateY(0) rotate(0deg); } 50% { transform: translateY(-22px) rotate(0.6deg); } } @keyframes hrDeviceIn { from { opacity: 0; transform: translateY(60px) scale(.9); } to { opacity: 1; transform: none; } } .hr-cta-wrap { position: relative; display: inline-block; border-radius: 14px; padding: 2px; background: conic-gradient(from var(--hrBorderAngle), transparent 0%, #2199ea 12%, #63b7f0 22%, #137dc5 32%, transparent 44%, transparent 100%); animation: hrBorderRotate 2.5s linear infinite; transition: transform 0.3s cubic-bezier(.2,.8,.3,1); } .hr-cta-wrap:hover { transform: scale(1.04); } .hr-cta-inner { position: relative; overflow: hidden; padding: 20px 36px; background: linear-gradient(135deg, #2199ea 20%, #137dc5); color: #fff; border: none; border-radius: 12px; font-family: var(--font-heading); font-size: 15px; font-weight: 500; letter-spacing: 0.02em; cursor: pointer; display: flex; align-items: center; gap: 8px; } .hr-cta-inner::after { content: ''; position: absolute; inset: 0; background: linear-gradient(105deg, transparent 30%, rgba(255,255,255,0.55) 50%, transparent 70%); background-size: 200% 100%; animation: hrBtnShimmer 9s ease-in-out infinite; pointer-events: none; } .hr-cta-arrow { display: inline-block; animation: hrBtnArrow 3s ease-in-out infinite; } @media (prefers-reduced-motion: reduce) { .hr-cta-wrap, .hr-device { animation: none !important; } } `; document.head.appendChild(s); } // Cluster de dispositivos reales — laptop Tasty al fondo + phone Comunidad Cima adelante function HeroMockups({ mouse }) { const F = window.F; const px = (mouse.x - 0.5) * 30; const py = (mouse.y - 0.5) * 30; return (
{/* glow */}
{/* laptop Tasty */}
Tasty Control
{/* phone Comunidad Cima — al frente, abajo izquierda */}
Comunidad Cima
{/* chip flotante */}
En producción
); } function FHeroReal({ content }) { const F = window.F; const tweaks = React.useContext(window.TweaksCtx) || {}; const heroRef = React.useRef(null); const canvasRef = React.useRef(null); const progress = useScrollProgress(heroRef); const [mouse, setMouse] = React.useState({ x: 0.5, y: 0.5 }); const rotatingWords = React.useMemo( () => content.hero.rotating || [content.hero.title[0]], [content.hero.rotating, content.hero.title] ); React.useEffect(() => { injectHeroRealStyles(); }, []); // Particle network (igual que el hero original) React.useEffect(() => { const c = canvasRef.current; if (!c) return; const ctx = c.getContext('2d'); let w, h, raf; const dpr = Math.min(2, window.devicePixelRatio || 1); const resize = () => { const r = c.getBoundingClientRect(); w = r.width; h = r.height; c.width = w * dpr; c.height = h * dpr; ctx.setTransform(dpr, 0, 0, dpr, 0, 0); }; resize(); const ro = new ResizeObserver(resize); ro.observe(c); const N = 48; const pts = Array.from({ length: N }, () => ({ x: Math.random() * w, y: Math.random() * h, vx: (Math.random() - 0.5) * 0.3, vy: (Math.random() - 0.5) * 0.3, r: 0.8 + Math.random() * 1.6 })); const loop = () => { ctx.clearRect(0, 0, w, h); ctx.strokeStyle = 'rgba(120,140,210,0.06)'; ctx.lineWidth = 1; for (let x = 0; x < w; x += 60) { ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, h); ctx.stroke(); } for (let y = 0; y < h; y += 60) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(w, y); ctx.stroke(); } for (const p of pts) { p.x += p.vx; p.y += p.vy; if (p.x < 0 || p.x > w) p.vx *= -1; if (p.y < 0 || p.y > h) p.vy *= -1; } for (let i = 0; i < pts.length; i++) { for (let j = i + 1; j < pts.length; j++) { const dx = pts[i].x - pts[j].x, dy = pts[i].y - pts[j].y; const d = Math.hypot(dx, dy); if (d < 170) { ctx.strokeStyle = `rgba(33,153,234,${(1 - d / 170) * 0.4})`; ctx.lineWidth = 0.7; ctx.beginPath(); ctx.moveTo(pts[i].x, pts[i].y); ctx.lineTo(pts[j].x, pts[j].y); ctx.stroke(); } } } for (const p of pts) { ctx.fillStyle = F.accent; ctx.shadowColor = F.accent; ctx.shadowBlur = 14; ctx.beginPath(); ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2); ctx.fill(); } ctx.shadowBlur = 0; raf = requestAnimationFrame(loop); }; loop(); return () => { cancelAnimationFrame(raf); ro.disconnect(); }; }, []); React.useEffect(() => { const onMove = (e) => { const el = heroRef.current; if (!el) return; const r = el.getBoundingClientRect(); setMouse({ x: (e.clientX - r.left) / r.width, y: (e.clientY - r.top) / r.height }); }; const el = heroRef.current; if (!el) return; el.addEventListener('mousemove', onMove); return () => el.removeEventListener('mousemove', onMove); }, []); const px = (mouse.x - 0.5) * 24; const py = (mouse.y - 0.5) * 24; return (
{/* Columna izquierda — copy */}

{content.hero.sub}

{tweaks.showTerminal !== false && }
{/* Columna derecha — mockups reales */}
SCROLL
); } Object.assign(window, { FHeroReal, HeroMockups });