@bitbaum/sitekit

中文文档
0.7.0发布于 2026/11/06MITTypeScriptES Module构建来源已验证近 30 天下载 4452

A website as data: a closed union of section shapes validated at runtime, one set of React renderers, and per-field provenance so a generated site can prove it fabricated nothing.

原始使用文档
文档目录9 节
  1. Why a closed union
  2. Install
  3. Use
  4. Application shell
  5. Provenance — the check behind "fabricate no facts"
  6. The styling contract
  7. Not in this package
  8. Verify
  9. Mobile tab bar

@bitbaum/sitekit

A website as data.

A site is pages; a page is sections; sections come from a closed union of shapes validated by Zod at runtime. One set of React renderers draws every site. A provenance sidecar records where every generated field came from — so "we fabricated nothing" is an assertion, not a promise.

Extracted from substrata's hosted-site model (2026-08). Decided in orangecat's ADR-0003 (the Site Factory).

Why a closed union

A generator emitting data against this schema is a task with a machine-checkable result; a generator emitting components is not. Per-site quality becomes a property of the renderers — fixing the cards renderer improves every site ever generated. And the schema is where review happens: validateSite() returns path: message errors a model can act on directly.

The current kinds: hero (with optional CTAs), prose, stats, meter, cards, definitions, feature (a figure beside a story), contact (locations, address, hours — the fields provenance exists to protect), faq, index, table. Most kinds take an optional anchor, and the schema rejects any index entry or hero action that points at a fragment nothing carries. Extending the union is a deliberate act in THIS repo — a new kind lands with its schema, its renderer, and its tests in one commit, and every consumer gets it on the next version bump.

Install

pnpm add @bitbaum/sitekit

ESM-only. react >= 18 is a peer dependency of @bitbaum/sitekit/react; the root export is framework-free (a Node generator or CI check can use it without React).

Use

import { validateSite, siteNavItems, sitePageAt, pageRendersOwnHeader } from '@bitbaum/sitekit';

const result = validateSite(generatorOutput);
if (!result.success) throw new Error(result.errors.join('\n'));
const site = result.data; // fully typed SiteSpec from here on
import Link from 'next/link';
import { SiteMasthead, SiteFooter, SiteSections } from '@bitbaum/sitekit/react';

<SiteMasthead chrome={site.chrome} navItems={siteNavItems(site.pages)} currentPath={path} Link={Link} />
<SiteSections sections={page.sections} />
<SiteFooter chrome={site.chrome} />

Link is the one framework seam: it defaults to a plain <a>, which is correct everywhere; a Next.js app passes next/link to get client-side navigation back.

Application shell

Product apps use the same masthead, navigation and footer with the application appearance. Import @bitbaum/sitekit/styles.css once. No Tailwind setup is required for this appearance; --sk-* variables map it to the product's shared design tokens. Existing document sites keep their utility-class appearance.

<SiteMasthead appearance="application" chrome={chrome} navItems={nav}
  currentPath="analyze" mainId="main-content" Link={Link}
  brand={<Brand />} actions={<AccountControl />} />
<SiteFooter appearance="application" chrome={chrome} Link={Link}
  links={[{ href: '/roadmap', label: 'Roadmap' }]} extra="Beta" />

For a grouped application menu, pass navGroups alongside navItems. Each group has a label and items containing path, label and an optional description. Import SiteNavGroup from @bitbaum/sitekit/react for typed configuration. Nonempty groups replace the flat application navigation with one native disclosure and a responsive panel; omitted or empty groups retain the flat API. Group labels, destinations and descriptions belong to the host.

navGroups={[{ label: 'Create', items: [
  { path: 'write', label: 'Write', description: 'Start an article.' }
] }]}

Run pnpm exec playwright install --with-deps chromium before pnpm run verify. An existing Chromium can be selected with PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH. The browser regression uses the public renderer and stylesheet at four widths.

The package owns the responsive menu, its native no-JavaScript fallback, Escape/outside/route dismissal, skip link, active states, touch targets and footer layout. Products supply labels, navigation data, identity and account slots. Fix shared chrome here, then release and update consumers through their normal dependency checks and deployment pipeline.

Provenance — the check behind "fabricate no facts"

A closed schema invites completion: a model handed a stats section wants numbers in it. So absence is first-class and typed. The generator emits a sidecar keyed by JSON path:

import { assertDeliverable, notFoundPaths } from '@bitbaum/sitekit';

const provenance = {
  'chrome.name':                    { kind: 'scraped', url: 'https://cafe-beispiel.ch/' },
  'pages.0.sections.1.paragraphs.0':{ kind: 'operator' },   // a human typed it
  'pages.0.sections.4.cards.0.meta':{ kind: 'inferred' },   // a model invented it
  'pages.0.sections.7.rows.0.1':    { kind: 'not-found' },  // we looked; it isn't public
};

