Public website and documentation hub for nSealr.
Non-profit, open-source program for Nostr signing devices. The site explains the program without turning the core work into a proprietary product.
- Astro 5 (static output) + TypeScript strict.
- Markdown / MDX content collections —
blog,docs,signers,authors— validated by Zod schemas at build time. Bad frontmatter fails the build. - JetBrains Mono + Inter (variable, self-hosted from
public/fonts/). - Light / dark theme with Nostr purple
#8E30EBas the primary accent. Toggle persists inlocalStorage, respectsprefers-color-schemeon first load, no FOUC. - Pagefind for static client-side search.
- Shiki for syntax highlighting (dual-theme:
github-dark-dimmedmin-light).
- Vercel preset with strict CSP, immutable cache for
/_astro/*and/fonts/*. The CSPscript-srchash is computed fromsrc/scripts/theme-init.tsbyscripts/compute_csp_hash.mjsat every build, sovercel.jsonstays in sync.
make setup # pnpm install --frozen-lockfile
make dev # → http://localhost:4321make build # → dist/ (astro build + pagefind + og images)
make ci # check + build + validate_site.py + unittest + lintscripts/validate_site.py scans the built dist/ tree:
HOME_REQUIRED_TEXT— required brand + safety-contract strings ondist/index.html.- Each signer family page (
dist/docs/signers/<family>/index.html) contains its declaredrequiredTextfrom the MDX frontmatter. dist/security/index.htmlcontains the safety-contract phrases.- No forbidden production claims appear anywhere.
- No
/vaultrepo link appears anywhere.
The project is Vercel-preset-aware. Connect the repo, framework =
astro. Production = push to main; preview deploys per PR. Custom domain
target is nsealr.com.
- Blog post: add
src/content/blog/<date>-<slug>.mdx. - Doc page: add
src/content/docs/<section>/<slug>.mdxwithsectioningetting-started | guides | signers | specs | security. - Signer family update: edit
src/content/signers/<family>.mdx. Thecapabilitiesarray mirrorsnSealr/specs vectors/features/signer-feature-matrix-v0.json— the samecontract_idmust keep the same behavior across families.
website/
astro.config.mjs · vercel.json(.tpl) · package.json · Makefile
public/ # fonts, favicon, robots, og-default.png
src/
content/ # MDX + JSON content (blog, docs, signers, authors)
components/ # Astro UI primitives
layouts/ # BaseLayout, DocsLayout, BlogPostLayout
pages/ # routes
styles/ # tokens.css, base.css, prose.css
scripts/ # theme-init.ts (inline blocking script source)
lib/ # docs-nav.ts, og.mjs
scripts/
validate_site.py # required-text / forbidden-claims validator
verify_repo.py # repo lint
build_og.mjs # satori OG image generation
compute_csp_hash.mjs # writes vercel.json from vercel.json.tpl
og-fonts/ # TTF fonts used only by satori
tests/
test_site_validation.py
nSealr/specs, nSealr/companion, nSealr/raspberry,
nSealr/esp32, nSealr/smartcard, nSealr/hardware, nSealr/lab.
MIT for code. CC0-1.0 for content when published.