@atomicstrata/themes

中文文档
0.9.0发布于 2026/10/30(PolyForm-Noncommercial-1.0.0 AND MIT AND OFL-1.1)TypeScriptES Module零依赖近 30 天下载 1697

Framework-independent semantic themes for AtomicStrata products: tokens, theme maps, self-hosted fonts, pre-paint selection and contract checks.

原始使用文档
文档目录9 节
  1. Install
  2. What is in the package
  3. Themes and tokens
  4. Using it
  5. Embedded exported documents
  6. Develop
  7. Verification
  8. Licence
  9. Provenance

@atomicstrata/themes

Shared, framework-independent theming for AtomicStrata products: semantic CSS tokens, four canonical themes, self-hosted fonts, pre-paint theme selection, and reusable contract checks. Products keep their own layouts, components, navigation and state.

Releases before 0.4.0 remain MIT licensed (see "Licence"). 0.5.0 adds theme families with a shared System/Light/Dark preference and a Scientific Clay Dark palette, opt-in: a consumer that does not ask for them gets exactly 0.4.0's behaviour. 0.5.1 writes the design-system compiler's ledger ratios truncated to 10 decimal places, so the Node versions measured write the same ledger (docs/design-systems.md, "Ledger ratios"); --check reports a ledger written by 0.5.0 or earlier stale once, and compiling again rewrites it. 0.6.0 adds an optional compact appearance switch for family pages (@atomicstrata/themes/appearance-switch, AppearanceSwitch in the React entry, css/appearance-switch.css): a sun/moon button with an attached chevron tab opening a System/Light/Dark and theme panel, mounted inline in a slot of the page's top bar or title row (recommended) or fixed to a viewport corner, sized from the root font size. It is opt-in: importing it changes no page, and a consumer that does not mount it gets exactly 0.5.1's behaviour. Its words are English, a corner is fixed to the viewport only when no ancestor of its host is transformed, and its 44px targets reach a little past what is seen (docs/reference.md, "Compact appearance switch"). 0.7.0 colours the switch's product preview from a design system compiled with --bind-product-slot (compile again after updating), keeps an earlier switch working when a remount is refused, and has the System hint name the device's scheme. 0.8.0 adds external themes, opt-in: a compiler (@atomicstrata/themes/theme-compiler, the atomicstrata-theme command) that compiles token-only ext- theme sources, with optional materials, into checked stylesheets, manifests and catalogs; a catalog run time for family pages (@atomicstrata/themes/catalog, @atomicstrata/themes/catalog/prepaint, useThemeCatalog); the authoring JSON Schemas; and css/materials.css, the material role sheet (docs/external-themes.md, docs/reference.md §8 and §9). A page that uses none of them keeps 0.7.0's behaviour, apart from the compact switch's corrections listed on the documentation site's Versions page. 0.8.1 fixes the switch's open panel under large text in a narrow viewport: nothing in it scrolls sideways. 0.9.0 adds the atomicstrata-visual-compare command (Live preview, Screenshot comparison and inspect, below), and makes every opted-in material card one stacking context from rest onward (docs/reference.md §9). The full reference (token roles, API and runtime assumptions, versioning, limits of the checks) is docs/reference.md, which ships in the package. docs/integration-acceptance.md, also shipped, says when a product's integration is finished: its intent, the material setup and load order, a cascade audit, a coverage matrix and four separate evidence tracks (appearance with material fidelity, accessibility, persistence and first paint, application state). Installed packages and theme menu entries alone never complete an integration. skills/atomicstrata-theme-integration/SKILL.md is a short agent skill that applies it; npm installs it with the package but not as an agent skill, so copy or link it into the agent's skills directory and refresh it after an upgrade.

Install

npm install @atomicstrata/themes

