48 Commits
Author SHA1 Message Date
zooqueenandHanzo Dev 31ad1f039e Team is its own repo now
apps/team moved to hanzo-apps/team with its history, and builds there
against the published @hanzo/gui. It leaves the workspace list, the
lockfile, and the Written-at-Hanzo list in every NOTICE (ten names
become nine).


Co-authored-by: Hanzo Dev <[email protected]>
2026-09-23 15:53:45 -07:00
zeekayandHanzo Dev 2013e0ca86 Flatten themes without cloning them first
transformConfig deep-cloned the whole config and then replaced every
theme variable with its value, so the clone built roughly 300k objects
that were discarded in the same pass. Measured on the default config
(900 themes x 362 variables), the same transform: 3502/6722/5005ms
before, 202/241/29ms after, and the emitted hanzogui.config.json is
byte-identical. It was most of a cold compiler start.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 13:03:39 -07:00
zeekay ab754ba686 Every published package carries the license it is under
151 packages of Tamagui-derived code are on npm with no license text in
them. Checked four tarballs at 8.3.5 — @hanzogui/core, @hanzogui/web,
@hanzogui/shell and @hanzo/gui — and not one contains a LICENSE file.

MIT asks for one thing: "The above copyright notice and this permission
notice shall be included in all copies or substantial portions of the
Software." Shipping the code without it does not meet that.

The cause is mechanical rather than deliberate. npm includes a LICENSE
that sits in the package directory, and ours sits at the monorepo root,
where it reaches no tarball. So the license is now in each of the 153
publishable packages, and NOTICE beside it — that one npm will not take on
its own, so 152 manifests name it in `files`.

Verified by dry-run pack: 1.3kB LICENSE, 2.8kB NOTICE.

