@hraness/design-kit 0.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARTICLE_COPY.md +208 -0
- package/HERO_FIELDS.md +55 -0
- package/ICONS.md +56 -0
- package/LANTERN_MATERIAL.md +60 -0
- package/LICENSE +21 -0
- package/MARKETING_COPY.md +49 -0
- package/MARKETING_PRESET.md +108 -0
- package/PALETTES.md +90 -0
- package/PAPER_THEME.md +128 -0
- package/README.md +745 -0
- package/STATUS_PAGES.md +67 -0
- package/STYLE.md +245 -0
- package/WRITING.md +72 -0
- package/dist/browser/index.js +2345 -0
- package/dist/chunk-44djxk16.js +6872 -0
- package/dist/chunk-5gtx3pza.js +9 -0
- package/dist/chunk-77391vmq.js +454 -0
- package/dist/chunk-7b1586eb.js +1209 -0
- package/dist/chunk-8834fh4n.js +6 -0
- package/dist/chunk-9t8xyqte.js +870 -0
- package/dist/chunk-cejpzyfh.js +446 -0
- package/dist/chunk-eh71jz57.js +429 -0
- package/dist/chunk-evb02bc1.js +516 -0
- package/dist/chunk-h4k7yv6x.js +368 -0
- package/dist/chunk-he8eznb1.js +760 -0
- package/dist/chunk-mr1vdcjq.js +404 -0
- package/dist/chunk-wzvdn8ey.js +116 -0
- package/dist/fonts/nebula-sans/social-fonts.generated.js +53 -0
- package/dist/icons.js +48 -0
- package/dist/index.js +237 -0
- package/dist/launch.js +41 -0
- package/dist/mockups/client.js +422 -0
- package/dist/mockups/index.js +1850 -0
- package/dist/portfolio.js +1549 -0
- package/dist/provider-marks.js +19 -0
- package/dist/react/charts.js +11 -0
- package/dist/react/hero-backdrop.js +8 -0
- package/dist/react/index.js +7252 -0
- package/dist/react/platform-install.js +10 -0
- package/dist/react/server.js +137 -0
- package/dist/stylex-manifest.json +1 -0
- package/dist/stylex.css +5392 -0
- package/dist/syntax-highlighting.js +15 -0
- package/dist/testing.js +250 -0
- package/package.json +377 -0
- package/portfolio-inventory.json +31 -0
- package/scripts/check-lantern-material-snapshot.d.mts +26 -0
- package/scripts/check-lantern-material-snapshot.mjs +126 -0
- package/scripts/check-marketing-snapshot.d.mts +12 -0
- package/scripts/check-marketing-snapshot.mjs +58 -0
- package/scripts/lantern-material-snapshot.ts +101 -0
- package/scripts/marketing-textures.ts +48 -0
- package/scripts/paper-theme-snapshot.ts +97 -0
- package/scripts/product-marketing-snapshot.ts +149 -0
- package/src/appearance-menu.css +266 -0
- package/src/appearance.ts +32 -0
- package/src/article-html.ts +269 -0
- package/src/article.ts +686 -0
- package/src/browser/appearance-menu.ts +604 -0
- package/src/browser/artifact-share.ts +164 -0
- package/src/browser/design-palette.ts +197 -0
- package/src/browser/foil.ts +124 -0
- package/src/browser/hero-light.ts +11 -0
- package/src/browser/index.ts +29 -0
- package/src/browser/status-field.ts +432 -0
- package/src/browser/status-page.ts +100 -0
- package/src/browser/sticky-offset.ts +82 -0
- package/src/browser/theme-color-sync.ts +213 -0
- package/src/charts.css +7 -0
- package/src/compiler-components.css +34 -0
- package/src/compiler-foundation.css +18 -0
- package/src/compiler-palettes.css +7 -0
- package/src/compiler-tokens.css +342 -0
- package/src/components.css +3 -0
- package/src/design-gallery.css +431 -0
- package/src/effects.css +14 -0
- package/src/fonts/geist-mono/GeistMono[wght].woff2 +0 -0
- package/src/fonts/geist-mono/OFL.txt +93 -0
- package/src/fonts/geist-mono/PROVENANCE.md +12 -0
- package/src/fonts/instrument-serif/OFL.txt +93 -0
- package/src/fonts/instrument-serif/UPSTREAM.md +14 -0
- package/src/fonts/instrument-serif/instrument-serif-latin-400.woff2 +0 -0
- package/src/fonts/nebula-sans/LICENSE.txt +96 -0
- package/src/fonts/nebula-sans/NebulaSans-Black.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-BlackItalic.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-Bold.otf +0 -0
- package/src/fonts/nebula-sans/NebulaSans-Bold.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-BoldItalic.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-Book.otf +0 -0
- package/src/fonts/nebula-sans/NebulaSans-Book.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-BookItalic.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-Light.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-LightItalic.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-Medium.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-MediumItalic.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-Semibold.woff2 +0 -0
- package/src/fonts/nebula-sans/NebulaSans-SemiboldItalic.woff2 +0 -0
- package/src/fonts/nebula-sans/PROVENANCE.md +14 -0
- package/src/fonts/nebula-sans/social-fonts.generated.ts +3873 -0
- package/src/fonts.css +106 -0
- package/src/icons/act60/act60.svg +5 -0
- package/src/icons/act60/application.svg +9 -0
- package/src/icons/act60/chapter-compare.svg +3 -0
- package/src/icons/act60/decree-residence.svg +6 -0
- package/src/icons/act60/estimate.svg +7 -0
- package/src/icons/act60/export-services.svg +4 -0
- package/src/icons/act60/investor.svg +13 -0
- package/src/icons/act60/presence.svg +7 -0
- package/src/icons/aicharts/aicharts.svg +6 -0
- package/src/icons/aicharts/cost-compare.svg +4 -0
- package/src/icons/aicharts/task-audio.svg +7 -0
- package/src/icons/aicharts/task-coding.svg +6 -0
- package/src/icons/aicharts/task-images.svg +3 -0
- package/src/icons/aicharts/task-reasoning.svg +9 -0
- package/src/icons/aicharts/task-research.svg +5 -0
- package/src/icons/aicharts/task-video.svg +4 -0
- package/src/icons/manifest.json +1371 -0
- package/src/icons/platonik/conversation.svg +3 -0
- package/src/icons/platonik/creature.svg +7 -0
- package/src/icons/platonik/economy.svg +4 -0
- package/src/icons/platonik/keep-light.svg +6 -0
- package/src/icons/platonik/platonik.svg +7 -0
- package/src/icons/platonik/spark-route.svg +15 -0
- package/src/icons/receipts/act60-retry.receipt.json +888 -0
- package/src/icons/receipts/act60.receipt.json +1366 -0
- package/src/icons/receipts/aicharts.receipt.json +1546 -0
- package/src/icons/receipts/platonik.receipt.json +1011 -0
- package/src/icons/receipts/roughday.receipt.json +770 -0
- package/src/icons/receipts/shared.receipt.json +1296 -0
- package/src/icons/receipts/slopcamera.receipt.json +1495 -0
- package/src/icons/receipts/soundfish-retry.receipt.json +460 -0
- package/src/icons/receipts/soundfish.receipt.json +1709 -0
- package/src/icons/receipts/sponge.receipt.json +1743 -0
- package/src/icons/receipts/stripe-history-retry.receipt.json +145 -0
- package/src/icons/receipts/stripe-history.receipt.json +1202 -0
- package/src/icons/receipts/wordcell.receipt.json +1924 -0
- package/src/icons/roughday/finance.svg +7 -0
- package/src/icons/roughday/roughday.svg +6 -0
- package/src/icons/roughday/technology.svg +4 -0
- package/src/icons/roughday/world.svg +4 -0
- package/src/icons/sets/act60.json +63 -0
- package/src/icons/sets/aicharts.json +63 -0
- package/src/icons/sets/platonik.json +39 -0
- package/src/icons/sets/roughday.json +25 -0
- package/src/icons/sets/shared.json +12 -0
- package/src/icons/sets/slopcamera.json +47 -0
- package/src/icons/sets/soundfish.json +43 -0
- package/src/icons/sets/sponge.json +51 -0
- package/src/icons/sets/stripe-history.json +39 -0
- package/src/icons/sets/wordcell.json +51 -0
- package/src/icons/shared/agent-skill.svg +4 -0
- package/src/icons/shared/cli.svg +5 -0
- package/src/icons/shared/privacy.svg +3 -0
- package/src/icons/shared/research.svg +7 -0
- package/src/icons/shared/sdk.svg +3 -0
- package/src/icons/slopcamera/diagram.svg +3 -0
- package/src/icons/slopcamera/direct-scene.svg +5 -0
- package/src/icons/slopcamera/edit-video.svg +17 -0
- package/src/icons/slopcamera/mcp.svg +3 -0
- package/src/icons/slopcamera/native-world.svg +3 -0
- package/src/icons/slopcamera/slopcamera.svg +11 -0
- package/src/icons/soundfish/agent-ui.svg +7 -0
- package/src/icons/soundfish/collaborate.svg +5 -0
- package/src/icons/soundfish/compose.svg +3 -0
- package/src/icons/soundfish/hear.svg +6 -0
- package/src/icons/soundfish/human-ui.svg +6 -0
- package/src/icons/soundfish/share.svg +3 -0
- package/src/icons/soundfish/soundfish.svg +6 -0
- package/src/icons/sponge/api.svg +3 -0
- package/src/icons/sponge/documents.svg +3 -0
- package/src/icons/sponge/library.svg +3 -0
- package/src/icons/sponge/one-question.svg +5 -0
- package/src/icons/sponge/people-direct.svg +5 -0
- package/src/icons/sponge/read.svg +3 -0
- package/src/icons/sponge/save.svg +4 -0
- package/src/icons/sponge/sponge.svg +7 -0
- package/src/icons/stripe-history/company-history.svg +3 -0
- package/src/icons/stripe-history/evidence.svg +4 -0
- package/src/icons/stripe-history/independence.svg +7 -0
- package/src/icons/stripe-history/publications.svg +11 -0
- package/src/icons/stripe-history/sources.svg +6 -0
- package/src/icons/stripe-history/stripe-history.svg +3 -0
- package/src/icons/wordcell/backlinks.svg +6 -0
- package/src/icons/wordcell/capture.svg +6 -0
- package/src/icons/wordcell/git-provenance.svg +4 -0
- package/src/icons/wordcell/kb.svg +4 -0
- package/src/icons/wordcell/markdown.svg +4 -0
- package/src/icons/wordcell/scopes.svg +3 -0
- package/src/icons/wordcell/search.svg +7 -0
- package/src/icons.generated.ts +734 -0
- package/src/icons.ts +51 -0
- package/src/index.ts +275 -0
- package/src/lantern-material.css +213 -0
- package/src/launch.ts +624 -0
- package/src/marketing-assets/UPSTREAM.md +18 -0
- package/src/marketing-assets/cells.svg +1 -0
- package/src/marketing-assets/grain.svg +1 -0
- package/src/marketing-forced-colors.css +12 -0
- package/src/mockups/client.tsx +415 -0
- package/src/mockups/core.tsx +318 -0
- package/src/mockups/frames.tsx +368 -0
- package/src/mockups/index.ts +14 -0
- package/src/mockups/surfaces.tsx +681 -0
- package/src/mockups.css +2607 -0
- package/src/palette-appearance.ts +45 -0
- package/src/palette-bridge.css +124 -0
- package/src/palette-color.ts +41 -0
- package/src/palette-system.css +721 -0
- package/src/palette-themes.ts +23 -0
- package/src/palette-tokens.stylex.ts +519 -0
- package/src/palettes.css +3 -0
- package/src/palettes.ts +161 -0
- package/src/paper-theme.css +244 -0
- package/src/plain-publication.css +1241 -0
- package/src/plain-site.css +397 -0
- package/src/platforms.ts +151 -0
- package/src/portfolio.generated.json +1595 -0
- package/src/portfolio.generated.ts +1596 -0
- package/src/portfolio.ts +226 -0
- package/src/product-marketing-foundation.css +433 -0
- package/src/product-marketing-preset.css +261 -0
- package/src/product-marketing.css +2186 -0
- package/src/provider-marks.generated.ts +112 -0
- package/src/provider-marks.ts +143 -0
- package/src/react/animated-rail-stage.stylex.ts +15 -0
- package/src/react/animated-rail-stage.tsx +51 -0
- package/src/react/app-shell.stylex.ts +104 -0
- package/src/react/app-shell.tsx +121 -0
- package/src/react/article.tsx +602 -0
- package/src/react/aurora-dots-background.tsx +34 -0
- package/src/react/charts.stylex.ts +563 -0
- package/src/react/charts.tsx +610 -0
- package/src/react/chat.stylex.ts +34 -0
- package/src/react/chat.tsx +155 -0
- package/src/react/design-gallery.tsx +943 -0
- package/src/react/design-palette.stylex.ts +124 -0
- package/src/react/design-palette.tsx +196 -0
- package/src/react/design-theme-context.tsx +41 -0
- package/src/react/effects.stylex.ts +325 -0
- package/src/react/fader.stylex.ts +71 -0
- package/src/react/fader.tsx +151 -0
- package/src/react/foil-card-math.ts +100 -0
- package/src/react/foil-card-surface.stylex.ts +326 -0
- package/src/react/foil-card-surface.tsx +742 -0
- package/src/react/foil-mark.tsx +35 -0
- package/src/react/foil.stylex.ts +163 -0
- package/src/react/haptics.ts +228 -0
- package/src/react/hero-backdrop.tsx +22 -0
- package/src/react/index.ts +38 -0
- package/src/react/keyboard-shortcuts.ts +228 -0
- package/src/react/lantern-material-gallery.tsx +166 -0
- package/src/react/lantern-material.stylex.ts +39 -0
- package/src/react/launch-beats.tsx +73 -0
- package/src/react/navigation-rail.stylex.ts +130 -0
- package/src/react/navigation-rail.tsx +228 -0
- package/src/react/particle-halo.tsx +115 -0
- package/src/react/phaser-dots.tsx +501 -0
- package/src/react/platform-icons.tsx +94 -0
- package/src/react/platform-install.stylex.ts +385 -0
- package/src/react/platform-install.tsx +389 -0
- package/src/react/playback-transport.stylex.ts +14 -0
- package/src/react/playback-transport.tsx +112 -0
- package/src/react/procedural-backdrop.tsx +192 -0
- package/src/react/procedural-recipe.ts +323 -0
- package/src/react/product-marketing.stylex.ts +4469 -0
- package/src/react/product-marketing.tsx +1611 -0
- package/src/react/production-data-preview-notice.stylex.ts +40 -0
- package/src/react/production-data-preview-notice.tsx +34 -0
- package/src/react/provider-mark.stylex.ts +132 -0
- package/src/react/provider-mark.tsx +120 -0
- package/src/react/relative-time.tsx +117 -0
- package/src/react/route-state.stylex.ts +39 -0
- package/src/react/route-state.tsx +350 -0
- package/src/react/server.ts +11 -0
- package/src/react/social-kit-panel.tsx +103 -0
- package/src/react/sticky-offset.tsx +33 -0
- package/src/react/surfaces.stylex.ts +179 -0
- package/src/react/surfaces.tsx +330 -0
- package/src/react/syntax-code.tsx +33 -0
- package/src/react/theme-color-sync.ts +1 -0
- package/src/react/theme-resolution.ts +11 -0
- package/src/react/theme.stylex.ts +276 -0
- package/src/react/theme.tsx +402 -0
- package/src/reading.css +72 -0
- package/src/relative-time.ts +185 -0
- package/src/reset.css +2 -0
- package/src/site-shell.css +16 -0
- package/src/status-page-html.ts +63 -0
- package/src/status-page.css +276 -0
- package/src/status-page.ts +323 -0
- package/src/styles.css +21 -0
- package/src/syntax-code-lexers.ts +303 -0
- package/src/syntax-highlighting.css +78 -0
- package/src/syntax-highlighting.ts +477 -0
- package/src/syntax-tokens.ts +33 -0
- package/src/testing.ts +307 -0
- package/src/tokens.css +3 -0
- package/src/typography.css +86 -0
- package/vendor/evilcharts/LICENSE +21 -0
- package/vendor/evilcharts/UPSTREAM.md +14 -0
- package/vendor/platform-marks/LICENSE +30 -0
- package/vendor/platform-marks/UPSTREAM.md +15 -0
- package/vendor/platform-marks/apple.svg +1 -0
- package/vendor/platform-marks/linux.svg +1 -0
- package/vendor/provider-marks/CRUSH-LICENSE.md +134 -0
- package/vendor/provider-marks/LICENSE +21 -0
- package/vendor/provider-marks/UPSTREAM.md +27 -0
- package/vendor/provider-marks/aider.svg +3 -0
- package/vendor/provider-marks/crush-heartbit.svg +8 -0
- package/vendor/provider-marks/lobehub/alibabacloud-color.svg +1 -0
- package/vendor/provider-marks/lobehub/alibabacloud.svg +1 -0
- package/vendor/provider-marks/lobehub/amp-color.svg +1 -0
- package/vendor/provider-marks/lobehub/amp.svg +1 -0
- package/vendor/provider-marks/lobehub/anthropic.svg +1 -0
- package/vendor/provider-marks/lobehub/claude-color.svg +1 -0
- package/vendor/provider-marks/lobehub/claude.svg +1 -0
- package/vendor/provider-marks/lobehub/claudecode-color.svg +1 -0
- package/vendor/provider-marks/lobehub/claudecode.svg +1 -0
- package/vendor/provider-marks/lobehub/codex-color.svg +1 -0
- package/vendor/provider-marks/lobehub/codex.svg +1 -0
- package/vendor/provider-marks/lobehub/cursor.svg +1 -0
- package/vendor/provider-marks/lobehub/deepseek-color.svg +1 -0
- package/vendor/provider-marks/lobehub/deepseek.svg +1 -0
- package/vendor/provider-marks/lobehub/devin-color.svg +1 -0
- package/vendor/provider-marks/lobehub/devin.svg +1 -0
- package/vendor/provider-marks/lobehub/gemini-color.svg +1 -0
- package/vendor/provider-marks/lobehub/gemini.svg +1 -0
- package/vendor/provider-marks/lobehub/geminicli-color.svg +1 -0
- package/vendor/provider-marks/lobehub/geminicli.svg +1 -0
- package/vendor/provider-marks/lobehub/goose.svg +1 -0
- package/vendor/provider-marks/lobehub/meta-color.svg +1 -0
- package/vendor/provider-marks/lobehub/meta.svg +1 -0
- package/vendor/provider-marks/lobehub/mistral-color.svg +1 -0
- package/vendor/provider-marks/lobehub/mistral.svg +1 -0
- package/vendor/provider-marks/lobehub/moonshot.svg +1 -0
- package/vendor/provider-marks/lobehub/nvidia-color.svg +1 -0
- package/vendor/provider-marks/lobehub/nvidia.svg +1 -0
- package/vendor/provider-marks/lobehub/openai.svg +1 -0
- package/vendor/provider-marks/lobehub/opencode.svg +1 -0
- package/vendor/provider-marks/lobehub/perplexity-color.svg +1 -0
- package/vendor/provider-marks/lobehub/perplexity.svg +1 -0
- package/vendor/provider-marks/lobehub/qwen-color.svg +1 -0
- package/vendor/provider-marks/lobehub/qwen.svg +1 -0
- package/vendor/provider-marks/lobehub/xai.svg +1 -0
- package/vendor/provider-marks/lobehub/zai.svg +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,745 @@
|
|
|
1
|
+
# hraness/design-kit
|
|
2
|
+
|
|
3
|
+
React components and CSS for Hraness apps and product sites: application shells, marketing sections, charts, themes, effects, and syntax highlighting. Built on `@hraness/ui`.
|
|
4
|
+
|
|
5
|
+
`@hraness/ui` supplies the accessible React Aria primitives: actions, form fields, overlays, collections, navigation, and basic surfaces. This package builds on them with application shells, loading and error pages, saved light and dark appearance, charts and instrument controls, haptics, decorative effects, server-side syntax highlighting, plain-site CSS, and a gallery you can run.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
Pin a GitHub release tag:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@hraness/design-kit": "github:hraness/design-kit#v0.31.1",
|
|
15
|
+
"@hraness/ui": "github:hraness/ui#v0.5.17"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`@hraness/ui` is an explicit peer dependency with the supported range
|
|
21
|
+
`>=0.5.16 <0.6.0`; consumers should pin an immutable compatible release such as
|
|
22
|
+
`v0.5.17` when using the stylesheet, React, or compiler-adopter entries. The peer is optional at
|
|
23
|
+
installation so the framework-neutral root and syntax highlighter can be used
|
|
24
|
+
on their own. React 18 or 19 and React DOM 18 or 19 are also peer dependencies.
|
|
25
|
+
|
|
26
|
+
### Provider artwork notices
|
|
27
|
+
|
|
28
|
+
Version 0.31.1 includes Charm's complete license and copyright notices for the Crush HeartBit artwork in `vendor/provider-marks/CRUSH-LICENSE.md`. The package also retains the LobeHub MIT notice and identifies the exact Crush source commit.
|
|
29
|
+
|
|
30
|
+
### Social posts carry claims only
|
|
31
|
+
|
|
32
|
+
Version 0.31.0 keeps caveats out of the social kit. `buildSocialKit` skips the `limits` beat and any beat marked `social: false`, so their text stays in the launch post and never reaches X, Bluesky, Threads, LinkedIn, or the Show HN and Product Hunt fact sheet. A beat can carry a `socialPost`, a narrower wording that is accurate without the caveat its `post` keeps; `resolveLaunchBeats` fills its placeholders and the checks apply to it. `assertLaunchKit` now rejects a kit that carries a launch-post-only beat. New exports: `launchPostOnlyParts`, `isSocialBeat`, `socialBeats`, and `socialPostText`. Kits built from beats without a `limits` beat are unchanged.
|
|
33
|
+
|
|
34
|
+
### Product names in the portfolio snapshot
|
|
35
|
+
|
|
36
|
+
Version 0.30.3 refreshes the `@hraness/design-kit/portfolio` snapshot from the registry. Related-product cards now spell every product the way its own site does, including GhostGet, TextButler, SlopCamera, Soulscrape, Valhalla, and Excalibur (xcb), and names that were set in capitals, such as Stripe History and Lifecharts, now use their prose form. The snapshot adds icon.place, GhostGet Skills, System One Skills, and Pattern Language, with the current one-liners and relations. No export changes.
|
|
37
|
+
|
|
38
|
+
### Narrow install tabs
|
|
39
|
+
|
|
40
|
+
Version 0.30.2 keeps the narrow and stacked `PlatformInstall` layout in place when another package, such as `@hraness/site-footer`, compiles the same default atoms into a later cascade layer: the tab row and tabs now read their narrow and stacked values from private `--_hraness-platform-install-*` custom properties, so the tab row spans its column again and stacked tabs use their smaller label and padding. No prop or export changes. Version 0.30.1 keeps every `PlatformInstall` tab name whole in narrow columns. The component is now an inline-size container named `hraness-platform-install`, and its narrow rules follow the column it sits in rather than the viewport. At 30rem and below the tab row spans the column; at 17.5rem and below each mark stacks above its name, so macOS, Linux, and Windows stay whole down to a 200px tab row, such as a nested install panel on a 320px phone. No prop or export changes. Sites that mirror the hook classes in their own CSS should add `container: hraness-platform-install / inline-size` to `.hraness-platform-install`, move their narrow `.hraness-platform-install__tabs` and `__tab` rules from `@media (max-width: 30rem)` to `@container hraness-platform-install (max-width: 30rem)`, and copy the stacked `__tab` rule. Version 0.30.0 adds `site-shell.css` with `hraness-site-shell` and `hraness-site-shell__content` hooks. Short pages place their footer at the viewport bottom; long pages keep it below their content. Plain and marketing document bodies use the shared layout by default. Version 0.29.3 keeps selected install-tab labels and marks readable in forced-colors mode. Selected tabs preserve the paired system selection colors across their descendants, including hovered tabs.
|
|
41
|
+
|
|
42
|
+
Version 0.29.2 keeps every `PlatformInstall` tab visible at 320 to 360px. Below 30rem the tab row spans its column, the tabs share its width and use tighter padding and a slightly smaller label, and a name is truncated only as a last resort, so the Windows tab no longer hides behind a sideways scroll. The component also defines each platform mark once as an SVG `<symbol>` and draws tabs and no-script labels by reference, which removes about 25 KB of repeated paths per instance. No prop or export changes. Sites that mirror the hook classes in their own CSS should copy the narrow rules for `.hraness-platform-install__tabs`, `__tab`, and the new `__tab-label`.
|
|
43
|
+
|
|
44
|
+
### Forced-colors action labels
|
|
45
|
+
|
|
46
|
+
Version 0.29.1 keeps marketing action labels readable with system button colors, including accent sections and hovered controls. Older consumers can load the standalone `@hraness/design-kit/marketing-forced-colors.css` after their existing marketing styles without changing normal appearance. Vendored copies must retain the exact released file and its provenance; local action color overrides must respect forced-colors mode.
|
|
47
|
+
|
|
48
|
+
### Metallic brand marks
|
|
49
|
+
|
|
50
|
+
`FoilMark` is available from both React entry points, including the server-safe
|
|
51
|
+
`@hraness/design-kit/react/server`. Give it a transparent same-origin SVG (or a
|
|
52
|
+
data URL); the exact artwork alpha carries the material and the original image
|
|
53
|
+
remains underneath as a fallback. An optional `fallback` accepts the original
|
|
54
|
+
inline vector for currentColor behavior. The mark is decorative unless `label`
|
|
55
|
+
is supplied. Name its enclosing link once.
|
|
56
|
+
|
|
57
|
+
React consumers load `@hraness/design-kit/components.css` or the complete
|
|
58
|
+
`styles.css` entry. The raw marketing stylesheet alone styles authored HTML
|
|
59
|
+
hooks; it does not contain the compiled React atoms.
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
<MarketingSiteHeader brand="Relay" brandMark="/marks/relay.svg" links={[]} />
|
|
63
|
+
<FoilMark src="/marks/relay.svg" size={44} />
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Wordmarks and marks use contrast-bearing metal bands with a faint rainbow
|
|
67
|
+
reflection, including before hydration and on touch devices. The existing
|
|
68
|
+
`attachFoil` controller adds bounded pointer movement only when motion and
|
|
69
|
+
forced-color preferences permit it. `--hraness-foil-reflection` defaults to
|
|
70
|
+
`14%`; `--hraness-foil-image` can replace the shared text/mark paint. The
|
|
71
|
+
spectrum image belongs to wordmarks and marks only: `.hraness-foil` and
|
|
72
|
+
`[data-emphasis="primary"]` bordered surfaces keep a flat fill under one
|
|
73
|
+
theme-aware monochrome edge, black on light and white on dark, overridable
|
|
74
|
+
through `--hraness-foil-edge`. A blocked inline
|
|
75
|
+
mask style or unsupported masks retain the original image. Cross-origin masks
|
|
76
|
+
require the asset server's CORS permission; prefer local assets. Forced colors
|
|
77
|
+
remove the overlay entirely.
|
|
78
|
+
|
|
79
|
+
### Provider and agent marks
|
|
80
|
+
|
|
81
|
+
`providerMarks` (root entry) is the shared registry of coding-agent and
|
|
82
|
+
model-vendor identities: display name, aliases, accent color, monochrome
|
|
83
|
+
glyph, and vendor-colored artwork where the source publishes one. `providerMark()`
|
|
84
|
+
resolves any display name or alias by folded lowercase-alphanumeric match, so
|
|
85
|
+
"Claude Code", `claude-code`, and `claudecode` land on the same mark.
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
import { providerMark } from "@hraness/design-kit";
|
|
89
|
+
import { ProviderMark, ProviderMarkChip } from "@hraness/design-kit/react";
|
|
90
|
+
|
|
91
|
+
<ProviderMark mark="claudecode" size={40} />
|
|
92
|
+
<ProviderMark mark="crush" tone="solid" size={40} />
|
|
93
|
+
<ProviderMarkChip mark="goose" />
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`ProviderMark` renders an accent-tinted tile by default, a saturated brand
|
|
97
|
+
tile with `tone="solid"`, or the bare glyph with `tone="plain"`. Identity
|
|
98
|
+
artwork comes from vendored sources (`vendor/provider-marks/`, LobeHub
|
|
99
|
+
icons 1.95.1 plus the Crush and Aider marks documented in its UPSTREAM.md);
|
|
100
|
+
marks without published color art keep a retinted glyph, and unknown names
|
|
101
|
+
fall back to a neutral monogram tile rather than invented artwork. In forced
|
|
102
|
+
colors the artwork yields to a system-color glyph or monogram. Non-React
|
|
103
|
+
consumers can build data URIs with `providerMarkGlyphDataUri` and
|
|
104
|
+
`providerMarkArtDataUri`.
|
|
105
|
+
|
|
106
|
+
### Install commands for each platform
|
|
107
|
+
|
|
108
|
+
`PlatformInstall` (`@hraness/design-kit/react`) shows one tab per operating
|
|
109
|
+
system with that platform's mark, its install command, and a Copy button.
|
|
110
|
+
Every CLI site should use it for install commands so they look and behave
|
|
111
|
+
the same.
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
import { PlatformBadges, PlatformInstall } from "@hraness/design-kit/react";
|
|
115
|
+
|
|
116
|
+
<PlatformInstall
|
|
117
|
+
platforms={[
|
|
118
|
+
{
|
|
119
|
+
id: "macos",
|
|
120
|
+
command: "brew install hraness/tap/relay",
|
|
121
|
+
shell: "Terminal",
|
|
122
|
+
note: "Apple silicon and Intel",
|
|
123
|
+
alternatives: [{ label: "npm", command: "npm install --global relay" }],
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: "linux",
|
|
127
|
+
command: "curl -fsSL https://relay.example/install.sh | sh",
|
|
128
|
+
shell: "Terminal",
|
|
129
|
+
note: "x86_64 and ARM64, glibc 2.34+",
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
id: "windows",
|
|
133
|
+
unavailable: true,
|
|
134
|
+
unavailableNote: "No native build yet. Relay runs in WSL2.",
|
|
135
|
+
command: "curl -fsSL https://relay.example/install.sh | sh",
|
|
136
|
+
shell: "WSL2 terminal",
|
|
137
|
+
},
|
|
138
|
+
]}
|
|
139
|
+
/>
|
|
140
|
+
|
|
141
|
+
<PlatformBadges platforms={["macos", "linux", { id: "windows", note: "via WSL2" }]} />
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The server render selects `defaultPlatform` (the first platform when
|
|
145
|
+
omitted). After hydration the component selects the visitor's operating
|
|
146
|
+
system when it is listed; pass `detect={false}` to keep the default. The tabs
|
|
147
|
+
follow the ARIA tab pattern: arrow keys, Home, and End move between
|
|
148
|
+
platforms. Copy writes the exact command, shows "Copied", and announces the
|
|
149
|
+
result to screen readers; when the clipboard is blocked it selects the
|
|
150
|
+
command and says so. Long commands scroll inside their box, not the page.
|
|
151
|
+
Below 30rem the tab row spans its column and the tabs tighten, so macOS,
|
|
152
|
+
Linux, and Windows fit side by side at 320px without scrolling; a name is
|
|
153
|
+
truncated only when a longer platform list cannot fit. Each platform mark is
|
|
154
|
+
defined once per component as an SVG `<symbol>` and drawn by reference, so
|
|
155
|
+
the markup does not repeat the paths. Non-React sites that render the hook
|
|
156
|
+
classes should mirror the narrow rules on `.hraness-platform-install__tabs`,
|
|
157
|
+
`.hraness-platform-install__tab`, and `.hraness-platform-install__tab-label`.
|
|
158
|
+
Without JavaScript the tab row and Copy buttons hide and every platform's
|
|
159
|
+
commands show in order under their names. The component uses no inline
|
|
160
|
+
script or style, so it works under a strict content security policy.
|
|
161
|
+
|
|
162
|
+
`PlatformIcon` draws the Apple logo, Tux, or the Windows window in
|
|
163
|
+
`currentColor`, and a neutral terminal glyph for other ids. It is decorative
|
|
164
|
+
unless you pass `label`. `PlatformBadges` is a compact "Runs on" row for
|
|
165
|
+
heroes and footers; both are server-safe and also ship from
|
|
166
|
+
`@hraness/design-kit/react/server`. The root entry exports `platformLabel`,
|
|
167
|
+
`platformMark` (raw SVG paths for non-React sites), `detectPlatform`, and
|
|
168
|
+
`matchDetectedPlatform`. The Apple and Linux marks come from Simple Icons (CC0); see
|
|
169
|
+
`vendor/platform-marks/UPSTREAM.md`.
|
|
170
|
+
|
|
171
|
+
## Load the presentation layer
|
|
172
|
+
|
|
173
|
+
Import the complete stylesheet once after Tailwind, if the application uses it:
|
|
174
|
+
|
|
175
|
+
```css
|
|
176
|
+
@import "tailwindcss";
|
|
177
|
+
@import "@hraness/design-kit/styles.css";
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The complete stylesheet composes the token, reset, legacy component, and extracted StyleX layers from `@hraness/ui` before applying design-kit presentation. It keeps `base` below `components`, then freezes UI `legacy.base`, legacy, and priority1 through priority7 before the design-kit legacy and priority1-through-priority8 inventory. The design-kit manifest currently maps eight raw-priority buckets to those eight serialized ranks. Rank 1 begins with generated raw-priority-0 keyframes, so its keyframes and custom-property atoms are unlayered and `priority1` is reserved in the prelude; the remaining atomic output occupies the exact `priority2` through `priority8` blocks. Migrated declarations therefore win according to package ownership and StyleX priority without relying on import timing. Nebula Sans is the default proportional text and heading face, while explicit code and mono roles keep the system monospace stack. Package-owned atomic component presentation is authored in colocated `*.stylex.ts` files and compiled into deterministic `dist/stylex.css` with runtime injection disabled. `styles.css` reaches that local artifact once through `components.css`, so the public narrow component entry and the complete entry carry the same component recipes. Generated atomic class names are declaration hashes that may repeat across package layers; they are internal and do not identify package ownership. Use documented stable classes only when a composition exposes one. The notice retains logical block-axis inset and border declarations through canonical dashed StyleX properties. Its minimum height remains physical; the horizontal LTR and RTL compiler canary does not establish complete vertical-writing-mode parity.
|
|
181
|
+
|
|
182
|
+
Applications that compile local StyleX declarations register both `@hraness/ui/stylex-manifest.json` and `@hraness/design-kit/stylex-manifest.json` with the build tools from `@hraness/ui/stylex-build`. Import `@hraness/design-kit/compiler-foundation.css` for full design-kit compositions, or `@hraness/design-kit/compiler-palettes.css` for palettes, the appearance menu, and portable controls with application-owned typography. The minimal entry supplies the UI foundation and palette bridge without webfonts or marketing styles; the full entry includes it transitively. Neither route imports precompiled StyleX recipes. The finalizer unions the raw UI, design-kit, and application rules and serializes them once into `components.hraness-stylex`, after every package's legacy layers. Generation plans and completion records use schema 2 and bind the exact union policy; package manifests remain schema 1 and bind the minimal foundation. Start a fresh generation when upgrading the union policy. Every HTML or SSR entry links that finalized stylesheet after its foundation stylesheet. Do not combine this route with either package's `styles.css` or `stylex.css`.
|
|
183
|
+
|
|
184
|
+
Package authors use `createStylexTransformCollector` and `serializeStylexPackageRules` from `@hraness/ui/stylex-build` to publish externalized JavaScript, independently usable package CSS under a distinct `components.*` namespace, and a manifest that binds the raw rules, runtime files, standalone CSS, and compiler foundation. Final applications consume those manifests rather than concatenating independently serialized package stylesheets.
|
|
185
|
+
|
|
186
|
+
Import narrower layers when the application does not need the full presentation system:
|
|
187
|
+
|
|
188
|
+
```css
|
|
189
|
+
@import "@hraness/design-kit/tokens.css";
|
|
190
|
+
@import "@hraness/design-kit/charts.css";
|
|
191
|
+
@import "@hraness/design-kit/effects.css";
|
|
192
|
+
@import "@hraness/design-kit/syntax-highlighting.css";
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
`site-shell.css` keeps the footer at the viewport bottom on short pages and below content on long pages. Import it and add `hraness-site-shell` to the root containing the header, `main`, and footer as direct children:
|
|
196
|
+
|
|
197
|
+
```html
|
|
198
|
+
<body class="hraness-site-shell">
|
|
199
|
+
<header>…</header>
|
|
200
|
+
<main>…</main>
|
|
201
|
+
<footer>…</footer>
|
|
202
|
+
</body>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
For React apps with a root wrapper, put the class on that wrapper instead. If the content is a grid or another wrapper around `main`, add `hraness-site-shell__content` to that direct child so it fills the available height. Keep the content’s width and maximum measure in your page styles. The shell fills the dynamic viewport with a `vh` fallback. Multiple footer rows stay together in normal document flow. `body.plain-site` and `body.hraness-marketing-page` include this layout by default; nested theme and marketing examples opt in with `hraness-site-shell`. The standalone stylesheet has no dependencies and can accompany older design-kit styles.
|
|
206
|
+
|
|
207
|
+
`plain-site.css` provides a compact site shell. `plain-publication.css` adds sourced article, citation, table, callout, and related-reading structure. `reading.css` carries the shared long-form scale on `.hraness-prose` for docs and guide surfaces outside the publication shell; the same `--hraness-type-*` tokens size the publication article, and `data-hraness-reading-face="serif"` adapts the scale to serif display faces.
|
|
208
|
+
|
|
209
|
+
### Heading type from the shared foundation
|
|
210
|
+
|
|
211
|
+
`typography.css` (included in `styles.css` and `compiler-foundation.css`, or importable as `@hraness/design-kit/typography.css`) owns the heading scale for every site. Site CSS should not set a heading's size or face. A heading at level N reads three tokens:
|
|
212
|
+
|
|
213
|
+
```css
|
|
214
|
+
.my-section h3 {
|
|
215
|
+
font-family: var(--hraness-type-h3-font);
|
|
216
|
+
font-size: var(--hraness-type-h3-size);
|
|
217
|
+
font-weight: var(--hraness-type-h3-weight);
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
h1 and h2 use the display face (`--hraness-type-heading-font`, which follows `--hraness-marketing-display-font`). h3 and h4 use the text face (`--hraness-type-subheading-font`). The display face is used only at `--hraness-type-display-min` (1.75rem) or larger, and h2 never scales below it. Both marketing presets set the display face to Nebula Sans, so the floor mainly protects a product that opts in to a condensed serif, which is unreadable at card and label sizes. Choose the level by a heading's role in the page, not by the size you want: a heading that should look small is an h3 or h4, set in the text face.
|
|
222
|
+
|
|
223
|
+
## Share the Paper theme
|
|
224
|
+
|
|
225
|
+
`paper-theme.css` is a separate, zero-import CSS contract for warm neutral light
|
|
226
|
+
and dark surfaces, Nebula Sans font roles, and compact marketing typography.
|
|
227
|
+
Opt in with `data-hraness-theme="paper"` after the existing stylesheets. It can
|
|
228
|
+
be adopted from an immutable package release or as a verified CSS snapshot
|
|
229
|
+
without upgrading UI, React, or a StyleX compiler. Existing layouts and
|
|
230
|
+
appearance choices remain product-owned. See [Paper theme](PAPER_THEME.md) for
|
|
231
|
+
installation, compatibility, snapshot verification, and preference migration.
|
|
232
|
+
|
|
233
|
+
## Add Lantern material
|
|
234
|
+
|
|
235
|
+
Lantern gives opaque reading surfaces a luminous perimeter and selected controls a warm, matched fill and text color. Glass is reserved for chrome with scrolling content behind it. The selected palette, existing focus indicators and product layout remain authoritative.
|
|
236
|
+
|
|
237
|
+
Set `data-hraness-material="lantern"` on a themed host and apply the documented surface hooks. Complete stylesheets include the material; selective and older consumers can import a verified CSS snapshot. React primitives use the compiled `lanternControlStyles` through their existing `controlXstyle` prop. `ThemeMenuButton` picks up the material by itself: raised at rest, inset while pressed, with a Lantern menu.
|
|
238
|
+
|
|
239
|
+
See the [material contract and examples](LANTERN_MATERIAL.md) for palette islands, portal hosts, accessibility fallbacks and the immutable installer. The gallery demonstrates light and dark workspaces with working search, selection and disclosures.
|
|
240
|
+
|
|
241
|
+
## Explain a technical product
|
|
242
|
+
|
|
243
|
+
`product-marketing.css` is an opt-in narrative grammar for technical product
|
|
244
|
+
sites. It gives every Hraness product one typeface, one measured type scale,
|
|
245
|
+
sentence-case labels, hairline chrome, soft radii, and one accent color, so the
|
|
246
|
+
portfolio reads as one studio's work. The roles are a sticky site header, a main landmark that clears that header,
|
|
247
|
+
equal-height product card rows, an outcome-led hero with an optional product
|
|
248
|
+
frame, a row of pillars, an install panel, an ordered flow, fact and stat strips,
|
|
249
|
+
narrative sections, numbered primitives, interface and trust cards, attributed
|
|
250
|
+
quotes, pricing, native questions, a maker section, a closing call to action,
|
|
251
|
+
and an in-flow site footer. The classes own
|
|
252
|
+
responsive structure and semantics-facing presentation.
|
|
253
|
+
|
|
254
|
+
When a page also mounts the shared network footer from `@hraness/site-footer`,
|
|
255
|
+
render it directly after the marketing footer: the grammar joins the pair into
|
|
256
|
+
one band instead of two stacked bars. The product row's bottom space collapses
|
|
257
|
+
to a compact gap, and the network row's content follows the marketing measure
|
|
258
|
+
and gutter through the footer's documented `--hraness-site-footer-measure`
|
|
259
|
+
seam, so both registers share one column. Products bind the
|
|
260
|
+
`--hraness-marketing-*` roles to their own content and set one accent:
|
|
261
|
+
|
|
262
|
+
```css
|
|
263
|
+
@import "@hraness/design-kit/styles.css";
|
|
264
|
+
|
|
265
|
+
.hraness-marketing-page {
|
|
266
|
+
--hraness-site-accent: oklch(0.55 0.21 262);
|
|
267
|
+
--hraness-site-accent-ink: #ffffff;
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Static sites may render the documented classes directly. React sites can use
|
|
272
|
+
the server-safe compositions from either React entry:
|
|
273
|
+
|
|
274
|
+
```tsx
|
|
275
|
+
import {
|
|
276
|
+
MarketingCallToAction,
|
|
277
|
+
MarketingMain,
|
|
278
|
+
MarketingPage,
|
|
279
|
+
MarketingPillars,
|
|
280
|
+
MarketingProofFrame,
|
|
281
|
+
MarketingSiteHeader,
|
|
282
|
+
ProductHero,
|
|
283
|
+
} from "@hraness/design-kit/react/server";
|
|
284
|
+
|
|
285
|
+
<MarketingPage>
|
|
286
|
+
<MarketingSiteHeader
|
|
287
|
+
action={{ href: "#install", label: "Install Relay" }}
|
|
288
|
+
brand="Relay"
|
|
289
|
+
links={[{ href: "#how", label: "How it works" }, { href: "#pricing", label: "Pricing" }]}
|
|
290
|
+
/>
|
|
291
|
+
<MarketingMain>
|
|
292
|
+
<ProductHero
|
|
293
|
+
actions={[
|
|
294
|
+
{ href: "#install", label: "Install Relay" },
|
|
295
|
+
{ href: "#how", label: "See how it works" },
|
|
296
|
+
]}
|
|
297
|
+
boundary="Free for local use on macOS and Linux · version 1.2.3"
|
|
298
|
+
example="Ask your agent to run the nightly job and show you the log."
|
|
299
|
+
eyebrow="A reference developer tool"
|
|
300
|
+
frame={(
|
|
301
|
+
<MarketingProofFrame caption="The log written by the example job." credit="Captured 5 September 2026" title="relay run job-01">
|
|
302
|
+
<img alt="Relay printing a run log in a terminal" src="/relay-log.png" />
|
|
303
|
+
</MarketingProofFrame>
|
|
304
|
+
)}
|
|
305
|
+
heading="Run a job from your terminal, your code, or your agent"
|
|
306
|
+
headingId="relay-title"
|
|
307
|
+
name="Relay"
|
|
308
|
+
summary="Relay runs the same job wherever you start it and writes a log you can read afterward: inputs, outputs, and how long it took."
|
|
309
|
+
/>
|
|
310
|
+
<MarketingPillars
|
|
311
|
+
ariaLabel="Relay in three points"
|
|
312
|
+
columns={3}
|
|
313
|
+
pillars={[
|
|
314
|
+
{ label: "No hosted service", summary: "Jobs run on your machine and never wait on a server." },
|
|
315
|
+
{ label: "A log for every run", summary: "Open it to see what went in, what came out, and when." },
|
|
316
|
+
{ label: "Your files stay put", summary: "Source files and credentials never leave your machine." },
|
|
317
|
+
]}
|
|
318
|
+
/>
|
|
319
|
+
<MarketingCallToAction
|
|
320
|
+
actions={[{ href: "#install", label: "Install Relay" }]}
|
|
321
|
+
footnote="Free for local use on macOS and Linux."
|
|
322
|
+
heading="Start with one job"
|
|
323
|
+
headingId="cta-title"
|
|
324
|
+
/>
|
|
325
|
+
</MarketingMain>
|
|
326
|
+
</MarketingPage>
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
A sticky `MarketingSiteHeader` publishes `--hraness-sticky-offset` on the
|
|
330
|
+
page and on `html`, so siblings inherit it. Wrap page content in
|
|
331
|
+
`MarketingMain` (`id="main-content"`) so skip links and hash targets use that
|
|
332
|
+
offset as scroll-margin. Do not add extra padding when the header stays in
|
|
333
|
+
flow; pass `clearance="pad"` only for a `data-position="fixed"` header. The
|
|
334
|
+
next sticky strip should use `.hraness-sticky-below-chrome` or
|
|
335
|
+
`data-hraness-sticky` instead of `top: 0`. When the header wraps, render
|
|
336
|
+
`StickyOffsetSync` once from `@hraness/design-kit/react` or call
|
|
337
|
+
`syncStickyOffset` from `@hraness/design-kit/browser` to replace the token
|
|
338
|
+
fallback with the measured border box. `MarketingCardRow` stretches every
|
|
339
|
+
direct child to the tallest item in the row and reserves a two-line meta
|
|
340
|
+
block; titles wrap and are not clamped. `MarketingCardArt` /
|
|
341
|
+
`.hraness-marketing-card__art` clips each card's logo or media well so
|
|
342
|
+
background paint cannot bleed through the gutter.
|
|
343
|
+
|
|
344
|
+
`tone="accent"` on the hero or the call to action paints that role edge to
|
|
345
|
+
edge in the product accent. `layout="split"` or `"split-reverse"` on a
|
|
346
|
+
section places its heading group beside its body. `MarketingQuoteGrid` and
|
|
347
|
+
`MarketingPillars` render nothing for an empty list, so a site adds quotes
|
|
348
|
+
only when it has real, attributed ones.
|
|
349
|
+
|
|
350
|
+
For a policy with `style-src-attr 'none'`, set `columns` to `1`, `2`, `3`, or
|
|
351
|
+
`4` on `MarketingFacts`, `MarketingPillars`, and `MarketingStatStrip`. Set
|
|
352
|
+
`factsColumns` on `ProductHero` for its nested facts. These finite choices use
|
|
353
|
+
compiled recipes and emit no inline column style. Below 48rem, facts and stats
|
|
354
|
+
still use two columns and pillars use one. Omitting the prop preserves the
|
|
355
|
+
existing item-count custom property, including its inline style and arbitrary
|
|
356
|
+
collection length. Use the compiled standalone stylesheet or the finalized
|
|
357
|
+
compiler-adopter stylesheet with the finite choices.
|
|
358
|
+
|
|
359
|
+
`MarketingNotice` renders one status or alert line — a redirect confirmation, a
|
|
360
|
+
failed action — on the content edge of the page column, with `tone` set to
|
|
361
|
+
`info`, `success`, or `error`. Errors use `role="alert"`; the other tones use
|
|
362
|
+
`role="status"`. Signed-in account pages inside `MarketingSiteHeader` compose
|
|
363
|
+
`MarketingMain`, `MarketingNotice`, `MarketingStatStrip`, and `MarketingSection`
|
|
364
|
+
so every block shares the header's measure and gutter; they do not add
|
|
365
|
+
full-bleed banners or cards nested inside sections.
|
|
366
|
+
|
|
367
|
+
`ProductHero.notice` renders product-owned content after the boundary text in
|
|
368
|
+
the hero's copy group. `MarketingInstallPanel.note` renders after its heading,
|
|
369
|
+
before the separate command group. Both accept React nodes without adding a
|
|
370
|
+
wrapper. Omit them to preserve the existing markup. `MarketingMaker.linkClassName`
|
|
371
|
+
adds a caller class to its listed links only; it does not style biography links.
|
|
372
|
+
|
|
373
|
+
Use `MarketingSectionLabel` for a native paragraph with the same label recipe
|
|
374
|
+
as `MarketingSection`. Its default preserves the existing label presentation;
|
|
375
|
+
`size="body"` selects the compiled 1rem variant. Override
|
|
376
|
+
`--hraness-marketing-example-measure` in a product stylesheet to change only
|
|
377
|
+
the hero example's maximum inline size. When absent, it uses
|
|
378
|
+
`--hraness-marketing-copy-measure`; the summary's measure is unchanged.
|
|
379
|
+
|
|
380
|
+
Homepage copy on this grammar follows [`STYLE.md`](STYLE.md) and
|
|
381
|
+
[`MARKETING_COPY.md`](MARKETING_COPY.md), which gives each slot its job and its
|
|
382
|
+
length limit. The headline states what the reader can do, in sentence case with
|
|
383
|
+
no period. The summary says what the product is, who it is for, and the one
|
|
384
|
+
thing it does differently. The `example` is a concrete request a reader could
|
|
385
|
+
make. State the release status once, plainly, in `boundary`, and keep each other
|
|
386
|
+
limit beside the feature it limits. A full-sentence section heading in the
|
|
387
|
+
editorial preset may end with a period; other headings do not. Words such as
|
|
388
|
+
"bounded", "exact", "authority", "custody", "immutable", and "inspectable" stay
|
|
389
|
+
out of the hero and leads. Every number has a date or a source, and no quote
|
|
390
|
+
appears without an attributed author who agreed to it.
|
|
391
|
+
|
|
392
|
+
Import only the grammar when a site owns its reset and tokens:
|
|
393
|
+
|
|
394
|
+
```css
|
|
395
|
+
@import "@hraness/design-kit/product-marketing.css";
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
The components render complete server HTML and add no clipboard, animation, or
|
|
399
|
+
analytics runtime. A
|
|
400
|
+
product may enhance a command with its own accessible copy control while
|
|
401
|
+
keeping selectable text as the fallback.
|
|
402
|
+
|
|
403
|
+
## Publish articles
|
|
404
|
+
|
|
405
|
+
The article layer renders long-form posts with a title, a one-sentence dek, a byline, published and updated dates, a visible drafting and review note, an optional contents list, sources, and related products. React and static sites get identical markup, styled by `plain-publication.css` (included in `styles.css`). The body keeps a 68ch measure, and the contents list moves beside it on wide screens. [`ARTICLE_COPY.md`](ARTICLE_COPY.md) gives the article shapes and the rules for provenance, freshness, and links.
|
|
406
|
+
|
|
407
|
+
```tsx
|
|
408
|
+
import {
|
|
409
|
+
ArticleSources,
|
|
410
|
+
MarketingArticle,
|
|
411
|
+
} from "@hraness/design-kit/react/server";
|
|
412
|
+
import { articleProvenanceFromAdmission } from "@hraness/design-kit";
|
|
413
|
+
|
|
414
|
+
<MarketingArticle
|
|
415
|
+
author={{ kind: "organization", name: "Hraness" }}
|
|
416
|
+
dek="Relay replays a failed webhook from the stored request body."
|
|
417
|
+
eyebrow="Technique"
|
|
418
|
+
heading="Replaying webhooks without breaking signatures"
|
|
419
|
+
provenance={articleProvenanceFromAdmission(admission)}
|
|
420
|
+
published="2026-09-10"
|
|
421
|
+
toc={[{ href: "#approach", label: "The approach" }]}
|
|
422
|
+
after={<ArticleSources sources={sources} />}
|
|
423
|
+
>
|
|
424
|
+
{body}
|
|
425
|
+
</MarketingArticle>
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
`ArticleIndex` lists posts, `ArticleCallout` marks a note, limit, or warning, and `ArticleRelatedProducts` wraps `MarketingRelated`. Static site builders import `renderArticleHtml`, `renderArticleIndexHtml`, `renderArticleSourcesHtml`, `renderArticleCalloutHtml`, and `renderArticleRelatedHtml` from the framework-neutral root and load `@hraness/design-kit/plain-publication.css` after `plain-site.css`. Text arguments are escaped; `bodyHtml` and `afterHtml` take HTML the site already rendered.
|
|
429
|
+
|
|
430
|
+
Each host keeps an `ArticleAdmission` record per article and checks the registry in a test:
|
|
431
|
+
|
|
432
|
+
```ts
|
|
433
|
+
import { assertArticleAdmissions } from "@hraness/design-kit";
|
|
434
|
+
|
|
435
|
+
assertArticleAdmissions(registry);
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
A record passes when its six 0 to 2 scores total at least 9 with no zero. An `indexable` record also needs a review with a reviewer type, dated sources, two observations, and a refresh trigger, and every reviewed record needs `reassessOn` 28 to 56 days after the review. The provenance sentence says "human" only for a human editor's review.
|
|
439
|
+
|
|
440
|
+
### Write a launch post
|
|
441
|
+
|
|
442
|
+
An "Introducing" post is a column of 7 to 10 beats. Each beat makes one claim, shows one visual, and doubles as one social post, except the `limits` beat and beats marked `social: false`, which stay in the post. Keep the numbers in one facts module and build the posts from the beats:
|
|
443
|
+
|
|
444
|
+
```tsx
|
|
445
|
+
import { assertLaunchKit, buildSocialKit, resolveLaunchBeats } from "@hraness/design-kit/launch";
|
|
446
|
+
import { LaunchBeats, SocialKitPanel } from "@hraness/design-kit/react";
|
|
447
|
+
|
|
448
|
+
const beats = resolveLaunchBeats(draftBeats, launchFacts);
|
|
449
|
+
const kit = buildSocialKit(beats, portfolioMessaging, { status: "Preview" }, canonicalUrl);
|
|
450
|
+
assertLaunchKit(beats, kit, { status: "Preview", publicInstall: false, canonicalUrl });
|
|
451
|
+
|
|
452
|
+
<LaunchBeats beats={beats} renderVisual={(beat) => <Visual beat={beat} />} />
|
|
453
|
+
<SocialKitPanel kit={kit} />
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
Draw the visuals with `@hraness/design-kit/mockups` and load `@hraness/design-kit/mockups.css`. Build the social kit only once the post is `indexable`. Product tests can run the checks from `@hraness/design-kit/testing`, such as `blogConformance` for the blog and `assertRoleImgWithLabel` for each mockup. See [ARTICLE_COPY.md](ARTICLE_COPY.md) for the beat rules.
|
|
457
|
+
|
|
458
|
+
Hraness product sites run the whole launch with the `product-launch` agent skill: mockups, the post, the social kit, the launch film, and comparison pages. It also lists the checks to run before you publish.
|
|
459
|
+
|
|
460
|
+
### Share product facts
|
|
461
|
+
|
|
462
|
+
`@hraness/design-kit/portfolio` holds the public facts about Hraness products: each product's name, one-liner, canonical URL, status, and other names, plus the registered relations between products. It is a snapshot generated from one commit of the portfolio registry, recorded in `portfolioProvenance`, and it renders nothing.
|
|
463
|
+
|
|
464
|
+
```tsx
|
|
465
|
+
import { ArticleRelatedProducts } from "@hraness/design-kit/react/server";
|
|
466
|
+
import { product, relatedFor, usesPairs } from "@hraness/design-kit/portfolio";
|
|
467
|
+
|
|
468
|
+
const textbutler = product("message-like-me");
|
|
469
|
+
|
|
470
|
+
<ArticleRelatedProducts headingId="related" items={relatedFor("message-like-me")} />;
|
|
471
|
+
|
|
472
|
+
for (const { relation, source, target } of usesPairs()) {
|
|
473
|
+
console.log(source.name, relation.label, target.name, relation.detail);
|
|
474
|
+
}
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
`relatedFor(id)` returns one card per related product, and only for relations with a written detail sentence. Each item carries the product's `mark` (the portfolio artwork hraness.com shows, as a `data:image/svg+xml` URL) and its one-line `role`; the cards show the mark, name, and role, as on the hraness.com project index. The relation's `relationship` sentence stays on the item for articles that quote it. `usesPairs()` lists the integration relations that have one. Static sites read the same data from `@hraness/design-kit/portfolio.json`. Pin `portfolioDigest` in a test so an upgrade that changes the facts shows up in review.
|
|
478
|
+
|
|
479
|
+
## Use application compositions
|
|
480
|
+
|
|
481
|
+
```tsx
|
|
482
|
+
import { Button, Icon, ViewportFrame } from "@hraness/ui";
|
|
483
|
+
import {
|
|
484
|
+
AppShell,
|
|
485
|
+
NavigationRail,
|
|
486
|
+
PageCanvas,
|
|
487
|
+
RailItem,
|
|
488
|
+
RailSection,
|
|
489
|
+
TopBar,
|
|
490
|
+
} from "@hraness/design-kit/react";
|
|
491
|
+
import { DashboardSquare01Icon } from "@hugeicons/core-free-icons";
|
|
492
|
+
|
|
493
|
+
export function Workspace() {
|
|
494
|
+
const rail = (
|
|
495
|
+
<NavigationRail>
|
|
496
|
+
<RailSection title="Workspace">
|
|
497
|
+
<RailItem
|
|
498
|
+
href="/"
|
|
499
|
+
icon={<Icon icon={DashboardSquare01Icon} />}
|
|
500
|
+
isActive
|
|
501
|
+
label="Overview"
|
|
502
|
+
/>
|
|
503
|
+
</RailSection>
|
|
504
|
+
</NavigationRail>
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
return (
|
|
508
|
+
<ViewportFrame>
|
|
509
|
+
<AppShell rail={rail} topBar={<TopBar title="Workspace" />}>
|
|
510
|
+
<PageCanvas>
|
|
511
|
+
<Button variant="primary">Create project</Button>
|
|
512
|
+
</PageCanvas>
|
|
513
|
+
</AppShell>
|
|
514
|
+
</ViewportFrame>
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
Connect routing with `RouterProvider` from `@hraness/ui`. Design-kit rail links use that public router context and intent-prefetch contract.
|
|
520
|
+
|
|
521
|
+
`AnimatedRailStage` keeps the surrounding shell mounted while one keyed route stage enters and exits through `AnimatePresence` in wait mode. The public `stageKey`, stable class, `data-stage-key`, and caller-last `className` contracts remain unchanged. Its logical minimum and reduced-motion fallback are delivered through extracted StyleX classes. Reduced motion keeps content visible, removes translation and duration from the motion recipe, and forces any Motion-authored transform and transition off in CSS.
|
|
522
|
+
|
|
523
|
+
`ChatMessage` keeps its article, finite `data-role`, optional avatar, header, and action slots, and caller-last root class while its grid, logical minimum, and metadata-row presentation are delivered through extracted StyleX classes. `ChatComposer` remains a controlled native form composition with a multiline field and submit button. It always prevents native navigation, calls its callback only for an enabled, non-pending, nonblank value, and keeps native form attributes and inline styles caller-controlled. Its two-column layout collapses to one column at the existing compact breakpoint. Neither component exposes a public `xstyle` or ref seam.
|
|
524
|
+
|
|
525
|
+
`TopBar`, `BottomBar`, `PageCanvas`, and `DockedFooter` keep their native header, footer, main, or div semantics while their product-neutral layout recipes are delivered through extracted StyleX classes. Their stable classes and data attributes remain available for semantic inspection, and native `className` and `style` props remain caller-controlled. `DockedFooter` continues to forward its root footer ref. Its `surface` value remains a stable data hook; only `TopBar` gives `glass` a visual treatment. Its 90% tint and 18px blur use feature detection; unsupported filtering, reduced transparency, and forced colors use an opaque surface.
|
|
526
|
+
|
|
527
|
+
`DitherSurface` composes its product-neutral texture through the typed `ThemedSurface` seam from `@hraness/ui`. Its `density` is one of `coarse`, `fine`, or `medium`; the default medium texture uses `4px`, while coarse and fine set the literal public `--hraness-design-dither-size` property to `7px` and `3px`. A caller `xstyle` recipe is applied after the shared texture, and native `style` remains last for deliberate per-instance overrides. Forced-colors mode removes the decorative image without changing the surface's content, native element, tone, shape, or border.
|
|
528
|
+
|
|
529
|
+
`PlaybackTransport` keeps one large primary command through idle, pending, and playing states. Give the toolbar exactly one of `aria-label` or `aria-labelledby`; the command changes its accessible label, glyph, busy state, and play or stop callback without changing its stable button hook. Its wrapping toolbar recipe and exact `1.5rem` logical glyph and spinner dimensions are delivered through extracted StyleX classes. The existing root `className`, button id, keyboard-shortcut, button-ref, and trailing-control seams remain available.
|
|
530
|
+
|
|
531
|
+
`Fader` keeps the full React Aria single-value slider contract while defaulting to a vertical, default-density control with a hidden accessible label and output. Its default and compact dimensions, horizontal variant, label row, rails, thumb, and focus-visible state are delivered through extracted StyleX classes. The two decorative rail nodes are inert and keep the logical geometry that the former pseudo selectors provided without expanding the package layer range. Existing root and input refs, visible label and accessory, output, caller `className`, native slider props, and native `style` overrides remain available. Native styles may override the public `--hraness-design-fader-*` properties for a deliberate per-instance size.
|
|
532
|
+
|
|
533
|
+
## Show status pages
|
|
534
|
+
|
|
535
|
+
`RouteNotFoundPage`, `RouteErrorPage`, and `GlobalErrorDocument` render one shared page for missing addresses and recoverable errors: the product's main action, a "Did you mean" link to the closest known page, up to three places to start, and a decorative glyph drawn as dots that react to the pointer. Static sites render the same markup with `renderStatusPageHtml` and enhance it with `attachStatusPage` from `@hraness/design-kit/browser`. [`STATUS_PAGES.md`](STATUS_PAGES.md) says what to put in each slot.
|
|
536
|
+
|
|
537
|
+
```tsx
|
|
538
|
+
<RouteNotFoundPage
|
|
539
|
+
siteName="Sponge"
|
|
540
|
+
primaryAction={{ href: "/start", label: "Start your library" }}
|
|
541
|
+
next={[{ href: "/docs", label: "Docs", description: "Connect Claude, ChatGPT, or any MCP client." }]}
|
|
542
|
+
routes={knownPages}
|
|
543
|
+
agentIndexHref="/llms.txt"
|
|
544
|
+
/>
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
## Use charts and syntax
|
|
548
|
+
|
|
549
|
+
Charts own responsive geometry, exact-value accessibility, reduced motion, and forced-color behavior. Applications own data, labels, units, and categorical colors.
|
|
550
|
+
|
|
551
|
+
```tsx
|
|
552
|
+
import { BarListChart, SyntaxCode } from "@hraness/design-kit/react";
|
|
553
|
+
|
|
554
|
+
<BarListChart
|
|
555
|
+
aria-label="Requests by region"
|
|
556
|
+
data={[
|
|
557
|
+
{ id: "north", label: "North", value: 72 },
|
|
558
|
+
{ id: "south", label: "South", value: 48 },
|
|
559
|
+
]}
|
|
560
|
+
/>
|
|
561
|
+
|
|
562
|
+
<pre>
|
|
563
|
+
<SyntaxCode code={'const ready = true;'} />
|
|
564
|
+
</pre>
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
`SyntaxCode` and `highlightCode(code)` choose a language for recognizable code when the language is omitted. The deterministic rules recognize JSON objects and arrays, common package and Git commands, and distinctive TypeScript, Markdown, HTML, and CSS syntax. Prose and uncertain input stay plain text. Pass a language or Markdown fence hint to keep an explicit choice. Rust, TOML, YAML, Lean, and TLA+ use explicit language hints and keep comments and multiline strings intact; unsupported hints and `language="text"` remain plain text. Blocks longer than 131,072 characters also remain escaped plain text.
|
|
568
|
+
|
|
569
|
+
The framework-neutral highlighter is available from `@hraness/design-kit/syntax-highlighting`. For sites that disallow inline styles, call `highlightCode(code, "typescript", { styles: "classes" })` or pass `styles="classes"` to `SyntaxCode`. Import `syntax-highlighting.css` when using the highlighter alone; the complete stylesheet, compiler foundation, and narrow `product-marketing.css` entry include it. The default style mode remains unchanged; both modes share the same theme colors and preserve source line breaks. Markdown renderers should pass each literal code block and its fence hint to this shared highlighter. Stylesheets do not tokenize raw `<pre><code>` markup.
|
|
570
|
+
Server components can import `SyntaxCode`, deterministic procedural effects, and
|
|
571
|
+
static surfaces from `@hraness/design-kit/react/server` without crossing the
|
|
572
|
+
client boundary used by the interactive React barrel.
|
|
573
|
+
|
|
574
|
+
## Foil cards and decks
|
|
575
|
+
|
|
576
|
+
`FoilCardSurface` adds deterministic material paint behind semantic card
|
|
577
|
+
content. Use `renderMode="static"` for image capture and other motionless
|
|
578
|
+
surfaces. Interactive cards work on their own; a collection should be wrapped
|
|
579
|
+
once in `FoilCardDeck`, which delegates pointer and focus interaction through a
|
|
580
|
+
single controller and keeps geometry cached for the active descendant.
|
|
581
|
+
|
|
582
|
+
```tsx
|
|
583
|
+
import { FoilCardDeck, FoilCardSurface } from "@hraness/design-kit/react";
|
|
584
|
+
|
|
585
|
+
<FoilCardDeck aria-label="Reference cards" className="card-grid">
|
|
586
|
+
{records.map((record) => (
|
|
587
|
+
<FoilCardSurface
|
|
588
|
+
intensity="standard"
|
|
589
|
+
key={record.id}
|
|
590
|
+
ornament="circuit"
|
|
591
|
+
preset="aurora"
|
|
592
|
+
renderMode="interactive"
|
|
593
|
+
seed={record.id}
|
|
594
|
+
>
|
|
595
|
+
<article>{record.label}</article>
|
|
596
|
+
</FoilCardSurface>
|
|
597
|
+
))}
|
|
598
|
+
</FoilCardDeck>
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
The optional `ornament` is one of `none`, `corners`, `rails`, `circuit`,
|
|
602
|
+
`radial`, or `facets`. It affects edge paint only, so product content remains
|
|
603
|
+
legible. Set `--foil-card-radius` on a surface or deck descendant to match a
|
|
604
|
+
product-owned card radius. Fine-pointer movement activates directional
|
|
605
|
+
diffraction; keyboard focus gets a motionless material cue. Touch, reduced
|
|
606
|
+
motion, and forced-colors modes keep ordinary semantic content intact, and no
|
|
607
|
+
inactive card receives `will-change`.
|
|
608
|
+
|
|
609
|
+
## Semantic palettes
|
|
610
|
+
|
|
611
|
+
Opt into Catppuccin, Gruvbox, Rosé Pine, or Tokyo Night in light or dark mode. `DesignPaletteProvider` and the existing `ThemeMenuButton` provide one appearance menu, with Catppuccin dark as the default. The shared controller supports external bootstrap scripts and strict content security policies. See [palette installation, semantic roles, and sources](./PALETTES.md).
|
|
612
|
+
|
|
613
|
+
## Appearance and fonts
|
|
614
|
+
|
|
615
|
+
Wrap browser applications with `DesignThemeProvider` and render
|
|
616
|
+
`ThemeMenuButton` as the final action in the product header. It exposes one
|
|
617
|
+
icon-only trigger and a Light, Dark, or System menu with the same presentation
|
|
618
|
+
across products. The first visit defaults to System and follows the device
|
|
619
|
+
preference. Explicit Light, Dark, and System choices persist under a versioned
|
|
620
|
+
Hraness-neutral key. Server-rendered document roots may use Light as a safe
|
|
621
|
+
concrete baseline while the blocking appearance bootstrap resolves the stored
|
|
622
|
+
or System preference before paint.
|
|
623
|
+
|
|
624
|
+
Show a timestamp with `RelativeTime` from `@hraness/design-kit/react`. It
|
|
625
|
+
renders `<time>` with the ISO instant in `dateTime`, the local date and time in
|
|
626
|
+
`title`, and relative text such as "5 minutes ago" or "in 23 hours". Pass `now`
|
|
627
|
+
to render the same text on the server and during hydration. After mount it
|
|
628
|
+
follows the browser clock and refreshes as often as the shown unit can change.
|
|
629
|
+
Set `refreshInterval` to a fixed number of milliseconds, or to `"off"` to keep
|
|
630
|
+
`now`. Framework-neutral code can call `formatRelativeTime(value, { now,
|
|
631
|
+
locale, numeric })` from the package root. Both throw on an invalid date instead
|
|
632
|
+
of printing "Invalid Date".
|
|
633
|
+
|
|
634
|
+
`ThemeColorSync` leaves adaptive media-qualified server tags in control until a
|
|
635
|
+
concrete Light or Dark preference resolves. It then owns one active browser
|
|
636
|
+
chrome color, temporarily neutralizes competing same-name tags, and restores
|
|
637
|
+
their exact media conditions after the final synchronized owner unmounts.
|
|
638
|
+
|
|
639
|
+
Use `GlobalErrorDocument` for a Next root `global-error` boundary. It remains
|
|
640
|
+
control-free because the normal product header is unavailable. Its System
|
|
641
|
+
default emits adaptive Light and Dark `theme-color` metadata plus a
|
|
642
|
+
`light dark` `color-scheme` before hydration, then follows the same stored
|
|
643
|
+
preference as the application. Products with their own canvas colors pass the
|
|
644
|
+
same palette once:
|
|
645
|
+
|
|
646
|
+
```tsx
|
|
647
|
+
<GlobalErrorDocument
|
|
648
|
+
darkColor="#101419"
|
|
649
|
+
error={error}
|
|
650
|
+
lightColor="#f4efe7"
|
|
651
|
+
reset={reset}
|
|
652
|
+
/>
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
An explicitly fixed `theme="light"` or `theme="dark"` emits one matching,
|
|
656
|
+
unqualified `theme-color` and a fixed `color-scheme` without mounting the
|
|
657
|
+
preference provider.
|
|
658
|
+
|
|
659
|
+
Static HTML products use the same composition without a client framework:
|
|
660
|
+
|
|
661
|
+
```ts
|
|
662
|
+
import { installAppearanceMenus } from "@hraness/design-kit/browser";
|
|
663
|
+
|
|
664
|
+
installAppearanceMenus({
|
|
665
|
+
darkThemeColor: "#09090d",
|
|
666
|
+
lightThemeColor: "#f7f3ea",
|
|
667
|
+
storageKey: "product-appearance",
|
|
668
|
+
});
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
Load `@hraness/design-kit/appearance-menu.css`, render one progressive
|
|
672
|
+
`[data-hraness-appearance-menu]` composition as the final header action, and
|
|
673
|
+
bundle the installer into a small blocking local script. The installer applies
|
|
674
|
+
the stored or System preference before the stylesheet loads, synchronizes
|
|
675
|
+
browser chrome, and supplies the same icon, menu, keyboard, focus, and storage
|
|
676
|
+
contract as the React control. Importing the browser module has no side effects.
|
|
677
|
+
|
|
678
|
+
Nebula Sans is bundled under the SIL Open Font License and loads through `tokens.css` for ordinary text and headings. Explicit serif treatments remain product-owned, and code and mono roles keep the system monospace stack. Geist Mono remains available as an optional display face:
|
|
679
|
+
|
|
680
|
+
Content Security Policies must allow same-origin font assets with `font-src 'self'`.
|
|
681
|
+
Bundlers configured to inline font assets also require `data:` in that directive.
|
|
682
|
+
|
|
683
|
+
```css
|
|
684
|
+
@import "@hraness/design-kit/fonts.css";
|
|
685
|
+
|
|
686
|
+
:root {
|
|
687
|
+
--font-heading: var(--font-geist-mono);
|
|
688
|
+
}
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
Applications may override semantic roles in a local stylesheet after the design-kit import. Keep deliberate serif and monospace treatments explicit so they are not absorbed into the proportional default. The public package contains no restricted font assets or metric overrides.
|
|
692
|
+
|
|
693
|
+
Generated artwork can import `nebulaSansSocialFonts` from
|
|
694
|
+
`@hraness/design-kit/fonts/nebula-sans/social`. It returns the official Book and
|
|
695
|
+
Bold OTF payloads without a remote request or runtime filesystem lookup, ready
|
|
696
|
+
for an `ImageResponse` `fonts` option.
|
|
697
|
+
|
|
698
|
+
## Migrating Jelly surfaces
|
|
699
|
+
|
|
700
|
+
The Jelly surface API, stylesheet export, and browser runtime have been removed.
|
|
701
|
+
Replace `JellySurface` wrappers with the appropriate native or `@hraness/ui`
|
|
702
|
+
primitive. Apply the [shared material roles](./LANTERN_MATERIAL.md) to that
|
|
703
|
+
semantic element when it needs a surface treatment. Keep labels, refs, disabled
|
|
704
|
+
and pending behavior, keyboard interaction, and portal ownership on the
|
|
705
|
+
primitive. Remove imports of `@hraness/design-kit/jelly.css` and any direct
|
|
706
|
+
Jelly runtime integration. `DesignThemeProvider` continues to manage appearance
|
|
707
|
+
and portal themes without loading a decorative control runtime.
|
|
708
|
+
|
|
709
|
+
The EvilCharts license and adaptation provenance remain under `vendor/evilcharts`.
|
|
710
|
+
|
|
711
|
+
## Gallery
|
|
712
|
+
|
|
713
|
+
`DesignSystemGallery` is an executable, product-neutral reference for the package boundary. Mount it in a development route and import `design-gallery.css` through the complete stylesheet. The gallery exercises Chat message slots, controlled composer submission, compact responsive layout, extracted class delivery, and caller-last classes alongside the other public compositions.
|
|
714
|
+
|
|
715
|
+
## Development
|
|
716
|
+
|
|
717
|
+
Provision the pinned test browser with `bun run browser:install` after installing dependencies. Browser checks use that Playwright revision by default. `CHROMIUM_EXECUTABLE_PATH` (or `CHROME_PATH`) may select an explicitly provisioned Chrome for Testing executable. Invalid overrides fail; checks never fall back to an installed personal browser. Each check reports the selected executable and version.
|
|
718
|
+
|
|
719
|
+
Use Bun 1.3.14:
|
|
720
|
+
|
|
721
|
+
```sh
|
|
722
|
+
bun install --frozen-lockfile
|
|
723
|
+
bun run browser:install
|
|
724
|
+
bun run check
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
The stable dependency pair for this release is `@hraness/ui` `v0.5.17` with `@hraness/design-kit` `v0.31.1`. Version 0.31.0 keeps the `limits` beat and beats marked `social: false` out of the social kit and adds `socialPost` for social wording that stands without a caveat. Version 0.30.3 refreshes the portfolio snapshot so related-product cards use each product's own spelling, such as GhostGet and TextButler. Version 0.30.2 keeps the narrow and stacked install-tab layout when another package compiles the same atoms into a later cascade layer. Version 0.30.1 keeps every PlatformInstall tab name whole in columns down to 200px by stacking each mark above its name, using a container query on the component. Version 0.30.0 adds `site-shell.css`, which keeps short-page footers at the viewport bottom. Version 0.29.3 preserves readable selected install tabs in forced colors. Version 0.29.2 keeps all three PlatformInstall tabs visible at 320 to 360px and draws each platform mark once per component. Version 0.29.1 keeps marketing action labels readable in forced colors. Version 0.29.0 adds `PlatformInstall`, one install block for every CLI site: a tab per operating system with its mark, the install command with a Copy button that announces the result, optional alternative commands such as npm or Homebrew, and a note for platforms without a native build. After hydration it selects the visitor's operating system; without JavaScript every command shows. It also adds `PlatformIcon` (Apple, Tux, and Windows marks in `currentColor`) and a `PlatformBadges` "Runs on" row, plus `platformLabel`, `platformMark`, `detectPlatform`, and `matchDetectedPlatform` at the package root. See [Install commands for each platform](#install-commands-for-each-platform). No existing export changes. Version 0.28.0 adds the launch kit. `@hraness/design-kit/mockups` draws labelled illustrations of chat, feeds, inboxes, articles, terminals, browsers, desktop windows, menu bars, and phones in server-safe plain React with no StyleX or React Aria, styled by `@hraness/design-kit/mockups.css`; each renders as one image with a text description and no headings. `@hraness/design-kit/mockups/client` adds `ModeShowcase`, `FitToWidth`, and `StepThrough`. `@hraness/design-kit/launch`, with no React, holds the `LaunchBeat`, `LaunchFacts`, and `SocialKit` shapes with `resolveLaunchBeats`, `buildSocialKit`, and `assertLaunchKit`. `@hraness/design-kit/testing` gives product repositories `blogConformance`, `renderMatrix`, `assertNoHeadings`, `assertRoleImgWithLabel`, and `assertFakeHandles`. The React entries add `ArticleFigure`, `ArticleVideo` with `articleVideoJsonLd`, `ArticleTable`, `ArticleBarChart`, `ComparisonTable`, `LaunchBeats`, and `SocialKitPanel`, and `MarketingProofFrame` takes `chrome` (`window`, `browser` with `url`, or `terminal`). [ARTICLE_COPY.md](ARTICLE_COPY.md) now writes "Introducing a product" as beats; the admission rules are unchanged. No existing export changes. Version 0.27.0 adds explicit Rust, TOML, YAML, Lean, and TLA+ code highlighting, including nested comments and multiline strings. The existing highlighter API and stylesheet remain the shared entry points; unsupported languages still render as escaped text. Version 0.26.0 adds `MarketingNotice` and the raw `.hraness-marketing-notice` class: one status or alert line (`info`, `success`, or `error`) that sits on the content edge of the page column instead of spanning the window. Errors are announced as alerts and other tones as status. Signed-in account pages that render inside `MarketingSiteHeader` should compose `MarketingMain`, `MarketingNotice`, `MarketingStatStrip`, and `MarketingSection` so every block shares the header's measure and gutter, rather than hand-rolled full-bleed banners and nested cards. Version 0.25.0 moves bordered foil surfaces off the spectrum: `.hraness-foil` and `[data-emphasis="primary"]` actions keep their flat surface fill under one theme-aware monochrome edge — black on light, white on dark, overridable through the new `--hraness-foil-edge` token — while the metallic spectrum stays on wordmarks and marks. The foil material contract advances to version 3: `surfaceImage` and `surfaceBackgroundClip` are replaced by `surfaceFill`, `edge`, `edgeDark`, and `edgeColor`. Reinstall any vendored marketing snapshot from the 0.25.0 commit. Version 0.24.0 joins a marketing footer directly followed by the shared `@hraness/site-footer` network footer into one band: the product row's bottom space collapses to a compact gap and the network row's content follows the marketing measure and gutter through `--hraness-site-footer-measure`, so product links and the organization row share one column instead of reading as two stacked bars. Mount the network footer directly after `MarketingSiteFooter`; no prop or markup change is needed inside either landmark. Version 0.23.0 moves marketing pages to the Quiet direction described in [DESIGN.md](DESIGN.md). `ProductHero` no longer renders a backdrop, `HeroBackdrop` renders nothing, and `attachHeroLight` is an inert disposer; their names and props stay so existing code compiles and are marked deprecated. The `cells`, `weave`, `contour`, and `mesh` patterns render as `none`, and marketing fields and Lantern walls paint the flat palette background. Both marketing presets use Nebula Sans for display headings (editorial at weight 550); Instrument Serif stays vendored for explicit opt-in only. Hero eyebrows are plain labels, the accent band loses its grid, and cards and header chrome use hairline edges instead of lifted shadows. On phones `MarketingSiteHeader` keeps the brand, primary action, and appearance menu on one row and moves the links to a second row that scrolls sideways, with 44px targets. To migrate, delete `backdrop` artwork, `HeroBackdrop`, `attachHeroLight`, pattern values, and product CSS that recreated textures or serif headings, then reinstall any vendored marketing snapshot from the 0.23.0 commit. Version 0.22.2 restores the canonical roughday mark — the rain-cloud artwork pinned by the portfolio registry — after the mark slot briefly carried a stray illustration. Version 0.22.1 completes the icon library with the roughday inline chip family (65 admitted assets, no pending members). Version 0.22.0 adds the `./icons` surface: 62 vetted single-ink assets across ten sets — a shared illustration family, product illustration families, and the product marks, each admitted through a measured gate (single ink, bounded aspect, coverage, stroke, paths, bytes) and per-set family coherence, distributed as a typed registry module (`hranessIcons`, `hranessIcon`, `hranessIconMarkup`, `hranessIconsForSet`) and as canonical `./icons/<set>/<slug>.svg` files for image consumers. See [ICONS.md](ICONS.md). Version 0.21.1 accepts status-page `routes` straight from a sitemap: long titles are shortened for the "Did you mean" line and unusable entries are dropped instead of failing the render. Version 0.21.0 replaces the 404 and route-error pages with one shared status page: the product's main action, a "Did you mean" link to the closest known page, at most three next links with one-line descriptions, an optional line for AI agents, and a glyph drawn as dots that gather, move away from the pointer, and settle. `RouteNotFoundPage`, `RouteErrorPage`, and `GlobalErrorDocument` render it; `renderStatusPageHtml` and `attachStatusPage` bring the same page to static sites; `status-page.css` ships in `styles.css` and `compiler-foundation.css`. The default copy changes to "We can’t find that page". See [STATUS_PAGES.md](STATUS_PAGES.md). Version 0.20.0 gives `ThemeMenuButton` the Lantern material: under `data-hraness-material="lantern"` its trigger is raised at rest and inset while pressed, and its menu uses the material plane, lift and warm selection, with no new props. Sites can delete their local Lantern CSS for the appearance menu. It also adds `formatRelativeTime` at the package root and a hydration-safe `RelativeTime` component in `@hraness/design-kit/react`. Version 0.19.0 redraws related-product cards as the hraness.com project cards: each shows the product's mark, its name, and its one-line `role` at reading size, and no longer renders the `relationship` sentence (the prop stays accepted and is deprecated). `MarketingRelatedProduct` and the static `ArticleRelatedLink` take a `mark`, and every `@hraness/design-kit/portfolio` product and `relatedFor()` item now carries its portfolio mark as an inert `data:image/svg+xml` URL. Related-tier and proof headings move to the new `--hraness-marketing-h3-size` token, so the editorial display face never renders below 1.75rem. `typography.css` gains per-level heading tokens (`--hraness-type-h1-font` through `--hraness-type-h4-font`, the matching `-weight` tokens, `--hraness-type-subheading-font`, and `--hraness-type-display-min`). h3 and h4 in `.hraness-prose` and publication articles now use the text face, and the h2 floor rises to 1.75rem. Version 0.18.3 adds the Sponge and Wordcell runtime relations to Oh to the `@hraness/design-kit/portfolio` snapshot, so related-product cards on all three sites can link them. Version 0.18.2 refreshes the `@hraness/design-kit/portfolio` snapshot from the registry: the public ghostget.com entry, updated Gobstopper and xcb naming and descriptions, and the current sibling-product relations for related-product cards. Version 0.18.1 adds the Perplexity mark and a dependency-free `@hraness/design-kit/provider-marks` leaf entry (`providerMark`, `providerMarks`, `providerMarkFallback`, `providerMarkGlyphDataUri`, `providerMarkArtDataUri`, `providerMarkOnAccent`, `providerMarkMonogram`) so packages such as `@hraness/ui` can consume the registry without pulling the marketing surface. Version 0.18.0 adds the shared provider-mark registry: `providerMarks`, `providerMark()` alias resolution, `ProviderMark`/`ProviderMarkChip` accent-tinted tile components on both React entry points, vendored agent and vendor artwork from LobeHub icons 1.95.1 plus documented Crush and Aider marks, monogram fallbacks for uncovered names, and data-URI helpers for CSS-mask consumers. See `vendor/provider-marks/UPSTREAM.md` for asset provenance. Version 0.17.2 carries the canonical portfolio messaging record per product (`names`, `category`, `tagline`, `short`, `meta`, `medium`, `long`, and hero copy) in the `/portfolio` snapshot. Version 0.17.1 lets Next.js apps that compile dependencies with Babel build the article layer: its link check no longer uses a Unicode property escape that Babel cannot rewrite, and it rejects the same control characters and whitespace as before. Version 0.17.0 adds the article layer: server-safe `MarketingArticle`, byline, provenance, sources, callout, related-product, and index components, a matching static HTML renderer for sites without React, long-form article styles in `plain-publication.css`, and the `ArticleAdmission` rubric with `assertArticleAdmissions()`. It also adds `@hraness/design-kit/portfolio`, a snapshot of public product names, one-liners, links, and relations for related-product cards and "How X uses Y" posts. See [ARTICLE_COPY.md](ARTICLE_COPY.md). Version 0.16.4 keeps native appearance-menu labels usable inside keyboard-focusable page landmarks, including mouse and touch selection. Version 0.16.3 keeps decorative hero backgrounds hidden in forced colors and reduced transparency when other packages load their styles afterward. Version 0.16.2 preserves palette hues in translucent headers, material surfaces, and decorative highlights. Version 0.16.1 keeps plain reading pages and nested compiled surfaces in their selected palette, including system appearance without JavaScript. Version 0.16.0 adds a shared bounded hero light, product-owned backdrop slots, five Lantern patterns, palette-derived soft surfaces, and responsive typography across marketing and reading layouts. Static sites can use the palette bridge for system appearance before JavaScript. See [HERO_FIELDS.md](HERO_FIELDS.md), [LANTERN_MATERIAL.md](LANTERN_MATERIAL.md), and [MARKETING_PRESET.md](MARKETING_PRESET.md). Version 0.15.0 lets `MarketingRelated` present labeled tiers of sibling products: a `groups` collection renders each tier under its own heading with an accessible card-row label, while the flat `items` shape stays available for a single group. Version 0.14.0 adds `MarketingRelated`, a collection section that presents sibling products as linked cards, each framed by its relationship to the featured product. Version 0.13.0 publishes `--hraness-sticky-offset` from sticky marketing chrome, gives `MarketingMain` and the next sticky sibling a clearance contract, stretches marketing card rows to the tallest item with a reserved two-line meta block, and clips per-card art wells so a logo surface cannot paint through the gutter. Version 0.12.0 replaces pointer-driven gradient rotation with a steady material and a moving light: the spectrum and its 115deg direction stay fixed while `--hraness-foil-x`/`--hraness-foil-y` highlights travel across each lockup, and marketing footers can opt into the same icon-plus-wordmark foil as the site header with `brandMark`. Version 0.11.1 preserves visible metallic marks when another package repeats a generic hidden atom in a later CSS layer. React consumers load `components.css` or `styles.css`; the raw marketing entry supports authored HTML hooks. Version 0.11 adds server-rendered `FoilMark` artwork and metallic text with subtle rainbow reflections, including a shared header mark seam and original-artwork fallbacks. Version 0.10.1 adds conservative server syntax defaults, includes their styles in the narrow marketing entry, and pins the icon dependency to preserve fresh Linux installs. Version 0.10 adds the shared foil contract: `.hraness-foil` surfaces and `.hraness-foil-text` wordmarks render a pointer-following metallic spectrum from the `--hraness-foil-*` custom properties, applied by default to marketing header brands and primary actions. The `attachFoil` browser export drives the bounded `x`/`y`/`angle` inputs with damped easing, reduced-motion and forced-color fallbacks, and no style injection; the same spectrum feeds `@hraness/site-footer` signup controls. Dark appearances use a deeper palette so the sheen stays visible. Version 0.8 removes Jelly's optional API, stylesheet, vendor runtime and theme-provider side effect. Migrate direct Jelly surfaces to native shared primitives before upgrading. Lantern now uses softer directional depth and shaded faces; the marketing preset adds individually shaded static cells, theme-aware terminal colors and window chrome. Code blocks retain source lines and follow the active palette. Paper preferences, semantic palettes, and compiler identity stay stable. Compiler adopters must regenerate their finalized stylesheet with the new package manifest.
|
|
728
|
+
|
|
729
|
+
The complete check runs linting, typechecking, production builds, an installed-package smoke test, deterministic examples, property tests, server rendering, vendor-integrity checks, and headless Chromium regressions. The browser gate verifies responsive shell ownership, extracted AnimatedRailStage, Fader, layout-surface, and playback-transport delivery, reduced-motion stage fallback, Fader keyboard and focus behavior, forced-color behavior, keyboard-operable appearance, browser-chrome synchronization across opposing device and saved preferences, global-error static metadata and runtime lifecycle, accessible title and copy, deterministic procedural layers, viewport containment, and the absence of the excluded canvas effect. Set `CHROMIUM_EXECUTABLE_PATH` when Chromium or Chrome is installed outside the standard macOS and Linux paths.
|
|
730
|
+
|
|
731
|
+
Global CSS remains the boundary for tokens, resets, document grammar, cross-component layout, accessibility media rules, and audited vendor fallbacks. A new overlapping compiled style family from another package requires a layer-order compatibility gate against that package's released artifact before adoption.
|
|
732
|
+
|
|
733
|
+
Read [CONTRIBUTING.md](./CONTRIBUTING.md) before opening a pull request. Report suspected vulnerabilities as described in [SECURITY.md](./SECURITY.md).
|
|
734
|
+
|
|
735
|
+
## License
|
|
736
|
+
|
|
737
|
+
MIT. Vendored Nebula Sans, Geist Mono, and other upstream artifacts retain their own included license and provenance files.
|
|
738
|
+
|
|
739
|
+
### Shared editorial marketing preset
|
|
740
|
+
|
|
741
|
+
Import `@hraness/design-kit/product-marketing-preset.css` after your existing marketing styles, then opt in with `<MarketingPage preset="editorial">`. The editorial preset sets one large Nebula Sans heading at weight 550 on the flat palette background, with hairline rules and a thin header whose links move to their own scrolling row on phones. `preset="minimal"` uses a more compact sans hierarchy. Hero backdrops, patterns, and textures are retired; see [Hero fields](HERO_FIELDS.md). Product accents and copy remain product-owned.
|
|
742
|
+
|
|
743
|
+
[Writing for the marketing components](MARKETING_COPY.md) says what each slot is for and which copy patterns to avoid.
|
|
744
|
+
|
|
745
|
+
[Marketing preset contract](MARKETING_PRESET.md) documents the native HTML hooks, shared tokens, paint-only header hook, and immutable CSS/font/asset snapshots for consumers that retain an older component release. The preset leaves application UI outside its explicit scope untouched.
|