Landing site
Content and assets
Add blog posts and documentation pages through Astro content collections, refresh product screenshots, and regenerate Open Graph images.
Content collections
Blog posts and documentation pages are Astro content collections defined in src/content.config.ts.
Adding a Markdown file to a collection is enough: the sidebar, search index, prev/next navigation and
the raw /docs/<slug>.md route are all derived from the collection.
- Blog: add
src/content/blog/<slug>.mdwith frontmattertitle,description,publishDateand optionalupdatedDate,author,tags,draft,ogImage. Setdraft: trueto keep a post out of the production build. - Docs: add
src/content/docs/<slug>.mdwith frontmattertitle,description,sectionandorder. Pages are grouped bysectionand sorted byorder; a section appears in the sidebar at the position of its lowest-ordered page (these Landing site pages sit in theLanding sitesection).
Screenshots and the home page
The product screenshots in public/screenshots/ are real captures from the running app, taken by
scripts/capture-screenshots.mjs (its header documents the seed and capture flow). Re-run that script
after a UI change rather than editing the images by hand. ScreenshotFrame.astro renders each capture
in both theme variants under a slim address bar.
The home page’s “What’s inside” section is InsideExplorer.astro, fed by src/lib/inside.ts: one entry
per area of the template, each with its items, an optional screenshot and the app route it opens in the
live demo. Every area renders into the static HTML, so search engines and visitors without JavaScript
see all of them; a small script turns the list into tabs, and /#inside-<id> links open one area.
Optional modules (billing, MCP, user notifications, the demo) sit inside their <module>:begin and
<module>:end marker lines in that file and on the page, so a scaffold with --no-billing and friends
removes them from the landing site too. Keep new module-specific copy inside those markers.
The counts in the home page’s stack strip (handlers, .NET tests, frontend tests) are read from the
repository at build time by src/lib/repoStats.ts, so they never go stale. A count the build cannot
read, for example in a landing-only checkout, is left out.
Open Graph images
Open Graph images are generated at build time. The build:og script (scripts/generate-og.mjs) runs
automatically before astro build when you run pnpm build, producing the default public/og-image.png
plus a per-page image under public/og/... for each page, blog post and docs page. There is no manual
step: build the site and the images are regenerated. The generator renders text with the TTF copies of
the brand fonts in scripts/fonts/; librsvg cannot read the woff2 files the site itself uses.
Checklist
- Add content by dropping a Markdown file into
src/content/blog/orsrc/content/docs/with the right frontmatter. - Re-run
scripts/capture-screenshots.mjsafter UI changes; do not hand-edit the screenshots. - Add or change home-page features in
src/lib/inside.ts, with module-specific entries inside their scaffold markers. - Run
pnpm buildto produce the static site and regenerate every Open Graph image.