Files
zeekay 4ddb1c9ed7 landing: every figure is in the HTML, and the page reads a few KB to keep it
The landing drew Smarter, Faster, Cheaper and the plans only once their
reads answered: the whole research record (1.2 MB), the price list, the
model list and the plans, about 160 KB compressed, asked for after
hydration. On a slow phone the figures appeared some 45 s after the page.

The build now reads the slices those figures need and derives them with
the same functions the browser runs (lib/figures, scripts/figures.ts),
one file a figure under lib/data/figures. The hooks draw that from the
first render, so the export holds every figure and no "Reading" line,
then read the slices again once the page is idle and move a figure only
where the answer differs (lib/api/use useLive). A figure the record no
longer holds comes down; a read that fails keeps the build's.

The slices: one research read a board benchmark with its all and
vs-claude-code measures, the timing runs' p50s, the price-list rows the
boards join (by id, and by each system's name), the model list's rows for
Kai, the frontier LLMs and the LLM its call is timed beside, and the
plans. Lists are walked by their next cursor. Kai's speed and spend
(lib/home call, spend) read those two slices, so the landing never reads
the whole record or the whole model list.

e2e/unit/seed.spec.ts holds each slice to the whole read it replaced, and
the gates serve and narrow every read as the API does and wait for the
page's live reads before they look for a served figure.
2026-10-29 21:31:00 -07:00

201 lines
9.0 KiB
TypeScript

'use client'
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'
import { Check, RotateCcw } from 'lucide-react'
import { useI18n } from '@hanzo/i18n/react'
import { Button, Text, View, XStack, YStack, type GuiElement } from '@hanzo/ui'
import { More } from '@hanzo/ui/marketing'
import { Mark } from '@/components/models/Mark'
import { useCoding } from '@/hooks/useCoding'
import { range, times, LEVEL } from '@/lib/coding'
import { race, type Lane } from '@/lib/home'
import { Reading, Section, Win, node, useSeen, useStill } from './chrome'
import { Onward } from './label'
/**
* Hanzo Dev beside Claude Code on the same held-out repairs, from the research
* API's coding.repair runs (lib/coding): the build's board first, then the
* API's answer once the page is idle (hooks/useCoding).
*
* A REPLAY OF THE RECORDED TIMINGS, NOT A TRANSCRIPT. The runs store each
* side's median seconds a task, its model calls a task and its solved count;
* no per-task transcript is filed. So each window runs a clock and a bar for
* exactly the median the run records, at the speed it ran, and names the run
* it replays. Under reduced motion both stand at their last frame. Under the
* clocks, the paired speed over the tasks both solved and each path Hanzo Dev
* settled a task by that is a resolved gain, with its own speed and interval,
* as /benchmarks prints them; both solved counts only while Hanzo Dev solved
* more (lib/home `race`).
*
* In the reader's language, every sentence is one message with its figures as
* arguments; a clock, a speed and an interval drawn on their own keep their own
* order on a right-to-left page (`data-i18n-ltr`), and each bar grows from the
* start of the line.
*/
/** Seconds as the clock prints them. */
const secs = (v: number) => `${v.toFixed(2)} s`
function Track({ lane, solved, take, play, still }: { lane: Lane; solved: boolean; take: number; play: boolean; still: boolean }) {
const { t, dir } = useI18n()
const bar = useRef<GuiElement>(null)
const clock = useRef<GuiElement>(null)
const [ended, setDone] = useState(false)
const done = still || ended
const run = useRef<Animation | null>(null)
const isClaude = lane.name.toLowerCase().includes('claude')
const icon = isClaude ? <Mark org="claude" size={15} ink /> : <Mark org="hanzo" size={15} ink />
// The bar is a paused animation from the first frame, so it waits at zero without a style of its own.
useLayoutEffect(() => {
const el = node(bar)
if (!el || typeof el.animate !== 'function') return
const a = el.animate([{ transform: 'scaleX(0)' }, { transform: 'scaleX(1)' }], { duration: lane.seconds * 1000, easing: 'linear', fill: 'both' })
run.current = a
if (still) a.finish()
else a.pause()
return () => a.cancel()
}, [lane.seconds, still])
useEffect(() => {
const a = run.current
const face = node(clock)
if (!a || !face) return
if (still) {
face.textContent = secs(lane.seconds)
return
}
a.currentTime = 0
face.textContent = secs(0)
if (!play) return
a.play()
const reset = requestAnimationFrame(() => setDone(false))
let raf = 0
const tick = () => {
const t = Math.min(lane.seconds, Number(a.currentTime ?? 0) / 1000)
face.textContent = secs(t)
if (t < lane.seconds) raf = requestAnimationFrame(tick)
}
raf = requestAnimationFrame(tick)
a.onfinish = () => {
face.textContent = secs(lane.seconds)
setDone(true)
}
return () => {
cancelAnimationFrame(reset)
cancelAnimationFrame(raf)
a.onfinish = null
}
}, [take, play, still, lane.seconds])
return (
<Win title={lane.name} icon={icon} aside={done ? t('done') : play ? t('working') : t('ready')} slot={`lane-${lane.name}`}>
<YStack p={14} gap={12} $md={{ p: 20, gap: 14 }}>
<Text fontFamily="$mono" fontSize="$1" lineHeight="$1" color="var(--muted-foreground)">
{t('median time a task')}
</Text>
<XStack items="center" justify="space-between" gap={12}>
<Text ref={clock} fontFamily="$mono" fontSize="1.75rem" lineHeight="2rem" $md={{ fontSize: '2.5rem', lineHeight: '2.75rem' }} fontWeight="600" color="var(--foreground)" $platform-web={{ fontVariantNumeric: 'tabular-nums' }} data-clock data-i18n-ltr>
{secs(lane.seconds)}
</Text>
<View
aria-hidden
opacity={done ? 1 : 0}
width={28}
height={28}
rounded={9999}
bg="var(--secondary)"
items="center"
justify="center"
$platform-web={{ borderRadius: '9999px', transition: 'opacity 0.2s ease-in-out' }}
>
<Check size={16} strokeWidth={2.25} color="var(--foreground)" />
</View>
</XStack>
<View height={10} rounded={9999} borderWidth={1} borderColor="var(--border-strong)" overflow="hidden" bg="var(--muted)" $platform-web={{ borderRadius: '9999px' }}>
<View ref={bar} height="100%" rounded={9999} bg="var(--foreground)" $platform-web={{ borderRadius: '9999px', transformOrigin: dir === 'rtl' ? 'right center' : 'left center' }} />
</View>
<YStack gap={2} pt={4}>
{lane.calls != null ? (
<Reading label={t('model calls a task')}>
<bdi dir="ltr">{lane.calls.toFixed(1)}</bdi>
</Reading>
) : null}
{solved ? <Reading label={t('solved')}>{t('{solved} of {of}', { solved: lane.solved, of: lane.of })}</Reading> : null}
</YStack>
<Text fontFamily="$mono" fontSize="$1" lineHeight="$1" color="var(--muted-foreground)" $platform-web={{ overflowWrap: 'anywhere' }}>
{t('replay of run {run}', { run: lane.run })}
</Text>
</YStack>
</Win>
)
}
export default function Race() {
const { t } = useI18n()
const c = useCoding()
const r = useMemo(() => race(c), [c])
const [ref, seen] = useSeen(0.35)
const still = useStill()
const [take, setTake] = useState(0)
if (!r) return null
return (
<Section
id="race"
label="Coding.Tasks"
title={t('{speed} faster on the same coding tasks.', { speed: times(r.speed) })}
lede={t("Hanzo Dev and Claude Code were handed the same {n} coding tasks (single-fault repairs), one try each. Each clock replays that side's median time a task, at the speed it ran.", { n: r.base.of })}
>
<YStack gap={16}>
<View ref={ref} display="grid" gridTemplateColumns="minmax(0, 1fr) minmax(0, 1fr)" gap={8} $md={{ gap: 16 }} data-slot="race">
<Track lane={r.base} solved={r.solved} take={take} play={seen} still={still} />
<Track lane={r.ours} solved={r.solved} take={take} play={seen} still={still} />
</View>
<XStack justify="center" pt={4}>
<Button
size="sm"
variant="outline"
rounded={9999}
$platform-web={{ borderRadius: '9999px', display: 'inline-flex', alignItems: 'center', gap: '6px' }}
disabled={!seen && !still}
onPress={() => setTake((t) => t + 1)}
>
<RotateCcw size={13} aria-hidden />
{t('Replay race')}
</Button>
</XStack>
</YStack>
<XStack flexWrap="wrap" items="center" justify="space-between" gap={24}>
<YStack gap={6} maxW={720} flex={1} minW={260}>
<Text fontSize="$5" lineHeight="$5" color="var(--foreground)" data-figure="speed">
{t('{speed} faster over the {n} tasks both solved, {level} interval {range}.', { speed: times(r.speed), n: r.speed.n ?? '', level: LEVEL, range: range(r.speed) })}
</Text>
{r.paths.length ? (
<Text fontSize="$3" lineHeight="$3" color="var(--muted-foreground)">
{r.solved ? `${t('Claude Code solved {base} of {of}; Hanzo Dev {ours} of {all}.', { base: r.base.solved, of: r.base.of, ours: r.ours.solved, all: r.ours.of })} ` : ''}
{t('By how Hanzo Dev settled a task:')}
</Text>
) : null}
<YStack render="ul" $platform-web={{ listStyle: 'none', margin: 0, padding: 0 }} data-figure="paths">
{r.paths.map((p) => (
<XStack key={p.label} render="li" justify="space-between" flexWrap="wrap" columnGap={16} py={4} borderTopWidth={1} borderColor="var(--border)" data-path={p.label}>
<Text fontSize="$2" lineHeight="$2" color="var(--foreground)">
{t(p.n === 1 ? '{label}, {n} task' : '{label}, {n} tasks', { label: t(p.label), n: p.n ?? '' })}
</Text>
<Text fontFamily="$mono" fontSize="$2" lineHeight="$2" color="var(--muted-foreground)" $platform-web={{ fontVariantNumeric: 'tabular-nums' }} data-i18n-ltr>
{times(p)} ยท {LEVEL} {range(p)}
</Text>
</XStack>
))}
</YStack>
</YStack>
<XStack gap={16} items="center" flexWrap="wrap">
<More href="/benchmarks#coding-agent">
<Onward>{t('Every coding task and both runs')}</Onward>
</More>
</XStack>
</XStack>
</Section>
)
}