Ziteox Forge

Architecture

Monorepo layout, package structure, and design decisions.

Architecture

This document describes how Ziteox Forge is structured and why.

Monorepo layout

ziteox-forge/
├── packages/
│   └── ui/                 # @ziteox/ui — shared React components
├── examples/
│   └── playground/         # Vite demo app for local development
├── docs/                   # Human + agent documentation (this tree)
├── agents/                 # Reserved
├── prompts/                # Reserved
└── standards/              # Reserved

Tooling:

ToolRole
pnpm workspacesPackage linking (packages/*, examples/*)
TurborepoCached builds across packages
TypeScript (tsc)Compile @ziteox/ui to dist/

Root scripts:

pnpm install    # Install all workspace dependencies
pnpm build      # Build all packages (turbo)
pnpm dev        # Watch mode where configured
pnpm clean      # Remove build artifacts

@ziteox/ui package structure

packages/ui/src/
├── index.ts                  # Root public API — re-exports domains only
├── animations/               # Internal motion presets
├── shared/                   # Internal hooks and utilities
│   └── hooks/
├── theme/                    # Theme domain
├── navigation/               # Navigation domain
└── branding/                 # Branding domain

Export model

Consumers import from:

Import pathContents
@ziteox/uiAll public symbols
@ziteox/ui/themeTheme domain
@ziteox/ui/navigationNavigation domain
@ziteox/ui/brandingBranding domain

Each domain has index.ts as its barrel. The root index.ts re-exports domain barrels only — never deep files.

package.json exports field maps subpaths to compiled dist/ outputs.

Internal modules

PathPurposePublic?
shared/hooks/use-mounted.tsHydration guard for client componentsNo
shared/hooks/use-skip-initial-animation.tsSuppress first-paint motion/transitionNo
shared/hooks/use-prefers-reduced-motion.tsprefers-reduced-motion media queryNo
animations/springs.tsShared motion spring presetsNo

Internal modules may change without semver notice. Do not import them from consuming apps.

Domain-first organization

Components are grouped by product concern (theme, navigation, branding), not by file type.

Rationale:

  • Keeps related code colocated as domains grow
  • Limits cross-domain coupling
  • Makes subpath exports (@ziteox/ui/navigation) meaningful
  • Scales to dozens of components without a flat components/ dump

See domain-boundaries.md for ownership rules.

Framework-agnostic design

@ziteox/ui targets React 18+ and avoids framework-specific imports in component source.

PatternImplementation
Routing linksPlain <a> (not next/link)
IconsInline SVG (no lucide-react in package)
StylingScoped ziteox-* CSS injected per component (no Tailwind in package)
Theme persistencenext-themes as peer dependency; wrapper in ThemeProvider

Apps using Next.js, Vite, or other React frameworks consume the same package. Next.js App Router consumers import client components ("use client") from client boundaries where required.

Controlled components

Interactive components use controlled state at the public API boundary:

<HamburgerButton isOpen={isOpen} onOpenChange={setIsOpen} />

Rationale:

  • Parent owns state (local state, context, or URL)
  • No hidden global providers required for basic usage
  • Easier to test and compose
  • Menu/nav context can be added at app level when needed

ThemeToggle is an exception at the convenience layer: it reads next-themes internally but still delegates rendering to controlled AnimatedThemeToggler.

Animation strategy

Two tiers — see animation-guidelines.md:

  1. CSS transitions — simple morphs (e.g. HamburgerButton)
  2. motion (motion/react) — complex SVG/path animation (e.g. AnimatedThemeToggler)

Do not add framer-motion as a separate dependency. Forge standardizes on motion.

Build output

  • Input: packages/ui/src/**/*.tsx|ts
  • Output: packages/ui/dist/ (ESM + .d.ts)
  • Module format: ESM ("type": "module")
  • JSX: react-jsx runtime

The playground resolves @ziteox/ui to source via Vite alias during local dev. Production consumers use compiled dist/.

Dependency model

Runtime libraries are peer dependencies on @ziteox/ui:

  • react, react-dom
  • next-themes (theme domain)
  • motion (animated components)

Apps install peers once. The package does not bundle them.

Adding a new component (checklist)

  1. Choose domain — see domain-boundaries.md
  2. Add component file under packages/ui/src/<domain>/
  3. Export from domain index.ts
  4. Re-export from packages/ui/src/index.ts
  5. Add subpath to package.json exports if new domain
  6. Add docs/ui/<component>.md
  7. Add playground example if useful
  8. Run pnpm build