assertDeliverable(provenance); // throws: names the inferred path
notFoundPaths(provenance);     // the honest gaps — in a pitch, these ARE the pitch

not-found is the difference between unknown and empty: it records that the looking happened, which is what makes "here is what we could not find out about you" an honest sentence instead of an excuse.

The styling contract

The renderers emit semantic utility classes and nothing else — no colours, faces, or radii ship in this package. Each consumer defines the tokens, which is how fifty sites share one renderer without looking like one company. (Uniform everywhere except aesthetics. Do NOT point consumers at @fleet/design-tokens values — those make things look like the fleet; inherit the shape, choose your own values.)

Classes the renderers use, to be defined by the consumer's Tailwind theme:

GroupClasses
Texttext-fg-primary text-fg-secondary text-fg-tertiary text-fg-muted
Surfacesbg-surface-page bg-surface-raised
Bordersborder-subtle border-strong divide-subtle
Accent & statusbg-accent decoration-accent bg-status-positive bg-status-warning bg-status-negative
Typefont-heading font-mono tracking-caps tracking-display
Layoutmax-w-shell max-w-prose scrollbar-hide

With Tailwind 4, define them as @theme variables (--color-fg-primary, --font-heading, …) and add the package to content scanning:

@import 'tailwindcss';
@source '../node_modules/@bitbaum/sitekit/dist';

Substrata's app/globals.css is the reference implementation of the contract.

Not in this package

  • No design tokens. See above — that is the point.
  • No scraper. siteFromUrl() (extraction from a live site, with provenance) is the planned next module; the schema is its target.
  • No HTTP, no framework. Same rule as every package in this fleet.

Verify

pnpm run verify  # lint + typecheck + build + test — same command CI runs

Tests import the package by name (@bitbaum/sitekit, @bitbaum/sitekit/react), so a broken exports map fails in CI, not at the first consumer.


Part of bitbaum — AI-native products on open infrastructure, built in Zürich. Every package here lists the apps that use it: which apps use sitekit.

Application footers can pass groups: [{ label, links: [{ href, label }] }] for semantic navigation groups. Existing flat links remain supported. Consumers can configure --sk-header-height, --sk-mobile-header-height, --sk-display-weight, --sk-display-leading, --sk-display-tracking and --sk-footer-gap through their theme adapter, without replacing shared markup.

Mobile tab bar

SiteTabBar renders a fixed bottom navigation for small screens (hidden from 48rem up, where the masthead nav takes over). Pass 3–5 { path, label, icon } items and the current path; it renders its own spacer so content is not hidden.

Use SiteIcon for the icons — { icon: <SiteIcon name="write" /> } — not a unicode glyph: the set is drawn on currentColor, so icon and label take one colour and the current tab is one rule. Names: SITE_ICON_NAMES. Pass tabBar to SiteMasthead on the same page so the masthead drops its menu button on phones instead of repeating the tab bar's destinations:

<SiteMasthead appearance="application" tabBar navItems={nav} … />
<SiteTabBar items={nav.map((n) => ({ ...n, icon: <SiteIcon name={n.icon} /> }))} … />

版本与发布记录

@bitbaum/sitekit 共发布 9 个版本,首次发布于 2026/09/05;过去 12 个月发布了 9 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.7.0latest2026/11/062 天前
0.6.12026/11/062 天前
0.5.12026/11/035 天前
0.5.02026/11/035 天前
0.4.22026/10/2414 天前
0.4.12026/10/2414 天前

关于 @bitbaum/sitekit 的常见问题

@bitbaum/sitekit 是什么?

A website as data: a closed union of section shapes validated at runtime, one set of React renderers, and per-field provenance so a generated site can prove it fabricated nothing.

如何安装 @bitbaum/sitekit?

在项目目录运行 npm install @bitbaum/sitekit,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(>=18)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@bitbaum/sitekit 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@bitbaum/sitekit 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@bitbaum/sitekit 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@bitbaum/sitekit 可以商用吗?

@bitbaum/sitekit 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@bitbaum/sitekit 的下载量有多少?

根据 npm 官方下载统计,@bitbaum/sitekit 在 2026/10/08 – 2026/11/06 这 30 天内被下载 4,452 次,日均约 148 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@bitbaum/sitekit 还在维护吗?

最新版本 0.7.0 发布于 2026/11/06(2 天前);至今共发布 9 个版本,其中过去 12 个月发布了 9 个;首次发布于 2026/09/05。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。