Skip to content

Architecture and Customization

a9x edited this page Sep 7, 2026 · 6 revisions

StarryBio is a static Astro application. A TypeScript configuration object is validated and normalized at build/request time during development, then Astro renders the profile page and client scripts add the small interactive behaviors (starfield, copy feedback, status dialog, announcement dismissal, and Google Analytics initialization).

Data and rendering flow

config/starrybio.config.ts
        │
        ▼
src/config/schema.ts ── validation + normalization
        │
        ▼
src/config/site.ts
        │
        ▼
src/pages/index.astro → BaseLayout → components
        │                              │
        │                              └─ config values become static HTML
        ▼
src/scripts/app.ts → starfield, copy buttons, status, announcement, GA runtime

There is no server API or persisted application state in this flow. Configuration visibility is calculated when the static site builds; browser-only status and announcement behavior are described in Availability and Announcements.

Project map

Location Responsibility Edit here when…
config/starrybio.config.ts Complete example/site configuration. Changing one deployed profile’s content or supported settings.
src/config/schema.ts Zod schema, TypeScript types, validation, defaults, normalization, visibility rules. Adding/changing a public config field or its default.
src/config/site.ts Imports, validates, and normalizes the user config. Changing how the sole config entry is loaded.
src/config/themes.ts Preset token definitions and CSS-property generation. Adding or changing a built-in theme preset.
src/config/icons.ts Simple Icon normalization, filenames, and raw-path handling. Changing icon configuration/generation behavior.
src/config/analytics.ts Provider script descriptors and safe data attribute serialization. Adding or adjusting an analytics provider.
src/config/urls.ts / image-assets.ts External-link safety attributes and local/generated asset URL conversion. Changing URL or asset rendering rules.
src/pages/index.astro The profile home page composition. Adding/reordering page-level components.
src/pages/404.astro Custom static 404 page. Changing unknown-route presentation.
src/layouts/BaseLayout.astro HTML document, SEO, analytics injection, starfield container, client bootstrapping. Changing document-level markup or page-wide integrations.
src/components/ Profile, links, featured cards, announcement, status, SEO, analytics, and icons. Changing a specific visible feature.
src/scripts/ Browser interactions. Changing copy, schedule/dialog, starfield, announcement, or GA behavior.
src/styles/ Theme tokens, layout rules, shared components, motion, Tailwind import. Changing CSS or responsive behavior.
scripts/ Validation, generated asset, Simple Icon, and live-config tooling. Changing build-time behavior.
public/ Static user assets and deployed _headers. Adding local media or changing security/cache headers.
tests/ Vitest unit coverage and Playwright browser release checks. Covering altered behavior.
wrangler.jsonc Worker name, compatibility date, static dist/ asset deployment. Changing Cloudflare deployment/routing.
vercel.json Vercel static build, output, and header translation. Changing Vercel deployment behavior.
netlify.toml Netlify static build and publish settings. Changing Netlify deployment behavior.
.github/workflows/deploy-github-pages.yml GitHub Pages build, Pages metadata, artifact upload, and deployment. Changing the Pages deployment behavior.

Add or change a configuration option

Treat a public config property as an end-to-end contract. For example, adding a profile display option generally needs all of these changes:

  1. Add a strict Zod field and TypeScript type in src/config/schema.ts.
  2. Decide and implement its normalization/default behavior there.
  3. Add it to config/starrybio.config.ts if the starter config should demonstrate it.
  4. Pass/read the normalized property in the relevant component, style, or browser script.
  5. Add focused unit tests under tests/unit/ for acceptance, rejection, and default behavior.
  6. Update Configuration Reference and the feature page explaining its practical effect.
  7. Run type checks, build, and browser tests.

Do not make validation permissive merely to avoid documenting the behavior. The current strict schema is intentional: it catches stale configuration before a deployment.

Add a theme or layout

For a theme preset:

  1. Add the preset name to THEME_PRESET_NAMES in src/config/themes.ts; the strict schema consumes that catalog.
  2. Add one declarative definition to THEME_PRESETS, including its intentional appearance, semantic colors, background treatment, and any optional decoration, radius, typography, or star-color tokens.
  3. Prefer shared defaults in the theme-definition helper and shared component tokens over duplicating a complete palette or branching in a component.
  4. Add CSS only when a new semantic token or reusable treatment cannot express the design cleanly.
  5. Verify every layout at narrow and wide sizes, including long/minimal content, hover and keyboard focus, contrast, and prefers-reduced-motion.

For a layout mode:

  1. Add the name to the layout schema enum.
  2. Add a complete responsive rule set in src/styles/layout.css.
  3. Ensure mobile collapse is intentional, not an accidental overflow.
  4. Add the needed component class/data usage if the existing ProfileCard class composition cannot express it.
  5. Update the Appearance and Branding table and browser tests where behavior is observable.

Use CSS custom properties emitted by getThemeStyle rather than hard-coding one preset’s colors into a component. This keeps every preset usable.

Add a new page or route

Create an Astro page under src/pages/. Astro will build a corresponding static HTML output. Configured root-relative links such as /about are rebased automatically for a GitHub Pages project site; relative links retain normal page-relative behavior. In source components, use toSitePath() for a root-relative internal link and toAbsoluteAssetPath() for an asset under public/ so the same code remains portable.

The stock Worker’s not_found_handling is 404-page; GitHub Pages, Vercel, and Netlify natively serve the generated 404.html. Do not add an SPA fallback unless you also implement client-side routing intentionally. The GitHub Pages workflow is the supported subpath deployment path; other hosts should serve the normal root-hostname artifact unless their own routing/build design accounts for a prefix.

Add a browser interaction

src/scripts/app.ts is the client entry point. It initializes behavior on Astro’s astro:page-load event and cleans it up before a transition swap using an AbortController. Follow that lifecycle for event listeners and timers so a new interaction does not duplicate handlers during client navigation.

Avoid inserting unescaped user configuration into executable JavaScript or innerHTML. Existing components render Astro values normally, serialize analytics JSON safely for attributes, and use textContent when dynamically creating schedule content.

Add an analytics provider

  1. Extend the discriminated analytics schema in src/config/schema.ts.
  2. Add a script descriptor branch in src/config/analytics.ts.
  3. Use HTTPS script URLs and data attributes; do not add an inline analytics script.
  4. Update the generated policy source in src/config/security-headers.ts, then run pnpm headers.
  5. Add unit coverage and a placeholder-only configuration example.
  6. Update SEO and Analytics and Security and Privacy.

Treat all browser analytics identifiers as public. Never add server-side credentials to static configuration.

Change generated assets

scripts/generate-assets.ts owns OG image, QR, and vCard generation; scripts/build-simple-icons.ts owns Simple Icon output. Both run before each build and remove stale configured/default output. Preserve that lifecycle when adding a generator so disabling a feature cannot leave a public stale artifact in a later deployment.

Use resolveOutputPath from scripts/config-utils.ts for generated paths so output remains under public/. Add coverage to tests/unit/assets.test.ts for escaping, file production, and cleanup behavior.

Evolve deployment deliberately

All supported providers serve the same static dist/ artifact. Adding API routes, auth, storage, functions, adapters, or provider bindings changes the project’s operational model and documentation requirements. Keep provider-specific behavior in the thin deployment layer, document secrets/bindings, and test each affected deployment path separately.

For the existing static deployment, use Deployment Overview. For quality gates and project contribution conventions, use Testing and Contributing.

Clone this wiki locally