Files
zooqueen 75c4f1f641 One product answers with one name, route, command and docs page
The CLI lines on the product pages were written from the product name -- hanzo
dns zones, hanzo kms keys -- and several were not commands the binary has. So the
command moves into lib/product.ts, which assembles the rest from what is already
stated: the catalog names the product and its route, pages.json names what the
catalog does not carry, and products-metadata answers for docs, where null means
docs publishes nothing and the link drops.

Every CLI line in that table was run against the binary. A product absent from it
has no command and its page prints none; nothing composes a verb out of a name.
Both blocks that draw it import the Product type rather than declaring their own,
which leaves the table the only place a command can be written.

The catalog also moves out of package.json into pnpm-workspace.yaml, where pnpm
reads it, so the versions are stated once.
2026-09-06 23:18:24 -07:00

80 lines
4.0 KiB
TypeScript

'use client'
import { ArrowRight, Activity, Cpu, HardDrive, Network, Server, ShieldCheck, Terminal } from 'lucide-react'
import { ProductLanding } from '@/components/product/ProductLanding'
import { ProductFooter } from '@/components/products/ProductFooter'
/**
* Hanzo Visor, through the ONE product kit.
*
* The largest cluster left: TWELVE pages — engine, gateway, guard, ingress,
* jin, metrics, o11y, operator, sentinel, skills, telemetry, visor — at 85%+
* identical className sets, each a hero, a six-card grid and a call to action
* written out again. All twelve pass one typed props object to
* `ProductLanding`. See LLM.md, "Tailwind is NOT gone".
*
* EVERY WORD IS THE ONE THAT WAS HERE. ProductFooter came out of the final
* card's `max-w-3xl` wrapper, where it had been rendering narrower than on
* every other product page.
*/
export default function HanzoVisorPage() {
return (
<>
<ProductLanding
badge={"hanzoai/visor"}
badgeIcon={Server}
title={"Hanzo Visor"}
tagline={"Machines from several clouds, through one API"}
lede={"Launch a machine, attach a volume, open a console, tear it down — the same four verbs whether the hardware is DigitalOcean, AWS, Hetzner, Azure, Google Cloud, Aliyun, Lightsail, or a KVM host in your own rack. Every machine belongs to an organization, and that organization is read from the signed identity on the request, never from a field the caller filled in."}
ctas={[
{ label: "View on GitHub", href: "https://github.com/hanzoai" },
]}
what={{
title: "What you get for the price of one integration",
sub: "A machine is a machine. The provider is a field on it.",
pillars: [
{
icon: Cpu,
title: "One catalogue, GPUs included",
body: "Regions, sizes and GPU instances from each provider, cached and priced, read through the same call. Ask for what you want; Visor knows which provider can give it to you and what it will cost there.",
},
{
icon: HardDrive,
title: "Volumes and images",
body: "Attach and detach block storage, launch from a provider image or one of your own. Batch launches name themselves in sequence and group under the prefix, so a fleet is just machines and there is no second object to learn.",
},
{
icon: Network,
title: "Pools, and managed Kubernetes",
body: "Node pools group machines by shape and role. Managed Kubernetes clusters are provisioned the same way, so the cluster and the machines beside it are one inventory rather than two consoles.",
},
{
icon: Activity,
title: "Priced before it exists",
body: "A launch can run as a dry run: it returns the quote and spends nothing. A real launch is metered against the organization as it goes, per provider, so the bill is assembled from the same numbers the quote came from.",
},
{
icon: Terminal,
title: "A console in the browser",
body: "RDP, VNC and SSH reach the machine through a gateway and render in a tab — no client to install, no key to hand out, and no bastion of your own to keep patched. The session is a record, not just a connection.",
},
{
icon: ShieldCheck,
title: "Every action leaves a row",
body: "Who launched it, who opened a console, who destroyed it, under which organization and project. Authorization runs through the same grant calculus the rest of the estate uses, so a machine cannot be reached by anyone whose token does not cover it.",
},
],
}}
finalCta={{
title: "Get started with Hanzo Visor",
buttons: [
{ label: "View on GitHub", href: "https://github.com/hanzoai" },
],
}}
/>
<ProductFooter slug={"visor"} name={"Visor"} />
</>
)
}