mirror of
https://github.com/zoo-apps/industries.git
synced 2026-10-30 14:57:03 +00:00
Adds three home compositions sharing the same investor narrative: - / (canonical) — restored old composition with Hero + zoo composite, Ecosystem, ZooLabsNarrative, ServicesOverview, ResearchHighlights, Leadership, TrustedBy, Contact. Adds polished motion (Reveal, Parallax wrappers, scroll-linked Hero drift), softer brutalist reset (rounded utilities now opt-in), and a Zen5 rainbow-gradient top banner. - /homepage1 — backup of the previous / composition (noindex). - /homepage2 — 10-slide deck with snap-mandatory CSS scroll snap, side-rail slide indicator, alternating brand-color slide washes, CSS-3D AI-coin scene behind the Hero (Zen5 family + Cloud / Network spokes, perspective + per-coin float keyframes, light blur), network-mesh edges, Foundation + Leadership + Traction + Access slides, plus the AI-native market-cap composite with NVIDIA as public-market comparable. - /homepage3 — editorial 'Quarterly' variant with serif display, masthead, drop cap, ornamental dividers, chapter framing, and a colophon footer. Wax-seal red accent on a cream paper surface. Other changes: - Navbar: drop rounded floating pill in favour of sharp transparent bar with a sharp backdrop-blur strip + border-b-2 black on scroll. - TopBanner: animated rainbow gradient background (300% width, background-position keyframe, prefers-reduced-motion aware). - Leadership / TeamMemberCard: rounded-full avatars (override the brutalist global border-radius reset via data-circle). - Ecosystem strip: render JPGs at /public/ecosystem/*.jpg with emoji fallback only when an image is missing (bear, drought, lake, eagle, forest, whale). - TheStack: each layer card is now a click target to its live domain (zenlm.org, zoo.cloud, zoo.network, zoo.fund, zoo.vote). - public/: new /hero/zooimg.png, /ecosystem/*.jpg, /pe/*.png. - Reveal / Parallax / ParallaxDivider / ParallaxBackground / CoinScene / SlideIndicator / SlideParallax / NetworkAnimation primitives under components/. Co-authored-by: Hanzo Dev <[email protected]>
219 lines
7.4 KiB
TypeScript
219 lines
7.4 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* Blurred 3D coin-network backdrop.
|
|
*
|
|
* Each AI model / family is a "coin" floating in CSS-3D perspective —
|
|
* a circular disc with a brand-coloured radial gradient and an embossed
|
|
* label. Coins float on independent translateZ + rotateY loops so the
|
|
* scene never settles into a static composition. Hairline SVG edges
|
|
* connect them into a network that suggests zoo.network's mesh.
|
|
*
|
|
* The whole container is ``filter: blur(...)`` + low opacity so the
|
|
* coins read as atmospheric depth, not foreground content. Foreground
|
|
* hero text in front stays razor-sharp because the blur is scoped to
|
|
* this container only.
|
|
*
|
|
* Everything animates on the compositor — ``transform`` and
|
|
* ``opacity`` only. ``prefers-reduced-motion`` short-circuits the
|
|
* float / spin keyframes so motion-sensitive visitors get a static
|
|
* blurred composition.
|
|
*/
|
|
|
|
// Coin roster: Zen5 family — Nano (edge), Eco (4B), Pro (8B), Max
|
|
// (1T+ frontier), Coder, plus product spokes (Network, Cloud, Bot)
|
|
// so the graph reads as the full zoo.network of AI, not one model
|
|
// line. Branded entirely under the Zoo / Zen umbrella.
|
|
const COINS: Array<{
|
|
label: string;
|
|
sub: string;
|
|
// Position as percentages of the scene viewport.
|
|
x: number;
|
|
y: number;
|
|
// Z depth in pixels (positive = closer to viewer).
|
|
z: number;
|
|
// Coin diameter in px.
|
|
size: number;
|
|
// CSS colour stop — uses brand-* vars.
|
|
color: string;
|
|
// Float keyframe alias.
|
|
floatKey: 1 | 2 | 3;
|
|
// Stagger offset (seconds).
|
|
delay: number;
|
|
}> = [
|
|
{ label: "ZEN5", sub: "FLAGSHIP", x: 50, y: 38, z: 30, size: 220, color: "var(--brand-yellow)", floatKey: 1, delay: 0.0 },
|
|
{ label: "PRO", sub: "ZEN5", x: 18, y: 30, z: -60, size: 160, color: "var(--brand-magenta)", floatKey: 2, delay: 0.6 },
|
|
{ label: "ECO", sub: "ZEN5", x: 82, y: 30, z: -40, size: 150, color: "var(--brand-green)", floatKey: 3, delay: 1.1 },
|
|
{ label: "NANO", sub: "ZEN5", x: 10, y: 68, z: -80, size: 130, color: "var(--brand-cyan)", floatKey: 1, delay: 1.6 },
|
|
{ label: "MAX", sub: "ZEN5", x: 90, y: 70, z: -50, size: 140, color: "var(--brand-blue)", floatKey: 2, delay: 2.0 },
|
|
{ label: "CODER", sub: "ZEN5", x: 32, y: 75, z: -30, size: 130, color: "var(--brand-red)", floatKey: 3, delay: 0.3 },
|
|
{ label: "NETWORK", sub: "ZOO", x: 68, y: 78, z: -100, size: 120, color: "var(--brand-blue)", floatKey: 1, delay: 1.3 },
|
|
{ label: "CLOUD", sub: "ZOO", x: 50, y: 85, z: -90, size: 110, color: "var(--brand-cyan)", floatKey: 2, delay: 0.9 },
|
|
];
|
|
|
|
// Edges between coins (network mesh). Indexed into COINS.
|
|
const EDGES: Array<[number, number]> = [
|
|
[0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7],
|
|
[1, 3], [1, 5], [2, 4], [2, 6], [3, 5], [4, 6], [5, 7], [6, 7],
|
|
];
|
|
|
|
const COIN_CSS = `
|
|
.coin-scene {
|
|
perspective: 1400px;
|
|
perspective-origin: 50% 40%;
|
|
transform-style: preserve-3d;
|
|
/* Light blur only — heavy blur turns circles into soft squares,
|
|
which is the visual artefact the brief was trying to avoid. */
|
|
filter: blur(4px);
|
|
opacity: 0.95;
|
|
}
|
|
.coin {
|
|
transform-style: preserve-3d;
|
|
will-change: transform;
|
|
}
|
|
/* Single-layer coin disc: radius-clipped circle with a metallic
|
|
radial gradient + inset highlights/shadows that imply 3D. No outer
|
|
rim ring (which renders as a square halo when blurred). */
|
|
.coin-disc {
|
|
position: absolute;
|
|
inset: 0;
|
|
border-radius: 9999px;
|
|
border: 2px solid rgba(0,0,0,0.6);
|
|
box-shadow:
|
|
0 18px 36px -10px rgba(0,0,0,0.35),
|
|
inset 0 12px 28px rgba(255,255,255,0.55),
|
|
inset 0 -14px 28px rgba(0,0,0,0.32);
|
|
}
|
|
.coin-hi {
|
|
position: absolute;
|
|
top: 8%;
|
|
left: 12%;
|
|
width: 38%;
|
|
height: 28%;
|
|
border-radius: 9999px;
|
|
background: radial-gradient(ellipse at 30% 30%,
|
|
rgba(255,255,255,0.7) 0%,
|
|
rgba(255,255,255,0) 70%);
|
|
filter: blur(2px);
|
|
pointer-events: none;
|
|
}
|
|
.coin-label {
|
|
position: absolute;
|
|
inset: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: #000;
|
|
font-weight: 900;
|
|
text-shadow: 0 1px 0 rgba(255,255,255,0.4);
|
|
}
|
|
.coin-label .coin-name {
|
|
font-size: 1.6em;
|
|
letter-spacing: 0.02em;
|
|
line-height: 1;
|
|
}
|
|
.coin-label .coin-sub {
|
|
margin-top: 0.35em;
|
|
font-size: 0.55em;
|
|
letter-spacing: 0.22em;
|
|
opacity: 0.7;
|
|
}
|
|
@keyframes coin-float-1 {
|
|
0%,100% { transform: translateZ(0) rotateY(0deg); }
|
|
50% { transform: translateZ(40px) rotateY(20deg); }
|
|
}
|
|
@keyframes coin-float-2 {
|
|
0%,100% { transform: translateZ(0) rotateY(0deg) rotateX(0deg); }
|
|
50% { transform: translateZ(-30px) rotateY(-25deg) rotateX(8deg); }
|
|
}
|
|
@keyframes coin-float-3 {
|
|
0%,100% { transform: translateZ(0) rotateY(0deg); }
|
|
33% { transform: translateZ(25px) rotateY(15deg); }
|
|
66% { transform: translateZ(-20px) rotateY(-10deg); }
|
|
}
|
|
@keyframes edge-pulse-3d {
|
|
0%,100% { opacity: 0.10; }
|
|
50% { opacity: 0.25; }
|
|
}
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.coin { animation: none !important; }
|
|
.net-edge3d { animation: none !important; }
|
|
}
|
|
`;
|
|
|
|
export default function CoinScene() {
|
|
return (
|
|
<>
|
|
<style dangerouslySetInnerHTML={{ __html: COIN_CSS }} />
|
|
|
|
<div className="coin-scene absolute inset-0 overflow-hidden pointer-events-none select-none">
|
|
{/* Edges layer — SVG positioned absolutely behind the coins. */}
|
|
<svg
|
|
viewBox="0 0 100 100"
|
|
preserveAspectRatio="none"
|
|
aria-hidden
|
|
className="absolute inset-0 w-full h-full"
|
|
>
|
|
{EDGES.map(([a, b], i) => {
|
|
const A = COINS[a];
|
|
const B = COINS[b];
|
|
return (
|
|
<line
|
|
key={`e${i}`}
|
|
className="net-edge3d"
|
|
x1={A.x}
|
|
y1={A.y}
|
|
x2={B.x}
|
|
y2={B.y}
|
|
stroke="#000"
|
|
strokeWidth="0.15"
|
|
style={{
|
|
animation: `edge-pulse-3d 6s ease-in-out infinite`,
|
|
animationDelay: `${(i % 5) * 0.7}s`,
|
|
}}
|
|
/>
|
|
);
|
|
})}
|
|
</svg>
|
|
|
|
{/* Coins layer */}
|
|
{COINS.map((c, i) => (
|
|
<div
|
|
key={c.label + i}
|
|
className="coin absolute"
|
|
style={{
|
|
left: `${c.x}%`,
|
|
top: `${c.y}%`,
|
|
width: c.size,
|
|
height: c.size,
|
|
transform: `translate3d(-50%, -50%, ${c.z}px)`,
|
|
animation: `coin-float-${c.floatKey} ${
|
|
10 + i * 0.6
|
|
}s ease-in-out infinite`,
|
|
animationDelay: `${c.delay}s`,
|
|
}}
|
|
>
|
|
{/* ``data-circle`` exempts these from the global brutalist
|
|
``border-radius: 0 !important`` reset in globals.css —
|
|
without it the discs render as squares regardless of the
|
|
inline ``9999px`` rule. */}
|
|
<div
|
|
data-circle
|
|
className="coin-disc"
|
|
style={{
|
|
background: `radial-gradient(circle at 32% 30%, color-mix(in oklab, ${c.color} 80%, #fff 20%) 0%, ${c.color} 40%, color-mix(in oklab, ${c.color} 65%, #000 0%) 75%, color-mix(in oklab, ${c.color} 40%, #000 35%) 100%)`,
|
|
}}
|
|
/>
|
|
<div data-circle className="coin-hi" />
|
|
<div className="coin-label">
|
|
<span className="coin-name">{c.label}</span>
|
|
<span className="coin-sub">{c.sub}</span>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</>
|
|
);
|
|
}
|