Files
hanzo.sh-native/LLM.md
Hanzo Dev 6c1f593a45 fix: render one page shell and self-host Geist
The page mounted two complete bodies: pages/Index wrapped Install (then named
Hero, itself a full page with its own fixed header and footer) in a leftover
template shell — a second fixed header at the same top/z-index that occluded
the first bar's links, plus a second footer carrying copy about container
solutions and a 2024 copyright. Install is the page; the shell and the unused
template components are gone, so the document now has one header and one
footer and every header link hit-tests to itself.

Geist named in CSS but absent from the bundle: the CDN @import it came from
404s, and an @import cannot place an @font-face in our own stylesheet. Ship
the variable woff2 from src/fonts so the served CSS carries the faces it
names, and move the theme into @theme in index.css so --font-sans feeds
preflight and the utilities from one place. The build asserts the CSS carries
@font-face, Geist, an emitted woff2, and no remote @import.

Deploy ran to GitHub Pages while hanzo.sh is served by the assets Worker, so
no push reached the live surface; deploy.yml now runs wrangler.

Drop the third-party editor script from a page that tells people to pipe a
shell, and the deps the removed components pulled in (CSS 63 -> 20 kB,
JS 380 -> 244 kB).

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-26 16:15:48 -07:00

2.2 KiB

hanzo.sh

The install surface. One page, one command: curl -fsSL hanzo.sh | bash.

Serving

hanzo.sh is a Cloudflare assets Worker (wrangler.toml, name hanzo-sh), not Pages and not GitHub Pages. .github/workflows/deploy.yml builds and runs wrangler deploy on push to main — that is the only path to production.

dist/index.html is a polyglot: a shell script whose HTML lives in a heredoc (scripts/build-polyglot.js). One byte stream serves both curl | bash and browsers, so no client sniffing can misfire. Consequence: the shell prefix precedes <!DOCTYPE html>, so the browser parses in quirks mode and keeps a short text node at the top of <body> (covered by the fixed header). Do not "fix" that by content-negotiating at the edge without a hard gate — serving HTML to a piped shell is the one unacceptable failure on this surface.

Structure

index.html          document shell
src/main.tsx        mount
src/Install.tsx     the page — header, install commands, footer. Exactly one of each.
src/index.css       Tailwind v4 entry: @font-face + @theme + base
src/fonts/          Geist Sans/Mono variable woff2, self-hosted
public/             served verbatim — install.sh and the /cli /mcp /dev /full shortcuts
scripts/            polyglot post-build

Theme lives in src/index.css (@theme), not a JS config. --font-sans / --font-mono feed both Tailwind's preflight and the font-sans / font-mono utilities from one place.

Fonts

Geist is self-hosted (src/fonts/*.woff2, bundled and hashed by Vite). A CDN @import was tried and could not work: the URL 404s, and an @import cannot put an @font-face in our own bundle. The build asserts the served CSS carries @font-face, Geist, an emitted .woff2, and no remote @import — a source fix that misses the bundle is not a fix.

Verify in a real browser, not with document.fonts.check() (it returns true with zero @font-face rules). Use CDP CSS.getPlatformFontsForNode and require isCustomFont: true; on a box with Geist installed system-wide that flag is the only thing separating our webfont from a system fallback.

Build & run

pnpm install
pnpm build     # vite build + polyglot
pnpm dev