Already-published tarballs are immutable, so this corrects on the next
publish and not before.
2026-09-07 23:06:05 -07:00
zeekay 2de0604a52 v8.3.5 2026-09-07 02:06:21 -07:00
zeekay b424fd5871 v8.3.4 2026-09-06 18:54:23 -07:00
zeekay c4074a9dd0 v8.3.3 2026-09-06 13:48:41 -07:00
zeekay c183da5389 Drop webpack from the stack
The loader and the Next plugin only existed to drive webpack; Next runs
on Turbopack and Vite has its own plugin. kitchen-sink and the
integration app serve through vite, the optimizer suite drops the
webpack name, and its fixture packages join the workspace so a fresh
checkout links @my/ui.
2026-09-06 08:17:57 -07:00
zeekay 5a07cee3b1 v8.3.2 2026-09-05 03:11:37 -07:00
zeekayandHanzo Dev dab83dc050 Run the optimizer's native pass under Node again
Node's require never selects a package's react-native condition and
cannot load an ES module whose sources say a bare require, so the
extractor resolves that entry itself and translates such a file to
CommonJS as it loads. Directories are walked with the filesystem's
glob, negative numbers become AST through valueToNode, the swallowed
load error is named under DEBUG, and the optimize fixture is its
source again with the suite restoring it after each run.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-05 02:00:02 -07:00
zeekayandHanzo Dev af24fc040a Emit the native build as CommonJS
Native sources say a bare require, which Metro provides and an ES
module cannot; marking dist/native CommonJS like dist/cjs lets Node
load it as written, so the optimizer's native pass runs again. The
.cjs sibling answers there too, the CLI imports its commands, the
loader names its css file by the emitted name, and the extractor
tolerates a dependency whose tsconfig extends a preset it lacks.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-05 00:14:46 -07:00
zeekayandHanzo Dev 97529f7dab Alias react-native-web-lite to the .js the emit writes
Co-authored-by: Hanzo Dev <[email protected]>
2026-09-04 23:42:41 -07:00
zeekayandHanzo Dev 37fc897be5 Hand the extractor's require by its local name
Co-authored-by: Hanzo Dev <[email protected]>
2026-09-04 23:32:21 -07:00
zeekayandHanzo Dev 44a5d08e34 Name every relative import and drop the root-level shims
A relative import without its extension survives the emit unchanged
and nothing but a bundler can load it, and the .cjs and directory
shims at package roots pointed at emits no build produces. The exports
map is the one entry; the worker each emit runs is the worker of its
own kind.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-04 22:46:29 -07:00
zeekayandHanzo Dev deea53538d Load a bundled config the way each emit loads modules
The CommonJS pass rewrites a dynamic import into a require, which
cannot take the file URL the ESM path hands it, so the load goes
through here.ts and its .cjs sibling. create-gui reads its manifest
from the package root at run time, names its relative imports with
their extension, and imports opener instead of requiring it.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-04 22:27:17 -07:00
zeekayandHanzo Dev 278ded5f22 Refuse a CommonJS emit that declares what the wrapper provides
A top-level `const require` is legal in a script and a syntax error
inside Node's CommonJS wrapper, which is where the emit actually runs,
so the local createRequire alias is now `need` and the runner names
any file that declares require, module, exports, __filename or
__dirname.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-04 21:24:26 -07:00
zeekayandHanzo Dev 42bd70986b Ship source, ESM, CommonJS and types from each package
Every published manifest now states the same exports: types, the
native emit where the package builds one, ESM under import and
CommonJS under require, with src, types and dist in files. The nine
packages that read import.meta do so in one here.ts each, with a
here.cjs.ts sibling for the CommonJS emit; the stragglers on bun,
esbuild, plain tsc or hand-written shims build with the runner like
everything else, and the root-level .cjs shims that pointed at emits
no build produces are gone, as is the vite-plugin-cjs mirror.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-04 21:07:06 -07:00
zeekayandHanzo Dev fd796e3eb4 Emit CommonJS for every package
The CJS pass ran only where a manifest named a require entry, so an
ESM-only package could drift into the tree and a package marked
commonjs could carry ESM files. Now every package gets all three emits
from tsgo; a .cjs.ts sibling answers for the one file that needs
import.meta, and the CommonJS output is parsed as a script so a module
that cannot load there fails the build by name.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-04 21:07:03 -07:00
zeekay 834a904e48 Format with oxfmt 2026-09-04 09:04:51 -07:00
zeekay fdb08b51a7 Type-check the packages the old build skipped
esbuild emitted without looking, so a driver could return an animated
style the hook's type did not admit, read a styleState the core passes
but never declared, and widen a snapshot field on the way through a
helper. The Ink screen asked for props Ink never had, and the solito
test was already commented out of its index.
2026-09-03 18:02:50 -07:00
zeekay de489abd1e Resolve every sibling package through node_modules
The project files inherited the root paths map, so a package's typecheck
read its siblings' source instead of their published declarations and
failed on files that were never its own. An ESM-only manifest now names
no dist/cjs path under any condition, the native emit names its renamed
map, and the runner has a test of its own again.
2026-09-03 18:02:50 -07:00
zeekay 77e8398deb Build every package with the TypeScript compiler alone
Babel and esbuild were never here for TypeScript. Babel carried the static
optimizing compiler and one plugin that appended extensions to esbuild's
emitted imports; source now names its own extensions and the compiler rewrites
them on emit. A sixty-line runner replaces the tool: an ESM emit with
declarations, a CommonJS emit where a manifest states a require entry, and a
native emit where a .native sibling takes its sibling's name. The compiler
packages keep Babel as their own substrate; nothing else runs over the code.
Eighteen packages still carry type errors the previous tool never checked.
2026-09-03 17:14:57 -07:00
zeekay 9f8d7c440f Align the build on Babel 8 and TypeScript 7 fixtures
Nothing in the repo declared Babel 7; the root override pinned it while every
package asked for 8. The fixture tsconfigs named downlevelIteration, which
TypeScript 7 removed, and the base-url flag named an option that no longer
exists.
2026-09-03 16:48:05 -07:00
zeekay 0243d68060 State a version once
A version written into a manifest is written into every manifest that wants it,
which is how eslint came to exist in a hundred and four forms across this estate
and how a package came to resolve twice at run time. The catalog moves the number
out of the manifest: a manifest names the package, the workspace names the
version.

