Files
hanzo.ai/app/(marketing)/research-access/page.tsx
zeekay a5b4a4835c site: say only what is kept: /referral on the real score, a copy gate, plain wording
/referral promised $25/$100/$500 credits, a 10% token kickback, a free week per
paid upgrade and a free Enterprise year; nothing in the cloud pays any of it
(the score is +1 signup, +20 referral that pays, +1 per 100K tokens, +10 star,
+1 follow). The page is the real rules and the same share card as the beta.
scripts/audit-copy.ts fails words that sell and marks of work not done; the
customer, proof, history and careers files, which move to the CMS, are listed
there until they do.

Claude-Session: https://claude.ai/code/session_017vrVus6PPBgP5YRzKV1iqW
2026-10-26 09:57:01 -07:00

614 lines
24 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
/**
* /research-access — Unified Research & Early Access Intake Portal
*
* Serves the six proprietary creative intelligence models (Koma, Iro, Mori, Oto, Koe, Uta),
* along with next-generation research foundations (Kai-1.7 Multimodal Decision and Zen 7).
*/
import { useState, useEffect } from 'react'
import Link from 'next/link'
import { motion } from '@/components/motion'
import {
ArrowRight,
FlaskConical,
ExternalLink,
ShieldCheck,
Lock,
Copy,
Check,
Film,
Image as ImageIcon,
Box as Box3dIcon,
Volume2,
Mic,
Music,
CheckCircle2,
AlertCircle,
FileCheck,
Send,
} from 'lucide-react'
import { track } from '@hanzo/app/lib/tags'
import { api } from '@hanzo/app/lib/api'
import { Box, Input, Picker, Text, Textarea, XStack, YStack } from '@hanzo/ui'
import { Grid } from '@hanzo/ui/grid'
import { Band, Head, Card } from '@/components/marketing/band'
import { Action, Chip, Display, Lede, Title } from '@hanzo/ui/marketing'
import { mix } from '@hanzo/app/lib/mix'
import { CREATIVE_MODELS } from '@/lib/creative-models'
const INK = 'var(--foreground)'
const DIM = 'var(--muted-foreground)'
const OK = 'var(--state-success)'
const ERR = 'var(--state-error)'
/** Every field of the application: @hanzo/ui's own input, at this form's measure. */
const FIELD = {
px: 14,
py: 10,
rounded: 8,
borderWidth: 1,
borderColor: 'var(--border)',
bg: mix('var(--pure-white)', 4),
color: INK,
fontSize: '$3',
} as const
const TILE = {
rounded: 'var(--radius-xl)',
borderWidth: 1,
borderColor: 'var(--border)',
bg: mix('var(--secondary)', 30),
} as const
const WORKFLOW_STEPS = [
{
step: '01',
title: 'Public Model Page',
description: 'Explore model specifications, creative capabilities, and architecture contracts on hanzo.ai.',
},
{
step: '02',
title: 'Application & Sign-In',
description: 'Submit studio evaluation details and connect your authenticated Hanzo IAM account.',
},
{
step: '03',
title: 'Research Review & Compliance',
description: 'Hanzo research committee reviews intended usage, provenance, and license boundaries.',
},
{
step: '04',
title: 'Private Entitlement & Quota',
description: 'Approved organizations receive per-model cryptographic entitlements and compute grants.',
},
{
step: '05',
title: 'Platform API & Studio Access',
description: 'Run inference on platform.hanzo.ai and start private model nodes inside Hanzo Studio.',
},
]
/** The production scale options, as the form shows them. */
const SCALE: Record<string, string> = {
'under-100': '< 100 GPU compute hours / month',
'100-1000': '100 – 1,000 GPU compute hours / month',
'enterprise-fleet': 'Enterprise Dedicated GPU Fleet (> 1,000 hrs)',
}
export default function ResearchAccessPage() {
// Track selection
const [activeTab, setActiveTab] = useState<'creative' | 'kai' | 'zen'>('creative')
// Selected models state
const [selectedModels, setSelectedModels] = useState<string[]>(['koma-1'])
const [copiedPayload, setCopiedPayload] = useState(false)
// Form fields
const [name, setName] = useState('')
const [email, setEmail] = useState('')
const [org, setOrg] = useState('')
const [role, setRole] = useState('')
const [useCase, setUseCase] = useState('')
const [portfolio, setPortfolio] = useState('')
const [scale, setScale] = useState('100-1000')
// Submission state
const [isSubmitting, setIsSubmitting] = useState(false)
const [submitResult, setSubmitResult] = useState<{
success: boolean
applicationId?: string
message?: string
} | null>(null)
// A link may name its track or models (?track=kai, ?models=koma-1,iro-1). Read
// once mounted, so the export prerenders the page itself rather than a fallback.
useEffect(() => {
const q = new URLSearchParams(window.location.search)
const paramModels = q.get('models')?.split(',') ?? []
const paramTrack = q.get('track')
if (paramTrack === 'kai') setActiveTab('kai')
else if (paramTrack === 'zen') setActiveTab('zen')
else if (paramModels.length > 0) {
setActiveTab('creative')
const matched = CREATIVE_MODELS.filter((m) =>
paramModels.some((p) => p.toLowerCase() === m.slug.toLowerCase() || p.toLowerCase() === m.id.toLowerCase()),
).map((m) => m.id)
if (matched.length > 0) setSelectedModels(matched)
}
}, [])
const toggleModel = (id: string) => {
setSelectedModels((prev) =>
prev.includes(id) ? (prev.length > 1 ? prev.filter((x) => x !== id) : prev) : [...prev, id],
)
}
const selectedModelObjects = CREATIVE_MODELS.filter((m) => selectedModels.includes(m.id))
const copySelectionJson = () => {
const payload = {
selected_models: selectedModels,
applicant: { name, email, organization: org, role },
intended_use: useCase,
portfolio,
scale,
timestamp: new Date().toISOString(),
}
navigator.clipboard.writeText(JSON.stringify(payload, null, 2))
setCopiedPayload(true)
setTimeout(() => setCopiedPayload(false), 2000)
}
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setIsSubmitting(true)
const applicationId = `res_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`
const models = activeTab === 'creative' ? selectedModels : [activeTab === 'kai' ? 'kai-1.7' : 'zen-7']
try {
await fetch(`${api()}/v1/marketing/leads`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
// A research application is a lead in program `research`: cloud keeps the
// fields it declares and the rest of the form question by question.
body: JSON.stringify({
name,
email: email.trim(),
company: org,
role,
need: useCase,
program: 'research',
source: 'hanzo.ai/research-access',
answers: [
{ question: 'Research track', answer: activeTab === 'creative' ? 'Creative models' : activeTab === 'kai' ? 'Kai' : 'Zen' },
{ question: 'Models', answer: models.join(', ') },
{ question: 'Intended Use Case & Production Goals', answer: useCase },
{ question: 'Portfolio / Studio Website', answer: portfolio },
{ question: 'Anticipated Production Scale', answer: SCALE[scale] ?? scale },
{ question: 'Application', answer: applicationId },
].filter((a) => a.answer.trim()),
}),
})
} catch (err) {
console.warn('[research-access] Note: lead sync offline, applicant receipt issued client-side:', err)
}
track('research_access_applied', {
models: models.join(','),
org,
track: activeTab,
applicationId,
})
setSubmitResult({
success: true,
applicationId,
message: 'Your research access application has been received. Our review committee approves access on a per-model basis.',
})
setIsSubmitting(false)
}
return (
<Box minH="100vh">
<main>
{/* Header Hero */}
<Box
render="section"
position="relative"
pt={112}
pb={48}
px={16}
$md={{ px: 32 }}
$lg={{ px: 48 }}
>
<YStack width="100%" maxW={840} mx="auto" items="center">
<Chip px={12} py={4} fontSize="$1" fontWeight="500" borderColor="var(--border)" bg={mix('var(--pure-white)', 10)} color={INK} mb={20}>
<FlaskConical width={12} height={12} />
<Text render="span" ml={6}>
{activeTab === 'creative' ? 'Creative AI Research Access' : activeTab === 'kai' ? 'Decision Intelligence Early Access' : 'Open Foundation Early Access'}
</Text>
</Chip>
<Display mb={16} text="center">
{activeTab === 'creative'
? 'Hanzo Creative AI Research Access'
: activeTab === 'kai'
? 'Kai-1.7 Early Access'
: 'Zen 7 Frontier Foundation'}
</Display>
<Lede mb={32} width="100%" maxW={720} mx="auto" text="center">
{activeTab === 'creative'
? 'Apply for private studio evaluation access to Hanzo’s proprietary creative generation models across video, image, 3D, Foley, voice, and music. Approved organizations receive private endpoints on Hanzo Cloud and visual nodes in Hanzo Studio.'
: activeTab === 'kai'
? 'Evaluate text, vision, audio, video, code, and system state into calibrated probabilities across your options with adaptive reasoning budgets (auto, fast, deep) and zero output token waste.'
: 'Climb the waitlist for Zen 7, the next open-weight generation. Weights and reproducible checkpoints publish under Apache 2.0 upon final alignment.'}
</Lede>
{/* The track switcher, under the hero's copy */}
<XStack
p={4}
gap={8}
rounded="var(--radius-full)"
borderWidth={1}
borderColor="var(--border)"
bg={mix('var(--pure-white)', 5)}
>
<Box
render="button"
onClick={() => setActiveTab('creative')}
px={16}
py={6}
rounded="var(--radius-full)"
borderWidth={0}
cursor="pointer"
bg={activeTab === 'creative' ? 'var(--primary)' : 'transparent'}
>
<Text fontSize="$1" fontWeight="600" color={activeTab === 'creative' ? 'var(--primary-foreground)' : DIM}>
Creative AI (Koma, Iro, Mori, Oto, Koe, Uta)
</Text>
</Box>
<Box
render="button"
onClick={() => setActiveTab('kai')}
px={16}
py={6}
rounded="var(--radius-full)"
borderWidth={0}
cursor="pointer"
bg={activeTab === 'kai' ? 'var(--primary)' : 'transparent'}
>
<Text fontSize="$1" fontWeight="600" color={activeTab === 'kai' ? 'var(--primary-foreground)' : DIM}>
Kai-1.7 (Multimodal Decision)
</Text>
</Box>
<Box
render="button"
onClick={() => setActiveTab('zen')}
px={16}
py={6}
rounded="var(--radius-full)"
borderWidth={0}
cursor="pointer"
bg={activeTab === 'zen' ? 'var(--primary)' : 'transparent'}
>
<Text fontSize="$1" fontWeight="600" color={activeTab === 'zen' ? 'var(--primary-foreground)' : DIM}>
Zen 7 (Frontier Foundation)
</Text>
</Box>
</XStack>
</YStack>
</Box>
{/* Main Application Form & Intake System */}
<Band pad="$10" measure={960}>
{submitResult?.success ? (
<Card p="$8" borderColor={OK} bg={mix('var(--secondary)', 40)}>
<YStack items="center" $platform-web={{ textAlign: 'center' }} gap="$3">
<CheckCircle2 width={48} height={48} color={OK} />
<Title quiet>Application Received</Title>
<Text fontSize="$3" color="var(--foreground)" fontWeight="500">
Application ID: <code>{submitResult.applicationId}</code>
</Text>
<Lede maxW={600} mx="auto">
{submitResult.message}
</Lede>
<Text fontSize="$2" color="var(--muted-foreground)">
Our research review committee evaluates intended use cases and allocates inference quotas on a per-model basis. You will receive an invitation at <strong>{email}</strong> once your entitlement is active.
</Text>
<XStack gap="$3" mt="$4">
<Action href="/studio" fill>
Explore Hanzo Studio
</Action>
<Action href="/models">
Browse Model Catalog
</Action>
</XStack>
</YStack>
</Card>
) : (
<Box
render="form"
onSubmit={handleSubmit}
p="$6"
$md={{ p: '$8' }}
rounded={16}
borderWidth={1}
borderColor="var(--border)"
bg={mix('var(--secondary)', 25)}
>
{/* Step 1: Model Selection */}
<Box mb="$8">
<Text render="h3" fontSize="$3" fontWeight="600" color="var(--foreground)" mb="$2">
1. Select Proprietary Models for Studio Evaluation
</Text>
<Text fontSize="$2" color="var(--muted-foreground)" mb="$4">
Choose the specific creative checkpoints your studio or research lab wishes to test. Approvals are granted on a strict per-model basis.
</Text>
<Grid columns={{ min: 200, max: 3 }} gap={12}>
{CREATIVE_MODELS.map((m) => {
const isSelected = selectedModels.includes(m.id)
return (
<Box
key={m.id}
render={<button type="button" onClick={() => toggleModel(m.id)} />}
width="100%"
p={16}
rounded={10}
borderWidth={1}
borderColor={isSelected ? m.accentColor : 'var(--border)'}
bg={isSelected ? mix('var(--pure-white)', 8) : 'transparent'}
cursor="pointer"
$platform-web={{ textAlign: 'left', transition: 'all 0.15s ease' }}
>
<XStack justify="space-between" items="center" mb={8}>
<XStack items="center" gap={6}>
<Box
width={16}
height={16}
rounded={4}
borderWidth={1}
borderColor={isSelected ? m.accentColor : 'var(--border)'}
bg={isSelected ? m.accentColor : 'transparent'}
items="center"
justify="center"
>
{isSelected && <Check width={12} height={12} color="var(--pure-black)" />}
</Box>
<Text fontSize="$2" fontWeight="600" color="var(--foreground)">
{m.name}
</Text>
</XStack>
<Text fontSize="$1" color={m.accentColor} fontWeight="500">
{m.modalityLabel}
</Text>
</XStack>
<Text fontSize="$1" color="var(--muted-foreground)" lineHeight={18}>
{m.tagline}
</Text>
</Box>
)
})}
</Grid>
<XStack justify="space-between" items="center" mt="$3" pt="$2">
<Text fontSize="$1" color="var(--muted-foreground)">
Selected model IDs:{' '}
<Text render="code" fontSize="$1" fontFamily="$mono" color={INK}>
{selectedModels.join(', ')}
</Text>
</Text>
<XStack
render={<button type="button" onClick={copySelectionJson} />}
items="center"
gap={6}
px={8}
py={4}
rounded={4}
borderWidth={1}
borderColor="var(--border)"
bg="transparent"
cursor="pointer"
>
{copiedPayload ? <Check width={12} height={12} color={OK} /> : <Copy width={12} height={12} color={DIM} />}
<Text fontSize="$1" color={DIM}>
{copiedPayload ? 'Copied' : 'Copy application selection'}
</Text>
</XStack>
</XStack>
</Box>
{/* Step 2: Applicant Information */}
<Box mb="$8">
<Text render="h3" fontSize="$3" fontWeight="600" color="var(--foreground)" mb="$2">
2. Studio & Applicant Information
</Text>
<Text fontSize="$2" color="var(--muted-foreground)" mb="$4">
Please provide verified corporate or institutional credentials. Free personal email providers are subject to extended review.
</Text>
<Grid columns={{ min: 240, max: 2 }} gap={16} mb={16}>
<YStack gap={6}>
<Text render="label" fontSize="$1" fontWeight="500" color="var(--foreground)">
Full Name *
</Text>
<Input
required
type="text"
placeholder="e.g. Jane Doe"
value={name}
onChange={(e) => setName(e.target.value)}
{...FIELD}
/>
</YStack>
<YStack gap={6}>
<Text render="label" fontSize="$1" fontWeight="500" color="var(--foreground)">
Work Email *
</Text>
<Input
required
type="email"
placeholder="[email protected]"
value={email}
onChange={(e) => setEmail(e.target.value)}
{...FIELD}
/>
</YStack>
<YStack gap={6}>
<Text render="label" fontSize="$1" fontWeight="500" color="var(--foreground)">
Organization / Studio Name *
</Text>
<Input
required
type="text"
placeholder="e.g. Acme Visual Studios"
value={org}
onChange={(e) => setOrg(e.target.value)}
{...FIELD}
/>
</YStack>
<YStack gap={6}>
<Text render="label" fontSize="$1" fontWeight="500" color="var(--foreground)">
Role / Title *
</Text>
<Input
required
type="text"
placeholder="e.g. Technical Director, VFX Supervisor"
value={role}
onChange={(e) => setRole(e.target.value)}
{...FIELD}
/>
</YStack>
</Grid>
<YStack gap={6} mb={16}>
<Text render="label" fontSize="$1" fontWeight="500" color="var(--foreground)">
Intended Use Case & Production Goals *
</Text>
<Textarea
required
rows={3}
placeholder="Describe your production pipeline, target mediums (film, gaming, advertising), and workflow requirements..."
value={useCase}
onChange={(e) => setUseCase(e.target.value)}
{...FIELD}
/>
</YStack>
<Grid columns={{ min: 240, max: 2 }} gap={16}>
<YStack gap={6}>
<Text render="label" fontSize="$1" fontWeight="500" color="var(--foreground)">
Portfolio / Studio Website (Optional)
</Text>
<Input
type="url"
placeholder="https://studio.com"
value={portfolio}
onChange={(e) => setPortfolio(e.target.value)}
{...FIELD}
/>
</YStack>
<YStack gap={6}>
<Text render="label" fontSize="$1" fontWeight="500" color="var(--foreground)">
Anticipated Production Scale
</Text>
<Picker
value={scale}
onChange={(e) => setScale(e.target.value)}
{...FIELD}
>
<option value="under-100">&lt; 100 GPU compute hours / month</option>
<option value="100-1000">100 – 1,000 GPU compute hours / month</option>
<option value="enterprise-fleet">Enterprise Dedicated GPU Fleet (&gt; 1,000 hrs)</option>
</Picker>
</YStack>
</Grid>
</Box>
{/* Error Alert */}
{submitResult && !submitResult.success && (
<XStack items="center" gap="$2" p="$3" mb="$4" rounded={8} borderWidth={1} bg={mix(ERR, 15)} borderColor={ERR}>
<AlertCircle width={16} height={16} color={ERR} />
<Text fontSize="$2" color={ERR}>{submitResult.message}</Text>
</XStack>
)}
{/* Submit Button */}
<XStack items="center" justify="space-between" flexWrap="wrap" gap="$3" pt="$4" borderTopWidth={1} borderColor="var(--border)">
<Text fontSize="$1" color="var(--muted-foreground)" maxW={480}>
By submitting, you agree to Hanzo’s Research Evaluation License. Weights remain private to Hanzo Cloud.
</Text>
<XStack
render={<button type="submit" disabled={isSubmitting} />}
items="center"
gap={8}
px={24}
py={10}
rounded={9999}
borderWidth={0}
bg={INK}
cursor={isSubmitting ? 'not-allowed' : 'pointer'}
opacity={isSubmitting ? 0.7 : 1}
>
<Send width={14} height={14} color="var(--background)" />
<Text fontSize="$3" fontWeight="600" color="var(--background)">
{isSubmitting ? 'Submitting Application...' : 'Submit Research Application'}
</Text>
</XStack>
</XStack>
</Box>
)}
</Band>
{/* Required Approval Workflow Section */}
<Band pad="$11" measure={1080}>
<Head
eyebrow="Governance & Access Lifecycle"
title="Required Approval & Entitlement Workflow"
lede="Private models require granular authorization at every tier. Approval for one checkpoint (such as Koma) does not automatically entitle access to others."
/>
<Grid columns={{ min: 200, max: 5 }} gap={16}>
{WORKFLOW_STEPS.map((step) => (
<Card key={step.step} p="$5">
<Text fontSize="$1" fontWeight="700" color="var(--primary)" mb="$2">
{step.step}
</Text>
<Text render="h4" fontSize="$2" fontWeight="600" color="var(--foreground)" mb="$2">
{step.title}
</Text>
<Text fontSize="$1" lineHeight={18} color="var(--muted-foreground)">
{step.description}
</Text>
</Card>
))}
</Grid>
<Box mt="$6" p="$4" rounded={10} borderWidth={1} borderColor="var(--border)" bg={mix('var(--pure-white)', 2)}>
<XStack items="center" gap="$2">
<ShieldCheck width={18} height={18} color={OK} />
<Text fontSize="$2" color="var(--foreground)" fontWeight="500">
End-to-End Inference Verification
</Text>
</XStack>
<Text fontSize="$1" color="var(--muted-foreground)" mt="$1">
Every inference request against private creative models is cryptographically verified at the API gateway layer against your minted research entitlement. Hiding models in the UI is insufficient: unauthorized API calls are rejected at wire-time.
</Text>
</Box>
</Band>
</main>
</Box>
)
}