mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-30 14:58:08 +00:00
Inline style objects became gui props (Box for a div, View or Text rendering the element for the rest, since Box styles only a div), raw colours and sizes became the design's tokens, the brand swatches read @hanzo/design's own values, and the project and creation hues moved to palette.json, which is data. The newsletter's subscribe button is the standard filled Action. connect-steps.tsx, which nothing imports, is deleted with the brand constants nobody read. Pages compared before and after at 1440x900 and 390x844: blockchain, brand, directory, projects, settings, unsubscribe identical; founder 0.03% of pixels; buying specialist's title snaps from 28 to the ramp's 26px and the newsletter's button is now filled. Claude-Session: https://claude.ai/code/session_017vrVus6PPBgP5YRzKV1iqW
601 lines
27 KiB
TypeScript
601 lines
27 KiB
TypeScript
'use client'
|
|
|
|
/**
|
|
* /blockchain — one key, every chain, and the tools an agent calls with it.
|
|
*
|
|
* The six section frames are `components/marketing/band`'s `Band` and `Head`;
|
|
* the type and the controls are `@hanzo/ui/marketing`; the inks, the
|
|
* tile, the mark disc and a card's two lines are `components/blockchain/surface`,
|
|
* where the pages under this route agree on them; the rest is gui props.
|
|
*
|
|
* A product card offers its "Get started" line only on approach (and on
|
|
* keyboard focus); nothing else about the card changes, because its two
|
|
* grounds were one colour in both themes. A capability head is a disclosure
|
|
* whose ground answers a pointer and adds no geometry.
|
|
*/
|
|
|
|
import React, { useState, type ReactNode } from "react";
|
|
import Link from "next/link";
|
|
import { motion } from "@/components/motion";
|
|
import {
|
|
Blocks,
|
|
Wallet,
|
|
CreditCard,
|
|
FileCode,
|
|
HardDrive,
|
|
Radio,
|
|
Search,
|
|
ArrowLeftRight,
|
|
Shield,
|
|
ArrowRight,
|
|
Check,
|
|
Database,
|
|
Globe,
|
|
Zap,
|
|
Lock,
|
|
Server,
|
|
Code,
|
|
ChevronDown,
|
|
ChevronUp
|
|
} from "lucide-react";
|
|
import { phrase } from "@hanzo/i18n";
|
|
import { useI18n } from "@hanzo/i18n/react";
|
|
import { Box, Pulse, Text, XStack, YStack } from '@hanzo/ui'
|
|
import { Grid } from '@hanzo/ui/grid'
|
|
import { Band, Head } from '@/components/marketing/band'
|
|
|
|
import { Card, CardBody, CardTitle, DIM, GROUND, INK, SOFT, Tile, ink, white } from '@/components/blockchain/surface'
|
|
import { Action, Chip, Display, Lede, Title } from '@hanzo/ui/marketing'
|
|
|
|
// Web3 capability categories
|
|
const CAPABILITIES = [
|
|
{
|
|
id: "nodes",
|
|
icon: Server,
|
|
title: phrase("Blockchain Nodes & Data"),
|
|
description: phrase("Read a chain without running a node for it"),
|
|
features: [
|
|
phrase("Multi-chain RPC endpoints (EVM, Solana, Cosmos, etc.)"),
|
|
phrase("Archive nodes for historical data access"),
|
|
phrase("WebSocket subscriptions for real-time events"),
|
|
phrase("Rate limiting and load balancing built-in"),
|
|
phrase("High availability with global distribution"),
|
|
],
|
|
},
|
|
{
|
|
id: "wallet",
|
|
icon: Wallet,
|
|
title: phrase("Wallet & Key Management"),
|
|
description: phrase("Where the keys live, and what has to happen before one signs"),
|
|
features: [
|
|
phrase("MPC (Multi-Party Computation) wallets"),
|
|
phrase("Hardware Security Module (HSM) integration"),
|
|
phrase("Policy-based transaction signing"),
|
|
phrase("Multi-sig support across chains"),
|
|
phrase("Custodial and non-custodial options"),
|
|
],
|
|
},
|
|
{
|
|
id: "payments",
|
|
icon: CreditCard,
|
|
title: phrase("On-Chain Payments"),
|
|
description: phrase("Take a stablecoin the way you would take a card"),
|
|
features: [
|
|
phrase("Stablecoin payment processing (USDC, USDT, DAI)"),
|
|
phrase("Native token support across chains"),
|
|
phrase("Payment links and checkout widgets"),
|
|
phrase("Automatic conversion and settlement"),
|
|
phrase("Invoice generation and tracking"),
|
|
],
|
|
},
|
|
{
|
|
id: "contracts",
|
|
icon: FileCode,
|
|
title: phrase("Smart Contract Management"),
|
|
description: phrase("Ship a contract to several chains and keep track of what you shipped"),
|
|
features: [
|
|
phrase("Contract deployment across multiple chains"),
|
|
phrase("ABI management and verification"),
|
|
phrase("Gas estimation and optimization"),
|
|
phrase("Event indexing and webhooks"),
|
|
phrase("Upgradeable proxy pattern support"),
|
|
],
|
|
},
|
|
{
|
|
id: "storage",
|
|
icon: HardDrive,
|
|
title: phrase("Decentralized Storage"),
|
|
description: phrase("Persistent, censorship-resistant data storage"),
|
|
features: [
|
|
phrase("IPFS pinning with global CDN"),
|
|
phrase("Arweave permanent storage integration"),
|
|
phrase("Filecoin deal management"),
|
|
phrase("NFT metadata hosting"),
|
|
phrase("Content-addressed file retrieval"),
|
|
],
|
|
},
|
|
{
|
|
id: "oracles",
|
|
icon: Radio,
|
|
title: phrase("Oracle Services"),
|
|
description: phrase("Bring off-chain data on-chain"),
|
|
features: [
|
|
phrase("Price feeds for DeFi applications"),
|
|
phrase("Custom data feeds and attestations"),
|
|
phrase("VRF (Verifiable Random Function)"),
|
|
phrase("Cross-chain message passing"),
|
|
phrase("Chainlink and custom oracle integration"),
|
|
],
|
|
},
|
|
{
|
|
id: "indexing",
|
|
icon: Search,
|
|
title: phrase("Blockchain Indexing"),
|
|
description: phrase("Ask a question a chain cannot answer in one call"),
|
|
features: [
|
|
phrase("Custom subgraph deployment"),
|
|
phrase("Real-time indexing and caching"),
|
|
phrase("Historical data aggregation"),
|
|
phrase("Cross-chain data unification"),
|
|
phrase("SQL and GraphQL query interfaces"),
|
|
],
|
|
},
|
|
{
|
|
id: "crosschain",
|
|
icon: ArrowLeftRight,
|
|
title: phrase("Cross-Chain Infrastructure"),
|
|
description: phrase("Bridge assets and data between chains"),
|
|
features: [
|
|
phrase("Token bridging with Wormhole, LayerZero"),
|
|
phrase("Cross-chain messaging protocols"),
|
|
phrase("Unified liquidity across chains"),
|
|
phrase("Chain abstraction for users"),
|
|
phrase("Multi-chain transaction batching"),
|
|
],
|
|
},
|
|
{
|
|
id: "compliance",
|
|
icon: Shield,
|
|
title: phrase("Compliance & Fiat"),
|
|
description: phrase("Enterprise compliance and fiat rails"),
|
|
features: [
|
|
phrase("KYC/AML integration"),
|
|
phrase("Transaction monitoring and screening"),
|
|
phrase("Fiat on/off ramp connections"),
|
|
phrase("Tax reporting and documentation"),
|
|
phrase("Regulatory-compliant custody"),
|
|
],
|
|
},
|
|
];
|
|
|
|
// Product pages - Core APIs
|
|
const PRODUCTS = [
|
|
// Core Infrastructure
|
|
{ id: "chains", name: phrase("Hanzo Chains"), description: phrase("Multi-chain RPC endpoints & infrastructure"), icon: Server, href: "/blockchain/chains" },
|
|
{ id: "directory", name: phrase("Chain Directory"), description: phrase("RPC endpoints, chain IDs and explorers for every network"), icon: Search, href: "/blockchain/directory" },
|
|
{ id: "indexer", name: phrase("Indexer"), description: phrase("Query blockchain data with GraphQL"), icon: Search, href: "/blockchain/indexer" },
|
|
{ id: "wallets", name: phrase("Smart Wallets"), description: phrase("ERC-4337 account abstraction wallets"), icon: Wallet, href: "/blockchain/wallets" },
|
|
{ id: "rollups", name: phrase("Rollups"), description: phrase("L2 scaling & rollup infrastructure"), icon: Blocks, href: "/blockchain/rollups" },
|
|
// Data APIs
|
|
{ id: "tokens", name: phrase("Token API"), description: phrase("ERC-20 balances, prices & metadata"), icon: Database, href: "/blockchain/tokens" },
|
|
{ id: "nft", name: phrase("NFT API"), description: phrase("NFT metadata, ownership & transfers"), icon: Blocks, href: "/blockchain/nft" },
|
|
{ id: "transfers", name: phrase("Transfers API"), description: phrase("Track token & NFT transfers"), icon: ArrowLeftRight, href: "/blockchain/transfers" },
|
|
// Trading & DeFi APIs
|
|
{ id: "prices", name: phrase("Prices API"), description: phrase("Real-time & historical price feeds"), icon: Database, href: "/blockchain/tokens" },
|
|
{ id: "dex", name: phrase("DEX API"), description: phrase("Swap routing & liquidity aggregation"), icon: ArrowLeftRight, href: "/blockchain/exchange" },
|
|
{ id: "oracle", name: phrase("Oracle API"), description: phrase("On-chain price oracles & data feeds"), icon: Radio, href: "/blockchain/oracle" },
|
|
// Realtime & Events
|
|
{ id: "webhooks", name: phrase("Webhooks"), description: phrase("Real-time blockchain event notifications"), icon: Radio, href: "/blockchain/webhooks" },
|
|
{ id: "websockets", name: phrase("Websockets"), description: phrase("Live blockchain data streaming"), icon: Radio, href: "/blockchain/websockets" },
|
|
// Account Abstraction
|
|
{ id: "bundler", name: phrase("Bundler API"), description: phrase("ERC-4337 UserOp bundling service"), icon: Blocks, href: "/blockchain/bundler" },
|
|
{ id: "gas", name: phrase("Gas Manager"), description: phrase("Sponsor gas for your users"), icon: Zap, href: "/blockchain/gas" },
|
|
{ id: "simulation", name: phrase("Simulation API"), description: phrase("UserOp & transaction simulation"), icon: Code, href: "/blockchain/bundler" },
|
|
// Debug & Development
|
|
{ id: "debug", name: phrase("Debug API"), description: phrase("Transaction tracing & debugging"), icon: Code, href: "/blockchain/explorer" },
|
|
{ id: "trace", name: phrase("Trace API"), description: phrase("Internal transaction traces"), icon: Search, href: "/blockchain/explorer" },
|
|
// Payments
|
|
{ id: "pay", name: phrase("Payments"), description: phrase("Crypto payments gateway"), icon: CreditCard, href: "/blockchain/pay" },
|
|
];
|
|
|
|
/** The two calls to action every block of this page closes on. */
|
|
function Actions() {
|
|
const { t } = useI18n();
|
|
return (
|
|
<>
|
|
<Action render="button" type="button" onClick={() => window.location.assign('/login')} fill>
|
|
{t('Try Hanzo')}
|
|
<ArrowRight width={16} height={16} data-i18n-mirror />
|
|
</Action>
|
|
<Action render="button" type="button" onClick={() => (window.location.href = '/pricing?tab=blockchain')}>{t('View Pricing')}</Action>
|
|
</>
|
|
)
|
|
}
|
|
|
|
/** A word in an outline on a tinted ground: the badges over the hero and the agent section. */
|
|
function Badge({ edge, ground, children }: { edge: string; ground: string; children: ReactNode }) {
|
|
return (
|
|
<Chip px={16} py={8} borderColor={edge} bg={ground}>
|
|
{children}
|
|
</Chip>
|
|
)
|
|
}
|
|
|
|
/** The diagonal white wash a framed block sits on. */
|
|
const WASH = { background: `linear-gradient(to bottom right in oklab, ${white(20)}, transparent)` } as const
|
|
|
|
const Blockchain = ({ agent }: { agent: ReactNode }) => {
|
|
const [expandedCapability, setExpandedCapability] = useState<string | null>(null);
|
|
const { t } = useI18n();
|
|
|
|
return (
|
|
<Box minH="100vh" $platform-web={{ color: 'var(--foreground)' }}>
|
|
|
|
{/* Hero Section */}
|
|
<Box render="section" position="relative" overflow="hidden" pt={96} pb={64} px={16} $md={{ px: 32 }}>
|
|
<Box position="relative" z="var(--z-raised)" width="100%" maxW={1152} mx="auto">
|
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.5 }}>
|
|
<Box mb={64} $platform-web={{ textAlign: 'center' }}>
|
|
{/* Live Badge */}
|
|
<Box mb={24}>
|
|
<Badge edge="var(--border)" ground={white(5)}>
|
|
<Pulse render="span" width={8} height={8} rounded={9999} $platform-web={{ backgroundColor: white(10) }} />
|
|
<Text fontSize="$2" lineHeight="1.1607rem" fontWeight="500" $platform-web={{ color: ink(70) }}>
|
|
{t('Now Available')}
|
|
</Text>
|
|
</Badge>
|
|
</Box>
|
|
|
|
<Display mb={24}>
|
|
{t('One API key, every chain.')}
|
|
<br />
|
|
{t('And an agent that can use it.')}
|
|
</Display>
|
|
|
|
<Lede mb={32} width="100%" maxW={672} mx="auto">
|
|
{t('RPC endpoints, token and NFT data, smart wallets, and webhooks — reached the same way whichever chain you are on. Reading a balance on Ethereum and reading one on Solana are the same call with a different argument, so the chain becomes a parameter instead of a rewrite. The same calls are exposed as tools, so an agent can make them too.')}
|
|
</Lede>
|
|
|
|
{/* CTA Buttons */}
|
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.5, delay: 0.1 }}>
|
|
<XStack flexWrap="wrap" gap={16} justify="center">
|
|
<Actions />
|
|
</XStack>
|
|
</motion.div>
|
|
<Text render="p" display="block" mt={16} fontSize="$1" lineHeight="0.9167rem" color={DIM}>
|
|
{t('Start on the free tier. No credit card required.')}
|
|
</Text>
|
|
</Box>
|
|
</motion.div>
|
|
|
|
{/* Visual Hero Element */}
|
|
<motion.div initial={{ opacity: 0, y: 40 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.6, delay: 0.2 }}>
|
|
<Box rounded="var(--radius-2xl)" borderWidth={1} borderColor="var(--border)" p={32} $md={{ p: 48 }} $platform-web={WASH}>
|
|
<Grid columns={{ min: 96, max: 6 }} gap={24}>
|
|
{[
|
|
{ icon: Server, label: phrase("Nodes") },
|
|
{ icon: Wallet, label: phrase("Wallets") },
|
|
{ icon: CreditCard, label: phrase("Payments") },
|
|
{ icon: FileCode, label: phrase("Contracts") },
|
|
{ icon: Database, label: phrase("Storage") },
|
|
{ icon: ArrowLeftRight, label: phrase("Bridges") },
|
|
].map((item, idx) => {
|
|
const Icon = item.icon;
|
|
return (
|
|
<motion.div
|
|
key={item.label}
|
|
initial={{ opacity: 0, scale: 0.8 }}
|
|
animate={{ opacity: 1, scale: 1 }}
|
|
transition={{ duration: 0.4, delay: 0.3 + idx * 0.05 }}
|
|
>
|
|
<YStack items="center" gap={8}>
|
|
{/* Half the tile at both sizes — 24 of 48, 32 of 64 —
|
|
so the mark steps with its box. */}
|
|
<Tile size={48} $md={{ width: 64, height: 64 }} rounded="var(--radius-xl)" borderWidth={1} $platform-web={{ borderColor: white(30) }}>
|
|
<Icon color={INK} width="50%" height="50%" />
|
|
</Tile>
|
|
<Text fontSize="$1" lineHeight="0.9167rem" color={DIM}>
|
|
{t(item.label)}
|
|
</Text>
|
|
</YStack>
|
|
</motion.div>
|
|
);
|
|
})}
|
|
</Grid>
|
|
</Box>
|
|
</motion.div>
|
|
</Box>
|
|
</Box>
|
|
|
|
{/* Performance Metrics */}
|
|
<Band pad="$10" measure={1152}>
|
|
<motion.div initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }}>
|
|
<Grid columns={{ min: 150, max: 4 }} gap={32}>
|
|
{[
|
|
{ value: phrase("One key"), label: phrase("Every chain"), detail: phrase("The chain is an argument") },
|
|
{ value: phrase("Archive"), label: phrase("Full history"), detail: phrase("Not just recent state") },
|
|
{ value: phrase("Push"), label: phrase("Webhooks and sockets"), detail: phrase("Instead of polling") },
|
|
{ value: phrase("Tools"), label: phrase("Agent-callable"), detail: phrase("The same calls you make") },
|
|
].map((stat, idx) => (
|
|
<motion.div
|
|
key={stat.label}
|
|
initial={{ opacity: 0, y: 20 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.4, delay: idx * 0.1 }}
|
|
>
|
|
<Box $platform-web={{ textAlign: 'center' }}>
|
|
<Text display="block" mb={4} fontSize="$8" lineHeight="1.95rem" fontWeight="700" color={INK}>
|
|
{t(stat.value)}
|
|
</Text>
|
|
<Text display="block" fontSize="$2" lineHeight="1.1607rem" fontWeight="500" color={INK}>
|
|
{t(stat.label)}
|
|
</Text>
|
|
<Text display="block" mt={4} fontSize="$1" lineHeight="0.9167rem" color={DIM}>
|
|
{t(stat.detail)}
|
|
</Text>
|
|
</Box>
|
|
</motion.div>
|
|
))}
|
|
</Grid>
|
|
</motion.div>
|
|
</Band>
|
|
|
|
{/* Products Section */}
|
|
<Band rule={false} pad="$12" measure={1152} ground="var(--background)">
|
|
<Head
|
|
title={t('The pieces')}
|
|
lede={t('Each one answers a question you would otherwise run a node to answer. They share a key, an address scheme, and a chain argument, so reaching for a second one costs you a line.')}
|
|
/>
|
|
|
|
<Grid columns={{ min: 260, max: 4 }} gap={16}>
|
|
{PRODUCTS.map((product, index) => {
|
|
const Icon = product.icon;
|
|
return (
|
|
<motion.div
|
|
key={product.id}
|
|
initial={{ opacity: 0, y: 20 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.4, delay: index * 0.03 }}
|
|
>
|
|
{/* A product card: the line under it is only OFFERED, on
|
|
approach — nothing else about the card changes. */}
|
|
<Card render={<Link href={product.href || "#"} />} group display="block" height="100%" p={20} rounded={16}>
|
|
<Tile size={40} mb={12}>
|
|
<Icon width={20} height={20} color={white(70)} />
|
|
</Tile>
|
|
<CardTitle>{t(product.name)}</CardTitle>
|
|
<CardBody>{t(product.description)}</CardBody>
|
|
<XStack
|
|
mt={12}
|
|
items="center"
|
|
gap={4}
|
|
opacity={0}
|
|
$group-hover={{ opacity: 1 }}
|
|
$group-focusVisible={{ opacity: 1 }}
|
|
$platform-web={{ transition: 'opacity var(--duration-fast) var(--ease-in-out)' }}
|
|
>
|
|
<Text fontSize="$1" lineHeight="0.9167rem" color={INK}>
|
|
{t('Get started')}
|
|
</Text>
|
|
<ArrowRight width={12} height={12} color={INK} data-i18n-mirror />
|
|
</XStack>
|
|
</Card>
|
|
</motion.div>
|
|
);
|
|
})}
|
|
</Grid>
|
|
</Band>
|
|
|
|
{/* Capabilities Section */}
|
|
<Band rule={false} pad="$12" measure={1152}>
|
|
<Head
|
|
title={t('What sits behind the key')}
|
|
lede={t('An app that touches a chain ends up needing most of this — a node to read from, somewhere to keep keys, a way to hear about a transaction that already happened. Open a group to see what it covers.')}
|
|
/>
|
|
|
|
<Grid columns={{ min: 300, max: 3 }} gap={16}>
|
|
{CAPABILITIES.map((capability, index) => {
|
|
const Icon = capability.icon;
|
|
const isExpanded = expandedCapability === capability.id;
|
|
return (
|
|
<motion.div
|
|
key={capability.id}
|
|
initial={{ opacity: 0, y: 20 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.4, delay: index * 0.05 }}
|
|
>
|
|
<Card overflow="hidden">
|
|
{/* A disclosure head whose ground answers a pointer, with no
|
|
geometry of its own. */}
|
|
<XStack
|
|
render={<button type="button" onClick={() => setExpandedCapability(isExpanded ? null : capability.id)} />}
|
|
items="flex-start"
|
|
gap={16}
|
|
width="100%"
|
|
p={20}
|
|
borderWidth={0}
|
|
bg="transparent"
|
|
cursor="pointer"
|
|
hoverStyle={{ bg: 'var(--white-06)' }}
|
|
$platform-web={{ textAlign: 'start', color: 'inherit', font: 'inherit' }}
|
|
>
|
|
<Tile size={40}>
|
|
<Icon width={20} height={20} color={INK} />
|
|
</Tile>
|
|
<Box grow={1} shrink={1} flexBasis="0%" minW={0}>
|
|
<XStack items="center" justify="space-between" gap={8}>
|
|
<CardTitle mb={0}>{t(capability.title)}</CardTitle>
|
|
{isExpanded ? <ChevronUp width={16} height={16} color={DIM} /> : <ChevronDown width={16} height={16} color={DIM} />}
|
|
</XStack>
|
|
<CardBody mt={4}>{t(capability.description)}</CardBody>
|
|
</Box>
|
|
</XStack>
|
|
|
|
{isExpanded && (
|
|
<motion.div initial={{ opacity: 0, height: 0 }} animate={{ opacity: 1, height: "auto" }} exit={{ opacity: 0, height: 0 }}>
|
|
<Box px={20} pb={20} borderTopWidth={1} borderColor="var(--border)">
|
|
<YStack render="ul" gap={8} mt={16}>
|
|
{capability.features.map((feature, idx) => (
|
|
<XStack key={idx} render="li" items="flex-start" gap={8}>
|
|
<XStack shrink={0} mt={2}>
|
|
<Check width={16} height={16} color={INK} />
|
|
</XStack>
|
|
<Text fontSize="$2" lineHeight="1.1607rem" $platform-web={{ color: SOFT }}>
|
|
{t(feature)}
|
|
</Text>
|
|
</XStack>
|
|
))}
|
|
</YStack>
|
|
</Box>
|
|
</motion.div>
|
|
)}
|
|
</Card>
|
|
</motion.div>
|
|
);
|
|
})}
|
|
</Grid>
|
|
</Band>
|
|
|
|
{/* Integration Section */}
|
|
<Band rule={false} pad="$12" measure={1152}>
|
|
<YStack gap={48} $lg={{ flexDirection: 'row', items: 'center' }}>
|
|
<Box grow={1} shrink={1} flexBasis="0%">
|
|
<motion.div initial={{ opacity: 0, x: -20 }} whileInView={{ opacity: 1, x: 0 }} viewport={{ once: true }}>
|
|
<Box mb={24}>
|
|
<Badge edge={white(30)} ground={white(10)}>
|
|
<Zap width={16} height={16} color={INK} />
|
|
<Text fontSize="$2" lineHeight="1.1607rem" fontWeight="500" color={INK}>
|
|
{t('Unified Platform')}
|
|
</Text>
|
|
</Badge>
|
|
</Box>
|
|
<Title quiet mb={16}>
|
|
{t('An agent with{br}{address}', { br: <br />, address: <Text color={DIM}>{t('an address.')}</Text> })}
|
|
</Title>
|
|
<Lede mb={24}>
|
|
{t('These calls are exposed as tools, so an agent can make them the way you would. It reads a balance, builds a transaction, and signs under whatever policy you put on the key — the same policy that governs a person. What an agent may spend is a rule on the wallet, not a promise in a prompt.')}
|
|
</Lede>
|
|
<YStack render="ul" gap={12} mt={14} mb={32} pl={40}>
|
|
{[
|
|
phrase("AI agents that can send on-chain transactions"),
|
|
phrase("Natural language smart contract interaction"),
|
|
phrase("Automated DeFi strategies with AI optimization"),
|
|
phrase("Cross-chain portfolio management"),
|
|
].map((item, idx) => (
|
|
<XStack key={idx} render="li" items="center" gap={12}>
|
|
<Tile size={24} rounded="var(--radius)">
|
|
<Check width={14} height={14} color={INK} />
|
|
</Tile>
|
|
<Text fontSize="$3" lineHeight="1.25rem" $platform-web={{ color: SOFT }}>
|
|
{t(item)}
|
|
</Text>
|
|
</XStack>
|
|
))}
|
|
</YStack>
|
|
</motion.div>
|
|
</Box>
|
|
|
|
<Box grow={1} shrink={1} flexBasis="0%">
|
|
<motion.div initial={{ opacity: 0, x: 20 }} whileInView={{ opacity: 1, x: 0 }} viewport={{ once: true }}>
|
|
<Card overflow="hidden" $platform-web={{ backgroundColor: 'color-mix(in oklab, var(--secondary) 80%, transparent)' }}>
|
|
<XStack items="center" gap={8} px={16} py={12} borderBottomWidth={1} borderColor="var(--border)" bg="var(--background)">
|
|
<XStack gap={6}>
|
|
{[0, 1, 2].map((k) => (
|
|
<Box key={k} width={12} height={12} rounded={9999} $platform-web={{ backgroundColor: white(10) }} />
|
|
))}
|
|
</XStack>
|
|
<Text ml={8} fontFamily="$mono" fontSize="$1" lineHeight="0.9167rem" color={DIM}>
|
|
hanzo-agent.ts
|
|
</Text>
|
|
</XStack>
|
|
{agent}
|
|
</Card>
|
|
</motion.div>
|
|
</Box>
|
|
</YStack>
|
|
</Band>
|
|
|
|
{/* Supported Chains */}
|
|
<Band rule={false} pad="$12" measure={1152}>
|
|
<Head
|
|
title={t('The chains')}
|
|
lede={t('Adding one is our work, not yours — the call you already wrote takes a different argument.')}
|
|
/>
|
|
|
|
<motion.div initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }}>
|
|
<XStack flexWrap="wrap" justify="center" gap={16}>
|
|
{[
|
|
// L1s
|
|
"Ethereum", "Solana", "Bitcoin", "Avalanche", "BNB Chain", "Cosmos",
|
|
// L2s & Rollups
|
|
"Arbitrum", "Optimism", "Base", "Polygon", "zkSync", "Scroll", "Linea", "Blast", "Starknet",
|
|
// Lux Ecosystem - All Chains
|
|
"Lux P-Chain", "Lux C-Chain", "Lux A-Chain", "Lux B-Chain", "Lux Z-Chain",
|
|
"Lux T-Chain", "Lux K-Chain", "Lux Q-Chain", "Lux D-Chain",
|
|
"Hanzo Network", "Zoo Network", "Pars Network",
|
|
// Other Networks
|
|
"Aptos", "Sui", "Sei", "Near", "Tron",
|
|
].map((chain) => (
|
|
<Chip
|
|
key={chain}
|
|
px={16}
|
|
py={8} borderColor="var(--border)" bg={GROUND} color={SOFT}
|
|
>
|
|
{chain}
|
|
</Chip>
|
|
))}
|
|
</XStack>
|
|
</motion.div>
|
|
</Band>
|
|
|
|
{/* CTA Section */}
|
|
<Band pad="$12" measure={896}>
|
|
<motion.div initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }}>
|
|
<Box
|
|
rounded="var(--radius-2xl)"
|
|
borderWidth={1}
|
|
p={32}
|
|
$md={{ p: 48 }}
|
|
$platform-web={{ ...WASH, borderColor: white(30), textAlign: 'center' }}
|
|
>
|
|
<Tile size={64} mb={24} mx="auto" rounded="var(--radius-2xl)">
|
|
<Blocks width={32} height={32} color={INK} />
|
|
</Tile>
|
|
<Title quiet mb={16}>
|
|
{t('Make the first call')}
|
|
</Title>
|
|
<Lede mb={32} width="100%" maxW={576} mx="auto">
|
|
{t('A key from the console reaches the RPC endpoints, the token and NFT data, the wallets and the webhooks. Pick a chain and read something. No credit card required.')}
|
|
</Lede>
|
|
|
|
<XStack mb={32} flexWrap="wrap" gap={16} justify="center">
|
|
<Actions />
|
|
</XStack>
|
|
|
|
<XStack flexWrap="wrap" justify="center" gap={24}>
|
|
{[
|
|
{ icon: Lock, text: phrase('Enterprise-grade security') },
|
|
{ icon: Globe, text: phrase('One key, every chain') },
|
|
{ icon: Zap, text: phrase('AI-native integration') },
|
|
].map(({ icon: Icon, text }) => (
|
|
<XStack key={text} items="center" gap={8}>
|
|
<Icon width={16} height={16} color={DIM} />
|
|
<Text fontSize="$2" lineHeight="1.1607rem" color={DIM}>
|
|
{t(text)}
|
|
</Text>
|
|
</XStack>
|
|
))}
|
|
</XStack>
|
|
</Box>
|
|
</motion.div>
|
|
</Band>
|
|
|
|
</Box>
|
|
);
|
|
};
|
|
|
|
export default Blockchain;
|