Four are held below their latest because the newer release cannot be used, and
the reason is recorded rather than the version alone: @noble/hashes 2 renamed
every subpath the web3 stack imports, @splinetool/runtime 2 depends on a package
that was never published, @dynamic-labs 5.4.1 the same, and react-resizable-panels
3 points its types condition at the bundle.
2026-08-29 18:13:47 -07:00
zeekay 56fc65d9ce v5 names what it re-exports, so the names survive
@hanzogui/config/v5 starred both @hanzogui/themes/v5 and ./v5-base, and
v5-base re-exports a dozen names it takes from themes/v5 — createThemes,
tokens, the palette helpers, the theme types. ESM calls a doubly-starred name
ambiguous and omits it rather than picking one, so every shared name silently
left the module: `import { tokens } from '@hanzogui/config/v5'` compiled and
resolved to undefined.

It ships as a patch in at least one consumer, which is the wrong home for it —
a fix in a patch file is a fix exactly one app gets, and only until its
overrides drift. So v5 now names the nine things themes/v5 carries that
v5-base does not, and everything they share arrives through v5-base, which is
the module that already curates it.

8.3.1.
2026-08-28 14:23:46 -07:00
zeekay 1620fff61e drop Inter and Geist from the docs, the artifacts and the snapshot
The estate renders in Zen, and the config sources here already did — but the
surfaces that teach the config had not moved with them. Every createFont example
in the docs still named Inter, so a reader copying one out wrote an app in a face
we do not ship, and the Expo guide sent them to @hanzogui/font-inter, a package
that does not exist in this repo at all; the one that does is @hanzogui/font-zen.

The tracked .gui configs and the two public/hanzogui.css files were stale output.
The compiler writes .hanzogui/hanzogui.config.json now and the apps emit
hanzogui.generated.css, so nothing produced or read either set any more; they had
simply frozen in place with the pre-Zen families still in them, and .gitignore had
already been taught to ignore .gui without the files being untracked to match.

The babel native snapshot recorded fontFamily "Inter" for the same reason. The
compiler emits "Zen" today — the snapshot was just never re-run.
2026-08-28 11:19:40 -07:00
zeekay f0fc7f0a04 v8.3.0 2026-08-27 08:06:19 -07:00
zeekay e83cb58508 v8.2.1 2026-08-25 13:28:47 -07:00
zeekayandHanzo Dev ffb28707a2 v8.2.0
Co-authored-by: Hanzo Dev <[email protected]>
2026-08-24 11:47:43 -07:00
zeekayandHanzo Dev 56e004e4b2 feat(fonts): Zen only — delete the nine faces that were not ours
The kit shipped ten typefaces. One is ours.

Deleted: font-inter, font-silkscreen, font-cherry-bomb, font-nohemi,
font-dm-sans, font-dm-serif-display, font-fira-mono, font-glusp, font-munro.
Six of those had no dependent in the workspace at all. font-zen stays, and so do
font-size, get-font-sized and font, which size and register rather than name a
face. Published versions remain on the registry, so anything pinned to one keeps
resolving.

@hanzogui/config's DEFAULT entry built heading and body from Inter — v4 was
already system fonts and v5 already Zen, so an app on the default got a face
nobody chose. It builds from Zen now. dev-config, which drives gui.hanzo.ai, was
worse: Inter for text, Berkeley Mono for code, plus Cherry Bomb and Silkscreen.
Every size, weight, letter-spacing and transform value is unchanged — only the
faces moved.

The pixel ROLE was worth keeping and only its face was borrowed, so font-zen
gained Zen Pixel Square (createZenPixelFont, --font-zen-pixel-*) and the token is
`$pixel`. `$silkscreen` and `$cherryBomb` are gone across ~35 call sites. Cherry
Bomb had no role of its own and no Zen counterpart, so it is deleted rather than
substituted.