The package has no runtime dependencies (React is an optional peer, used only by the @atomicstrata/themes/react subpath). Its JavaScript is ES modules plus two classic scripts, and its stylesheets and fonts are plain files: a bundler resolves the exports in the table below, and a page with no build step serves copies of the installed dist/ and css/ directories (serving the fonts' .woff2 files as binary, font/woff2), as the example under "Using it" does from /assets/themes/.

What is in the package

ExportWhat it is
@atomicstrata/themescreateThemeController, getThemeController, bindThemeSelect, the registry constants and the token-name lists
@atomicstrata/themes/prepaintprepaintSource(config): a classic script, as a string, for a same-origin file or an inline splice
@atomicstrata/themes/prepaint.global.jsthe prebuilt classic script, configured by data-* attributes on its own tag
@atomicstrata/themes/prepaint-mode.global.jsthe same with the optional System/Light/Dark preference (data-mode-storage-key)
@atomicstrata/themes/prepaint-family.global.js0.5.0: the same with theme families (Scientific Clay, Minimal, Nebula, the product) sharing that preference (data-product-modes)
@atomicstrata/themes/checkscolour arithmetic, a token-stylesheet reader and contract checks that take their policy as arguments
@atomicstrata/themes/theme.cssordered entrypoint: fonts, safe defaults, the four theme maps, focus and reduced-motion foundations
@atomicstrata/themes/css/*every stylesheet and font by path, including the optional layers below and theme.bundle.css, the entrypoint flattened with no @import
@atomicstrata/themes/design-systemdesign-system scope helpers: designSystemAttributes, applyDesignSystemScope, recipeAttributes and the attribute and layer names
@atomicstrata/themes/design-system/compilerNode, build time: profile validation, the compiler and pinned acquisition (also the bin atomicstrata-design-system)
@atomicstrata/themes/catalogoptional, 0.8.0, external themes (see below): createThemeCatalogController, getThemeCatalogController, the external-theme catalog controller for family pages; see docs/external-themes.md
@atomicstrata/themes/catalog/prepaint0.8.0, external themes, build time: prepaintCatalogSource, the catalog page's generated pre-paint script (external file or inline)
@atomicstrata/themes/theme-compiler0.8.0, external themes, Node, build time: compile token-only external theme sources (ext-… ids) into stylesheets, manifests and catalogs, and check them (also the bin atomicstrata-theme); see docs/external-themes.md
(repository only) examples/theme-packs/nine example external theme packs, each light and dark with a reference brief, compiled into one example catalog: the three curated candidates (Editorial, Graphite and Instrument, unfinished) and six expressive packs after named styles; authored with docs/theme-authoring.md, not packed and not published
(its own package) packages/theme-packs/@atomicstrata/theme-packs: the six expressive packs compiled into the catalog expressive by the published 0.8.0 compiler, with an author starter; data only, documented in its README and in docs/theme-pack-distribution.md
@atomicstrata/themes/schemas/theme-source.schema.json, …/theme-manifest.schema.json, …/theme-catalog.schema.json0.8.0, external themes: JSON Schemas for editing the three documents, as editor aids (the validators decide)
@atomicstrata/themes/appearance-switchoptional, 0.6.0: mountAppearanceSwitch, a compact sun/moon switch with a theme and appearance panel for family pages, inline in a slot of the page's top bar or title row, or fixed to a viewport corner (top right by default)
@atomicstrata/themes/reactoptional: DesignSystemScope, useDesignSystemAttributes, (0.5.0) useThemeAppearance, (0.6.0) AppearanceSwitch and, for external themes, (0.8.0) useThemeCatalog
@atomicstrata/themes/design-systems/strata/profile.jsonthe Strata design-system profile
@atomicstrata/themes/design-systems/strata/recipes.jsonthe Strata component recipe document (package-authored, opt-in)
(bin) atomicstrata-visual-compare0.9.0, Node, local: one loopback address (serve; preview is the same command) with two modes, a Live preview of one synthetic dashboard under two independently chosen themes, optionally with a compiled catalog's themes, which is reference HTML, not evidence; and a Screenshot comparison gallery for your own saved screenshots across themes, OS modes and versions (side by side, a reveal slider and an exact pixel difference), with a check that they are still the captured bytes (init, verify, serve --config); inspect drives your own running app in Chromium, with your own Playwright, and writes a dataset the gallery shows; not an export, and nothing in the runtime imports it; see docs/visual-comparison.md

Visual comparison. With the package installed in your project (npm install @atomicstrata/themes, above), npx atomicstrata-visual-compare serve needs nothing else: it opens one address with two modes. In a project without the package, npx does not find this bin; it looks for a different package named atomicstrata-visual-compare. Live preview serves one synthetic dashboard live in two panes, each with its own theme and appearance (--catalog <index> adds a compiled catalog's themes, such as an installed @atomicstrata/theme-packs); it is reference HTML, not screenshot evidence. Screenshot comparison shows your own saved screenshots once a configuration names them: npx atomicstrata-visual-compare init visual-review creates a project with a synthetic example dataset (four generated images, not product evidence), and serve --config visual-review/visual-compare.config.json shows it beside Live preview. You supply your own screenshots, captured with your own tools; the gallery counts pixel differences and makes no accessibility or approval judgement. docs/visual-comparison.md, which ships in the package, covers both modes, the configuration, the dataset format and capturing.

External themes (the catalog, catalog/prepaint, theme-compiler and schemas rows, useThemeCatalog and the atomicstrata-theme bin) are new in 0.8.0: installing 0.7.0 or earlier from npm does not supply them. The documentation site's Versions page records each release's status.

Design systems (an external vocabulary such as the Strata registry's, its brands and a one-way bridge onto the contract tokens) are described in docs/design-systems.md, which also ships in the package. A system can also be shown in the theme appearance (data-design-appearance="theme"): its unchanged components take the canonical theme in force, beside the native appearance. From 0.4.0, an os system may also allow a pinned System/Light/Dark choice (designMode on the controller, §6 of the guide), and a product's own markup can opt into a system's component recipes (data-design-recipe: actions, fields, cards, status and text roles, with checked contrast and labelled accessibility overrides, §7), compiled for the product root and native regions only unless asked otherwise.

A whole application in one design system (for example Strata, offered in the theme menu beside Scientific Clay and Minimal) is supported with no system-specific theme id. In outline:

  • Compile the system with --bind-product-slot.
  • Write data-design-system, data-design-brand and data-design-appearance="theme" on <html> in the served markup.
  • Offer the product id, labelled with the system's name (data-product-label="Strata"). Keep the existing storage key, and state the default explicitly.
  • Declare the cascade layer order before any other stylesheet.

Under product the root is the native system; under a canonical theme its components adapt to that theme. The full recipe is "A whole application in one system" in §5 of docs/design-systems.md. It also covers fonts, popups, and what stays the product's work: spacing, sizes, hardcoded CSS values and the brand's known contrast exceptions. A system on the root without data-design-appearance="theme" under a canonical theme is the mixed state of §4, not the consistent whole-application recipe.

Optional stylesheets, never loaded by theme.css:

  • css/typography-root.css: the themed body font at 16px/1.55 on the root.
  • css/control.css: material for the labelled theme <select>.
  • css/appearance-switch.css (0.6.0): material for the compact appearance switch.
  • css/materials.css (0.8.0): the material role sheet, for elements marked data-theme-material="<role>" (docs/reference.md §9). Link it after theme.css and before any statically linked theme stylesheet; docs/integration-acceptance.md covers the order, opt-ins and evidence.
  • css/ambient/scientific-clay.css: Scientific Clay's ambient glow, on elements marked data-theme-ambient="page" and data-theme-ambient="frame".
  • css/adapters/llmwiki-public.css: the llmwiki viewer's public names (--bg-shell, --fg-body, --accent, --ok…), defined from semantic tokens, with the Nebula shades that have no semantic name kept as literals. Do not load it beside another vocabulary that uses --accent or --border.
  • css/profiles/commonware-workbench.css: the Commonware workbench's values for Scientific Clay and Minimal.

Themes and tokens

Theme ids are scientific-clay, minimal, nebula-light and nebula-dark, stamped as data-theme on the document root. Only minimal follows the operating system's light or dark setting. A product may add one more id, product, for its own palette, which it declares in its own stylesheet under [data-theme="product"]; the package ships no such rule. Ids are stored in people's browsers and are permanent API.

Every theme defines every token in TOKEN_NAMES. Each status has three roles: --status-<s> is a decorative accent for marks, bars and icons and carries no contrast promise; --status-<s>-text is the ink for words; --status-<s>-soft is the tinted fill that ink sits on. Product token families (graph, gate, category, workflow) stay with the product, declared under the same [data-theme="…"] selectors.

Using it

<!-- before the first stylesheet -->
<script src="/assets/themes/prepaint.global.js" data-storage-key="acme.app.theme.v1"></script>
<link rel="stylesheet" href="/assets/themes/css/theme.css">

<label class="theme-control"><span>Theme</span><select data-theme-select></select></label>
import { bindThemeSelect, getThemeController } from "@atomicstrata/themes";
const release = bindThemeSelect(document, getThemeController());

Script attributes: data-storage-key="…" or the bare data-session-only (exactly one), and optionally data-themes="scientific-clay minimal", data-product-label="Acme paper", data-default="minimal".

With a build step, generate the script instead. This form also supports a one-time migration from an older preference key; every migration target must be one of the offered themes:

import { prepaintSource } from "@atomicstrata/themes/prepaint";
const script = prepaintSource({
  storageKey: "acme.app.theme.v1",
  themes: ["scientific-clay", "minimal", "nebula-light", "nebula-dark"],
  legacyPreference: { key: "acme-old-theme", values: { light: "nebula-light", dark: "nebula-dark" } },
});

Write the string to a same-origin .js file, or splice it inline right after <head> and allow it by hash. All three deliveries are built from the same functions in src/boot-core.ts.

Behaviour worth knowing:

  • storageKey is always stated: a non-empty string you choose, or null for a choice that lasts for the page. The package never invents a key.
  • An invalid configuration throws before storage is read or the document is touched; the page then renders on the stylesheet's safe :root defaults.
  • A stored id that is unknown, too long or not offered resolves to the default. Storage that throws is treated as unusable: the default applies, nothing is migrated and nothing is written.
  • Selecting a theme sets data-theme on the root and writes one key. It fetches nothing, navigates nowhere and does not reach into frames.
  • bindThemeSelect returns a release function, and binding the same select again replaces its earlier binding. For React, use controller.subscribe with useSyncExternalStore.
  • Without a bundler, serve the whole dist/ directory: the module entry imports its sibling files by relative path. A page that serves a closed list of files instead needs every module dist/index.js imports, listed in docs/reference.md ("Runtime assumptions"); from 0.5.0 that includes dist/family-core.js, even on a page that never asks for families. Each classic script (prepaint.global.js, prepaint-mode.global.js, prepaint-family.global.js) is a single file. The css/ directory must keep its structure too, because fonts are addressed relative to their stylesheets.

Embedded exported documents

Theming never styles a frame's contents. A page that embeds a fixed-appearance document should say so itself: give the document its own <meta name="color-scheme">, and set color-scheme on the iframe element (for a light export, color-scheme: light), so the application's scheme does not reach the embedded canvas or native controls. That rule belongs to the embedding product; the playground's content.css shows it.

Develop

Needs Node 22.18 or later (tests run TypeScript directly).

npm install
npm test                 # build, then node --test over tests/*.test.ts
npm run typecheck
npm run codehealth       # tests with measured coverage, then fallow dead-code, dupes and health
npm run vendor:fonts     # recopy fonts and regenerate notices from the pinned @fontsource packages
cp .env.example .env     # playground host and port; no defaults are built in
npm run playground       # http://127.0.0.1:4319/
npm run playground:screenshots   # needs the server running; writes playground/screenshots/
npm run fixtures:prepare # pack the package and build the two consumer fixtures from that tarball
npm run test:browser     # Playwright acceptance against the built fixtures
npm run visual:gallery   # saved screenshot comparison gallery, http://127.0.0.1:4320/
npm run visual:check-distribution   # pack, install in a scratch consumer, drive the installed gallery in Chromium
npm run design-systems:acquire   # pinned private Strata brand files via gh (organisation access)
npm run test:strata      # acquire, then the Strata profile against the pinned files
npm run design-systems:prepare   # after fixtures:prepare: build the plain and React galleries from the tarball
npm run design-systems:serve plain   # http://127.0.0.1:4351/ (react: 4352)
npm run test:design-systems:browser  # both galleries in Chromium, Firefox and WebKit
npm run docs:dev         # documentation site (docs-site/, Mintlify) preview, http://localhost:4360/
npm run docs:check       # generated reference pages current, mint validate and broken links

The React gallery also needs the registry's components: node fixtures/design-systems/react/scripts/vendor-registry.mjs (gh, pinned commit; bytes stay git-ignored).

npm run visual:gallery serves the repository's own gallery of saved product screenshots across themes and theme versions, starting with the llmwiki migration evidence; see tools/visual-comparison/README.md. That evidence and the capture harnesses stay in the repository and are not packed. The gallery itself ships as the atomicstrata-visual-compare command, described above.

The playground shows one content fragment in three layouts (reader, workbench, product), each loading the package through a different pre-paint delivery under a strict content security policy. The fixtures under fixtures/ install the packed tarball into a plain-JavaScript site and a React/Vite build.

Verification

Three layers, each run from this repository:

  • Unit and contract tests (npm test): the resolver's behaviour as one table run against the module entry, the generated script and the prebuilt script; rejected configurations leaving the page untouched; the select binding; every theme complete and its text roles readable by arithmetic; reference direction; the viewer drop-in comparison against unmodified upstream stylesheets; font bytes and notices; and the documentation's own examples.
  • Packed-artifact fixtures (npm run fixtures:prepare): one tarball is packed and installed into a plain-JavaScript site and a React/Vite production build. Neither imports from this source tree.
  • Browser acceptance (npm run test:browser): Playwright against both built fixtures, in the Chromium, Firefox and WebKit builds it pins.
  • Design-system galleries (npm run test:design-systems:browser): the same tarball in a plain-HTML Strata and Lumen site and a React/Tailwind site with the Strata registry's twelve components in every brand, compared with registry-only reference pages, in the same three engines.

Results are not written into this file, because it ships inside the package it would be describing. In the repository, the dated report under evidence/verification/ records the commands run, their results, the tarball digest and what was left unverified. The repository's tech-debt.md lists known compromises. Neither is part of the published package.

Licence

From version 0.4.0, including this version (0.9.0), @atomicstrata/themes is free for noncommercial use under the PolyForm Noncommercial License 1.0.0 (LICENSE, the official text, unmodified). The licensor is Supernet Inc., doing business as Atomic Strata.

Required Notice: Copyright (c) 2026 Supernet Inc., doing business as Atomic Strata

  • Noncommercial use is permitted on the licence's terms, which define it: any noncommercial purpose, personal uses without any anticipated commercial application (its "Personal Uses" section), and use by a charitable organisation, educational institution, public research organisation, public safety or health organisation, environmental protection organisation or government institution regardless of funding (its "Noncommercial Organizations" section). Read LICENSE for the exact wording.
  • Commercial use outside the permitted purposes above requires a separate written, paid agreement with Supernet Inc., doing business as Atomic Strata. Contact [email protected]. Installing the package or making a payment without that agreement does not grant additional commercial rights.
  • Earlier releases stay MIT. Every version published before 0.4.0 (0.0.0-stage, 0.1.0 and 0.3.0) was released under the MIT License and remains under it. Material as published in those versions, including where it appears unchanged in 0.4.0 or later, stays available under those MIT terms. Supernet Inc.'s original contributions first published in 0.4.0 or later are offered under PolyForm Noncommercial unless separately licensed, including through a commercial agreement. Third-party material retains its own terms.
  • Third-party MIT material. The theme values and mechanisms derived from the MIT-licensed llm-wiki-compiler viewer keep that project's MIT notice. It and this package's earlier MIT licence are the same text byte for byte, shipped in full as LEGACY-MIT-LICENSE.txt.
  • Fonts stay under the SIL Open Font License 1.1, as below.

The license field in package.json is (PolyForm-Noncommercial-1.0.0 AND MIT AND OFL-1.1): one package containing material under each of the three. This section describes the arrangement; it is not legal advice.

Provenance

The theme values and mechanisms derive from the MIT llm-wiki-compiler viewer; tests/upstream/llm-wiki-compiler/ holds unmodified copies of its theme stylesheets, which tests/viewer-drop-in.test.ts compares against. Fonts are SIL Open Font License 1.1, copied unmodified from pinned @fontsource packages; css/fonts/manifest.json records each file's source and digest, THIRD_PARTY_NOTICES.txt carries each package's full licence file, and a test checks the thirteen files are byte-identical to the viewer's. Source commits and digests for the design review are in evidence/source-snapshots/2026-10-11-design/SOURCES.md.

Cross-product architecture and migration plans live in am-research-internal.

版本与发布记录

@atomicstrata/themes 共发布 11 个版本,首次发布于 2026/10/12;过去 12 个月发布了 11 个版本。

版本发布日期距今
0.9.0latest2026/10/3011 天前
0.8.12026/10/2714 天前
0.8.02026/10/2317 天前
0.7.02026/10/1921 天前
0.6.02026/10/1822 天前
0.5.12026/10/1822 天前

关于 @atomicstrata/themes 的常见问题

@atomicstrata/themes 是什么?

Framework-independent semantic themes for AtomicStrata products: tokens, theme maps, self-hosted fonts, pre-paint selection and contract checks.

如何安装 @atomicstrata/themes?

在项目目录运行 npm install @atomicstrata/themes,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 atomicstrata-theme、atomicstrata-design-system、atomicstrata-visual-compare,可以用 npx atomicstrata-theme 直接运行。

@atomicstrata/themes 支持 TypeScript 吗?

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

@atomicstrata/themes 支持 ESM 还是 CommonJS?

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

@atomicstrata/themes 需要什么版本的 Node.js?

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

@atomicstrata/themes 可以商用吗?

@atomicstrata/themes 使用 (PolyForm-Noncommercial-1.0.0 AND MIT AND OFL-1.1) 许可。声明的许可为 (PolyForm-Noncommercial-1.0.0 AND MIT AND OFL-1.1),请阅读许可原文确认使用条件。以上为概括,不构成法律意见,请以许可原文为准。

@atomicstrata/themes 的下载量有多少?

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

@atomicstrata/themes 还在维护吗?

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