Hirael ships "the components shadcn/ui doesn't ship": ~64 React components,
80+ section blocks, and full-page templates, distributed through the shadcn
registry schema — consumers run npx shadcn add https://hirael.com/r/<name>.json and the source lands in their repo. There's
no runtime package. The repo is the showcase site: a static Next.js 16 export
that previews every item and serves the generated /r/*.json files.
CONTRIBUTING.md has the full workflow and item checklist.
Next.js 16, React 19, Tailwind v4. Check the nextjs / shadcn /
react-best-practices skills before framework code. Traps hit here:
output: "export"— no server at runtime. Data (the/changelogfetch, source reads) is fetched once atnext buildand frozen intoout/. Images areunoptimized; routeparamsare Promises (awaitthem);dynamicParams = false, so add items toregistry-meta.ts, not a route table.- The React Compiler is on. Don't hand-write
useMemo/useCallbackin showcase code (app/,components/,lib/,examples/) — but keep explicit memoization in shipped registry source (ui/*,components/*), which consumers may run without the compiler. TanStack Table (v9) components need"use no memo". - Tailwind is CSS-first — no config file; tokens via
@theme inlineinapp/globals.css;.dark/.lightset on<html>by a prehydration script inapp/layout.tsx.
registry-meta.ts declares every item;
the sidebar, counts, pages, and sitemap derive from it (its presence is the
only "published" flag). To change the catalog: edit it, register the preview
loader in registry-demos.tsx, run
pnpm registry:gen, commit. Never hand-edit registry.json — it's
generated, and pnpm check:registry fails on drift or a missing loader. List
registryDependencies by bare name; generation rewrites hirael-to-hirael deps
to /r/<name>.json URLs.
- Compound API first — a flat set of composable parts like shadcn
primitives, no namespacing. The bare
Nameholds state;NameTrigger,NameContent, … are the parts. A single-prop form is optional, never the only API. data-slot="<kebab>"on every rendered slot.ui/is shadcn primitives only; hirael's own go incomponents/. Import via@/registry/hirael/ui/*and@/registry/hirael/components/*(rewritten on install); never import across items by relative path.- Design tokens, never hard-coded colors (defined in
app/globals.css); compose classes withcn(). Light is a faithful inverse of dark, both must work.--warm(taupe) is the brand tone;--accent-coolis reserved for live/active state — don't swap or waste them. - A demo at
examples/<name>-demo.tsxwith user-facing strings throughuseT()—t({ en, ar })— so the RTL toggle shows Arabic. - RTL works with no config — logical properties (
ms/me,ps/pe,start/end),rtl:rotate-180on directional icons, mirror horizontal arrow-key focus. Physical geometry stays physical (Radixdata-[side], Sheet/Sidebarside). Verify with the toggle. - Copy reads like a human — plain and specific, no hype ("Pick a date", not "Effortlessly select your desired date").
- Dark is the default canvas (
:root);.lightis the inverse. - No em dashes in site copy; social link is GitHub, not X — both deliberate.
- Components are generic controls; single-domain compositions are blocks
(the
cloud/saas/widgetsblock kinds). - Auth embeds (
/embed/blocks/auth/*) carry a "doesn't submit" notice — Google Safe Browsing flagged them as phishing. Keep registry components real (nativetype="password"), fix appearance at the showcase layer, and don't robots-disallow/embed/. - Single static-export app — not a monorepo, ships no npm package.
Before review, all four pass (plus a manual pass in both themes and RTL):
pnpm lint && pnpm typecheck && pnpm registry:build && pnpm build/changelog renders MDX entries from content/changelog/*.mdx — one file per
release, compiled at build (next-mdx-remote) and frozen into the export.
Frontmatter is title, date (YYYY-MM-DD), and optional version /
description; the MDX body is visitor-facing (new components, blocks, fixes —
no build/deploy internals). Production deploys only when a Release is
published — main auto-deploy is off in vercel.json — so add the changelog
entry in the same change and cut a Release to ship it.
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in node_modules/next/dist/docs/ (resolved from this file's directory; in monorepos the next package may not be visible from the repo root) before writing any code. Heed deprecation notices.
This block is written and re-added by next dev — verify at node_modules/next/dist/server/lib/generate-agent-files.js. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.