// SINZETA Landing — scroll-driven from hero (logo) to honeycomb (sections) const HEX_GLOW = '#00E5FF'; // Single hexagon — pointy-top orientation function Hex({ size = 100, stroke = HEX_GLOW, fill = 'transparent', strokeWidth = 1.5, opacity = 1, glow = false, children, onClick, label, sub }) { const sizeStr = typeof size === 'number' ? `${size}px` : size; // Pointy-top hex: width = sqrt(3)*r, height = 2*r, r = size/2 const VB = 100; const ph = 200; const pw = Math.sqrt(3) * VB; const ppoints = [ [pw / 2, 0], [pw, VB * 0.5], [pw, VB * 1.5], [pw / 2, ph], [0, VB * 1.5], [0, VB * 0.5], ].map(p => p.join(',')).join(' '); const cssW = `calc(${sizeStr} * ${Math.sqrt(3) / 2})`; const cssH = sizeStr; const labelSize = `calc(${sizeStr} * 0.10)`; const subSize = `calc(${sizeStr} * 0.06)`; return (
{(label || children) && (
{children} {label && (
{label}
)} {sub && (
{sub}
)}
)}
); } // V3 logo mark — uses SinzetaV3 from monogram-v3.jsx function SinzetaV3Mark({ size = '60vmin' }) { return (
); } function App() { const [scrollProgress, setScrollProgress] = React.useState(0); const [hoveredHex, setHoveredHex] = React.useState(null); const stickyRef = React.useRef(null); React.useEffect(() => { const onScroll = () => { if (!stickyRef.current) return; const el = stickyRef.current; const elTop = el.getBoundingClientRect().top + window.scrollY; const scrolled = window.scrollY - elTop; const total = el.offsetHeight - window.innerHeight; const p = Math.max(0, Math.min(1, scrolled / Math.max(1, total))); setScrollProgress(p); }; onScroll(); window.addEventListener('scroll', onScroll, { passive: true }); return () => window.removeEventListener('scroll', onScroll); }, []); // Hero exits p=0..0.45, honeycomb enters p=0.35..0.80, stable 0.80..1 const heroY = -Math.min(scrollProgress / 0.45, 1) * 100; const heroOpacity = Math.max(0, 1 - scrollProgress / 0.40); const honeyP = Math.max(0, Math.min(1, (scrollProgress - 0.35) / 0.45)); const honeyY = (1 - honeyP) * 100; const honeyOpacity = honeyP; const sections = [ { id: 'projects', label: 'Proyectos', sub: '01' }, { id: 'about', label: 'Quiénes somos', sub: '02' }, { id: 'contact', label: 'Contacto', sub: '03' }, { id: 'deeper', label: 'El más allá', sub: '04 · DEEPER' }, ]; // Hex sizes (vmin units as numbers, used as `${n}vmin`) const MAIN = 34; // main hex height in vmin const DECO = 14; // large decorative const DECOS = 9; // small decorative // Pitch helpers for pointy-top hexagons const pitchX = (r) => Math.sqrt(3) * r; // horizontal distance between adjacent columns const pitchY = (r) => 1.5 * r; // vertical distance between adjacent rows // 4 main hexes in a 2×2 honeycomb grid const halfR = MAIN / 2; // radius (half-height) of a main hex const mainPositions = [ { x: -pitchX(halfR) * 0.5, y: -pitchY(halfR) * 0.5 }, { x: pitchX(halfR) * 0.5, y: -pitchY(halfR) * 0.5 }, { x: -pitchX(halfR) * 0.5, y: pitchY(halfR) * 0.5 }, { x: pitchX(halfR) * 0.5, y: pitchY(halfR) * 0.5 }, ]; // Decorative hexes — [col, row, size, opacity] // col/row multiplied by each hex's own pitch to place them const decoHexes = [ // top / bottom centers (sized like DECO) [0, -1.6, DECO, 0.50], [0, 1.6, DECO, 0.50], // left / right sides [-2.6, 0, DECO, 0.45], [ 2.6, 0, DECO, 0.45], // mid corners [-2, -1.6, DECOS, 0.35], [ 2, -1.6, DECOS, 0.38], [-2, 1.6, DECOS, 0.35], [ 2, 1.6, DECOS, 0.38], // outer fringe [-3.5, -0.6, DECOS, 0.22], [ 3.5, 0.6, DECOS, 0.22], [-3.2, 1.9, DECOS, 0.18], [ 3.2, -1.9, DECOS, 0.18], // center gap [ 0, 0, DECO, 0.22], ]; return ( <> {/* Fixed cosmic background */}
{Array.from({ length: 80 }).map((_, i) => { const x = (i * 53 + 7) % 400; const y = (i * 89 + 23) % 400; const r = 0.3 + ((i * 7) % 10) / 12; const op = 0.2 + ((i * 13) % 10) / 25; return ; })}
{/* Scroll driver — 220vh gives comfortable transition range */}
{/* Sticky viewport — clips overflow so honeycomb doesn't show during hero */}
{/* ── SCREEN 1 · HERO ── */}
SINZETA
SIN LÍMITES
COMING SOON
{/* Scroll indicator */}
SCROLL
SINZETA.COM · 2026
{/* ── SCREEN 2 · HONEYCOMB ── */}
0.5 ? 'auto' : 'none', }}> {/* Section header */}
SINZETA
EXPLORA EL ECOSISTEMA
{/* Hex grid — all positioned from the center of the viewport */} {/* Main hexes */} {mainPositions.map((pos, i) => { const sec = sections[i]; const isHovered = hoveredHex === sec.id; return (
setHoveredHex(sec.id)} onMouseLeave={() => setHoveredHex(null)} > {}} />
); })} {/* Decorative hexes */} {decoHexes.map(([col, row, sz, op], i) => { const r = sz / 2; const px = col * pitchX(r); const py = row * pitchY(r); return (
); })} {/* Footer hint */}
HOVER · EXPLORE
); } ReactDOM.createRoot(document.getElementById('root')).render();