gui.hanzo.ai now self-hosts three Zen files in place of four foreign ones — one
variable file per family instead of a weight per request — and its OG-image
route renders cards in the same faces as the pages they link to. The Inter,
Berkeley, Silkscreen and glusp binaries are gone from public/fonts, including an
otf directory of 20 Inter cuts.

Native is honestly short: @hanzo/font ships woff2 and react-native wants
otf/ttf, so the expo starter and kitchen-sink's native entry load no custom face
and say why, rather than keeping Inter because it happened to be there.

bun install 0 · build 161/161 · typecheck passed.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-24 11:44:08 -07:00
zeekay c351006e1d vite: a dependency that renders is bundled, so telemetry works under SSR 2026-08-17 08:35:23 -07:00
zooqueen 7d00280456 the formatter was failing on files nobody wrote
gui's whole CI lane has been red since Aug 5 and the cause was `oxfmt --check`
inside `bun run lint`, which the `Test` step reaches about eighty seconds in.
Nine authored files had drifted from the format — mechanical, no behaviour — and
two more were machine-written.

Those two are the real finding. The generated per-app gui config moved from
`.hanzogui/` to `.gui/` and `.gitignore` did not follow it, so every app's
generated config sat untracked-but-unignored. The formatter checks what git does
not ignore, so a gate that exists to keep AUTHORED code consistent was failing on
an esbuild bundle. `.gui` is ignored now, beside the old name.

`bun run check` and `bun run lint` both exit 0.
2026-08-14 01:48:09 -07:00
zeekayandHanzo Dev 89b9132c26 v8.1.1
Co-authored-by: Hanzo Dev <[email protected]>
2026-08-05 19:27:01 -07:00
zeekayandHanzo Dev 81e9a5f82b feat(compiler): extractPackages replaces the blanket node_modules skip, so an app can name its design system
Co-authored-by: Hanzo Dev <[email protected]>
2026-08-05 16:48:36 -07:00
Gui Release 85519508c8 v8.1.0 2026-08-05 02:20:37 +00:00
zeekayandHanzo Dev 8df6f77162 test: regenerate the two snapshots the transplant left on upstream's fonts and pre-data-slot markup
Co-authored-by: Hanzo Dev <[email protected]>
2026-08-04 17:09:40 -07:00
zeekayandHanzo Dev 74b6762d36 fix(static): don't die when the app's typescript has no program API (7.x)
Co-authored-by: Hanzo Dev <[email protected]>
2026-08-04 12:25:08 -07:00
zeekayandHanzo Dev cfae0a1c37 fix(loader): the Next plugin attached the compiler to nothing on Next 16
Co-authored-by: Hanzo Dev <[email protected]>
2026-08-04 12:19:45 -07:00
zeekayandHanzo Dev dd403681c1 fix(loader): the ESM build looked for a css loader filename it never emits
`withGui()` could not be loaded from a .mjs next.config at all. Requiring the
plugin threw MODULE_NOT_FOUND on './css.js' before Next had read a single line
of config, so the static-extraction path was unreachable and apps fell back to
shipping the whole atomic sheet inline — 350 KB re-sent with every document.

The candidates were './css.cjs', './css.esm', './css.js'. No build has ever
written a css.esm or a css.js. The CJS build emits css.cjs and got lucky on the
first try; the ESM build emits css.mjs, which was not on the list, so all three
missed and the last one threw. Ask for the two filenames that actually exist,
and say so plainly if neither is there instead of surfacing a resolver error
from a file nobody meant to name.

Same shape as the bug this repo keeps shipping: a reference to something that
was never authored, green in every build that does not exercise it.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-04 11:22:59 -07:00
zeekayandHanzo Dev 33b80fe28d chore(build): stop tracking generated declarations, the build emits them
Co-authored-by: Hanzo Dev <[email protected]>
2026-08-04 01:47:01 -07:00
zeekayandHanzo Dev ed3e545e34 release: 8.0.1 for the closure the undeclared-sibling fix had to move
The six manifest fixes are only reachable if every package that pins one
of them moves too: intra-workspace deps publish as exact versions, so
@hanzo/[email protected] asks for [email protected] by number and would keep resolving
the broken copy no matter what 8.0.1 said. Walking the exact-pin edges
back from the six gives 76 packages, all bumped here to the versions now
on npm.

