// 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 */}
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( );