Long-scroll photo essay builder: index (poster tiles), reader (cinematic full-bleed scroll), builder (order image/text beats, publish). @hanzo/gui + @hanzo/iam PKCE + @hanzo/base (stories, blocks; org-scoped). Forked from hanzo-starter; provider stack, vite.config, auth and deploy contract intact.
4.3 KiB
Frame Story — agent notes
A real Hanzo app: long-scroll visual photo essays. Editors sequence
full-bleed image blocks and text passages; readers fall through them as a
cinematic vertical scroll. Built on the canonical Hanzo stack —
Vite + React 19 + @hanzo/gui (UI) + @hanzo/iam (auth) + @hanzo/base (data).
Forked from hanzo-apps/hanzo-starter; the provider stack, vite.config, auth
and deploy contract are unchanged from it. Keep every surface REAL — it must
build and run, no fabricated UI.
The app (three views)
- Index (
src/views/stories.tsx) — poster tiles of every published essay in your org. Click a poster to read it. - Reader (
src/views/story.tsx) — the cinematic scroll: a title card, then the ordered beats (full-bleed image / centred text passage) with slow rhythm and near-zero chrome, then an end card. - Builder (
src/views/builder.tsx) — pick or create an essay, edit its cover/byline, add & reorder image/text beats, publish. "Load the sample essay" seeds a complete, publishable piece from the bundled frames.
src/views/studio.tsx is the signed-in shell (tiny route state, no router).
src/views/landing.tsx is the signed-out title card. src/views/ui.tsx holds
the shared primitives (Caps, FullBleed, the Solid/Ghost/Plain buttons,
Field). src/lib/model.ts is the data model + the bundled SVG frames.
One way, decomplected
- Providers (
src/providers.tsx) mount in the canonical order every Hanzo surface ships:GuiProvider→IamProvider→BaseProvider.BaseProvidergets aBaseClientcarrying the IAM access token; it is rebuilt when the token changes (src/lib/base.tsbaseAs). That single seam makes everyuseQuery/useMutationorg-scoped to the signed-in user. - Env is one place (
src/env.ts), read fromimport.meta.env.VITE_*. The IAM client id isVITE_IAM_CLIENT_ID(fallbackhanzo-app); per-app clients are provisioned at deploy. - UI is one system —
@hanzo/guiprimitives only (no second kit, no Tailwind). The bundled cinematic frames are self-contained SVG, so nothing depends on the network to render.
Gotchas (do not regress)
@hanzo/guiunder Vite needs three things invite.config.ts(it is the Tamagui line; the in-browser builder runtime can't do this, which is the whole reason this ships as a real repo): (1) aliasreact-native→react-native-web, (2)defineprocess.env.TAMAGUI_TARGET/NODE_ENV/__DEV__, (3)dedupereact/react-dom/react-native-web. No Tamagui compiler, noone, no Expo — the optimizer is a perf pass, not a correctness one.@hanzo/guiprops are Tamagui LONGHAND:alignItems/justifyContent/backgroundColor/padding/alignSelf/borderRadius/textAlign— NOT theitems/justify/bg/p/self/rounded/textshorthands. Shorthands pass at runtime but FAILtsc.Buttonis a styled stack — no text props.color/fontWeight/fontSizeare NOT valid onButton(they failtsc). Set the frame onButtonand the label colour on a nestedText; that is exactly what theSolid/Ghost/Plaincompositions inui.tsxdo.ButtonusesonPress;Input/TextAreausevalue/onChangeText.- PKCE storage is
localStorage(not sessionStorage) so the verifier/state survive the round-trip to hanzo.id. schema.sqlis the data contract. It is thedatabaseSchemaDDL the deploy translates into Base collections (provisionBaseFromDDL). Base managesid/created/updated/owner/org; the provisioned rule is@request.auth.org_id = org. Keep it in lockstep withsrc/lib/model.ts.
Deploy contract (Hanzo Cloud)
- Static SPA:
npm run build→dist/, served at<slug>.hanzo.appfrom object storage. No server process. - On publish,
schema.sql→provisionBaseFromDDLcreates thestoriesandblockscollections (org-scoped, IAM-native). Runtime read/write is browser →VITE_HANZO_BASE_URLwith the IAM token. - IAM redirect registration is the one external requirement: the IAM client
(
VITE_IAM_CLIENT_ID, defaulthanzo-app) must allow this origin's/auth/callback.
Build
CI (.github/workflows/ci.yml) runs npm ci && npm run typecheck && npm run build — build-verification only, NEVER a container image (Hanzo Cloud owns
deploys; do not build images locally).