Published from the 8.0.0 release point (15c59decd) rather than this
branch, so the patch carries the manifest fix and nothing else — main has
since gained the Geist typeface and the brand themes, which are features
and do not belong in a patch. Source for the six is identical between the
two points; 625 of the published packages diff clean against the release
point, and the 17 that do not are the hanzogui -> @hanzo/gui rename that
8.0.0 shipped half-applied.

Versions recorded here so the next release computes from what exists.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-03 11:02:10 -07:00
zeekayandHanzo Dev 907cf6bbea style: oxfmt the repo
Co-authored-by: Hanzo Dev <[email protected]>
2026-08-02 10:43:58 -07:00
zeekayandHanzo Dev eff21b84fa white-label brand themes: hanzo, lux, zoo, pars
Ports the brand work from hip-0111-iam onto the current lineage. brands.ts
is the whole definition — one data row per brand, accent hue plus a 12-step
ramp reusing the audited Radix scales, so nothing downstream hardcodes a
brand color.

The branch wired this into v4-default.ts, which is DEAD in this tree
(nothing imports it). The live path is themes.tsx -> generated-new.ts, built
from themes-new.ts, so the brands are registered there instead: each becomes
a palette through the same getColorPalette() as every built-in color, then a
child theme, so <Theme name="lux"> behaves exactly like <Theme name="blue">.

generated-new.ts is the ACTIVE theme set but nothing regenerated it — there
was no script, so its source could drift silently. Added generate:new.

Three defects had to be fixed for that script to run at all:

  @hanzogui/colors is "type": "module", so its legacy/*.js CommonJS compat
  shims (for metro, which ignores exports maps) were being evaluated as ES
  modules and threw "require is not defined in ES module scope". A scoped
  package.json marks that directory commonjs — the shims keep working and
  Node can load them.

  v3-themes.ts read color.blue4Light / color.blue4Dark; that object holds only
  the white/black ramps and never had those keys, so the brand color was
  undefined at runtime. Now reads the blue scale off colorTokens.

  themes-new.ts exceeded tsc's type serialization limit (TS7056) once the
  brand children were added, so its export is annotated.

2112 themes build, light_/dark_ for all four brands. 171/171.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-30 22:38:37 -07:00
zeekayandHanzo Dev 0b6d91258a restore the desktop app and @hanzogui/tauri the transplant left behind
apps/desktop survived the transplant as FOUR files, all of them generated
Tauri schemas under src-tauri/gen — the manifest, Cargo.toml, build.rs,
icons and capabilities that produce them were gone, so the desktop surface
existed only as its own build output. pkgs/tauri (TitleBar, isTauri,
shortcuts, system, window) was absent entirely.

Both come back from hip-0111-iam, which is where the work actually lives.
The 2.0G src-tauri/target is excluded because the restore brings the app's
own .gitignore with it — the same file whose absence let 3,859 Rust
artifacts into a commit earlier.

Carried onto the current lineage: the umbrella rename (hanzogui ->
@hanzo/gui) reached their manifests, and tauri's scripts called gui-build,
whose symlink is a stale leftover of the old lineage — every other package
in the tree calls hanzogui-build.

171/171 build.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-30 22:27:00 -07:00
zeekayandHanzo Dev 2c1c376ace release: 8.0.1 for the three packages whose dependency edges moved
next-plugin now needs @hanzogui/loader, logo and demos need @hanzo/gui.
Their 8.0.0 releases point at names that cannot exist on the registry, so
they are superseded rather than amended — a published version is immutable.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-30 20:35:14 -07:00
zeekayandHanzo Dev 751ef5c778 rename the framework to @hanzo/gui and the loader to @hanzogui/loader
Both old names are owned by a different npm account (artemis-prime), so
publishing them returns 403 — which is how this surfaced: the 8.0.0 run
shipped @hanzogui/logo and @hanzogui/demos depending on [email protected], a
version that cannot be published and therefore does not exist. Those two
were uninstallable.

@hanzo/gui and @hanzogui/* are ours, so the framework now carries the name
it is imported by everywhere downstream, and the loader moves under the
scope we control.

The rewrite is limited to package references. `DEBUG?.startsWith('hanzogui')`
is a log-namespace filter and join(dir, 'hanzogui') is a path — rewriting
either would change behaviour, so both are untouched.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-30 20:23:18 -07:00
zeekayandHanzo Dev 8556db6732 release: converge the gui lineage on 8.0.0
Aligns @hanzogui/* and the four unscoped gui packages with @hanzo/ui@8,
which is already on the 8.x line. @hanzo_network/* and @hanzo/booker keep
their own version streams — they are not part of this framework's lineage.

The lockfile is regenerated deliberately: bun resolves workspace:* from it
at publish time, so bumping versions without re-resolving would have
published 8.0.0 packages whose deps pin 2.6.0 — versions never published
under this scope, so every install would 404.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-30 19:56:20 -07:00
zeekayandHanzo Dev 38a546e67c restore @hanzo_network packages and team app dropped by the transplant
The transplant rebuilt the tree on upstream tamagui and carried our own
packages forward by hand, which silently lost seven @hanzo_network/*
packages and apps/team — 735 files with no other home in the workspace.
They are back at the tip of the old lineage's content.

pkgs/ai is NOT restored: @hanzo/ai is published from hanzo-js/ai, so a
copy here would be the duplicate we are trying to avoid.
templates/expo-router is NOT restored: apps/starters/expo-router already
declares that exact package name upstream.

Also fixes a rebrand defect: the blanket tamagui->hanzogui rule rewrote
upstream's GitHub path into github.com/hanzogui/hanzogui, a repo that has
never existed, and it shipped in repository.url for every published
package. The transform now maps the remote to hanzoai/gui and repairs a
tree already branded wrong, so a future sync cannot reintroduce it.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-30 19:53:12 -07:00
zeekayandHanzo Dev 69c6e860d7 transplant onto tamagui v2.6.0, brand as a re-runnable transform
This repo could never sync. There was NO merge-base with tamagui — 372 commits
here against 15,791 there, unrelated histories — because it began as a
copy-paste rebrand with a flattened layout. Every "sync" since was a hand
re-application that drifted, which is why the tree sat on 7.3.1 while upstream
shipped fixes we then rediscovered by hand.

This commit's PARENT IS TAMAGUI. A future sync is `git merge tama/main` then
`node scripts/rebrand.mjs` — a real merge, because the history is now shared.

174 packages: 166 upstream, our 8 restored (chrome, shell, telemetry, recipes,
get, font-geist-{sans,mono}, @hanzo/booker), bento-get gained. 170/170 build.

Our patches to files UPSTREAM ALSO OWNS are carried, which the package-level
delta missed and which was where the value actually was:
  - useMedia's server snapshot (`initState ?? getMedia()`). Upstream still
    returns undefined there, so every Tamagui Dialog kills a prerender — the
    exact crash hanzo.app spent a day on.
  - data-slot on web host nodes, absent upstream entirely.
Both applied ONTO upstream's newer files (it rewrote useMedia +150/-63 and
createComponent +160/-55), marked `PATCH (ours, carried across the transplant)`.

Seven traps are encoded in scripts/rebrand.mjs, each found by a gate:
skip itself and lockfiles; special-case the double-branded names in BOTH scoped
and bare form; map path strings, not just paths; drop a level for the flattened
group; check disk rather than a stale index.

Rust build artifacts are NOT committed. An earlier draft of this commit swept
apps/desktop/src-tauri/target/debug in via `git add -A` — 3,859 files including
a 272MB .a, over GitHub's 100MB cap, so the push could never have landed. They
are gitignored now.

Co-Authored-By: Hanzo Dev <[email protected]>
2026-07-30 18:25:06 -07:00