# Build and deploy

> Static site build to dist, deploy-anywhere assumptions, and operational notes for the zero-JS-by-default Astro field guide.

- Repository: yetone/kill-ai-slop
- GitHub: https://github.com/yetone/kill-ai-slop
- Human docs: https://grok-wiki.com/public/docs/yetone-kill-ai-slop-c0d8c9670cbb
- Complete Markdown: https://grok-wiki.com/public/docs/yetone-kill-ai-slop-c0d8c9670cbb/llms-full.txt

## Source Files

- `website/astro.config.mjs`
- `website/src/pages/index.astro`
- `website/src/layouts/Base.astro`
- `README.md`
- `website/src/styles/global.css`

---

---
title: "Build and deploy"
description: "Static site build to dist, deploy-anywhere assumptions, and operational notes for the zero-JS-by-default Astro field guide."
---

The field guide lives under `website/` as a single Astro content site. Production output is a static `dist/` tree: `npm run build` writes files you can host on any static origin. Live site: **https://killaislop.com**.

## What gets built

| Surface | Path / role |
| --- | --- |
| Site root | `website/` — multilingual field guide (en, zh, ja, ko) |
| Config | `website/astro.config.mjs` — `site`, `build.inlineStylesheets` only; no integrations |
| Entry page | `website/src/pages/index.astro` — hero, catalogue, principles, skill sections |
| Layout shell | `website/src/layouts/Base.astro` — document head, pre-paint scripts, `Nav` / `Footer` |
| Styles | `website/src/styles/global.css` (imports tokens + demos) |
| Skill package | `skill/` — **not** part of the site build; install and run separately |

Repo layout (from the project README):

```text
website/   Astro site, the field guide (multilingual, static, zero-JS-by-default)
skill/     the kill-ai-slop Agent Skill (SKILL.md + references + scanner)
```

## Astro configuration

`website/astro.config.mjs` is intentionally minimal: static, dependency-light, no Astro integrations.

```js
import { defineConfig } from 'astro/config';

// Kill AI Spop is a single, static, dependency-light content site.
// No integrations by design — the build artifact should be as lean as the
// aesthetic it argues for.
export default defineConfig({
  site: 'https://killaislop.com',
  build: {
    inlineStylesheets: 'auto',
  },
});
```

| Key | Value | Effect |
| --- | --- | --- |
| `site` | `https://killaislop.com` | Base for absolute URLs (`Astro.site`) used in canonical and Open Graph metadata |
| `build.inlineStylesheets` | `'auto'` | Lets Astro decide when stylesheets are inlined into HTML |
| Integrations / adapters | none | No SSR adapter; build is static HTML/CSS/assets |

<Note>
If you fork and deploy under a different public origin, update `site` so `canonical`, `og:url`, and `og:image` stay correct. Absolute share URLs are built from `Astro.site` in `Base.astro`.
</Note>

## Prerequisites

- Node.js with `npm` available
- Working directory: `website/`
- Dependencies installed once: `npm install`

No host-specific CLIs, env files, or CI config are required by the site source as documented.

## Build commands

From the repository root:

```bash
cd website
npm install
npm run dev        # http://localhost:4321
npm run build      # → dist/  (static, deploy anywhere)
```

| Command | Purpose | Success signal |
| --- | --- | --- |
| `npm install` | Install site dependencies | Completes without install errors |
| `npm run dev` | Local Astro dev server | Serves at `http://localhost:4321` |
| `npm run build` | Production static build | Writes `dist/` (static; deploy anywhere) |

<Steps>
  <Step title="Install">
    ```bash
    cd website
    npm install
    ```
  </Step>
  <Step title="Build">
    ```bash
    npm run build
    ```
    Expect a static artifact under `dist/` relative to `website/`.
  </Step>
  <Step title="Deploy">
    Publish the contents of `dist/` to any static host (object storage + CDN, Pages, Netlify, nginx, etc.). No Node server or Astro adapter is required for the production artifact described in the README.
  </Step>
</Steps>

## Deploy-anywhere assumptions

The README states the build is **static** and can be **deployed anywhere**. Operational constraints that follow from the evidence:

1. **Static origin only** — Serve the built files over HTTPS (or HTTP in private previews). No server-side rendering or API routes are configured.
2. **Root-relative assets** — Head links use root paths such as `/favicon.svg` and `/og.png`. Host `dist/` at the site root of the public origin (or ensure those paths resolve if you change layout).
3. **Canonical site URL** — `site: 'https://killaislop.com'` drives absolute metadata. Mismatched deploy hostname vs `site` yields wrong OG/canonical URLs, not a failed HTML serve.
4. **No build-time env vars** — Language, theme, and sound preferences are client `localStorage` keys (`kas-lang`, `kas-theme`, `kas-sound`), not deploy-time secrets.
5. **Skill is out of band** — Deploying the field guide does not install or run `skill/`. Scanner and agent skill install are separate (`npx skills add yetone/kill-ai-slop` or manual copy).

```text
  source (website/)
        │
        │  npm run build
        ▼
     dist/   static HTML + CSS + assets
        │
        │  any static host
        ▼
  public origin (e.g. killaislop.com)
```

## Runtime behavior baked into the static pages

“Zero-JS-by-default” means no framework client islands or integrations in config. `Base.astro` still ships small **inline** head scripts for pre-paint preferences (no flash):

| Concern | Storage key | Behavior |
| --- | --- | --- |
| Language | `kas-lang` | Valid: `en`, `zh`, `ja`, `ko`. Missing/invalid → derive from `navigator.language` (zh/ja/ko prefixes) else `en`. Sets `data-lang` and `lang` on `<html>`. |
| Sound | `kas-sound` | `"off"` → `data-sound="off"`; otherwise `"on"` (default). |
| Theme | `kas-theme` | Only `"light"` or `"dark"` set `data-theme`; otherwise unset so CSS follows OS via `@media`. |
| Deep links | (none) | On load, if `location.hash` matches an id, scroll to it; then may add `.nav-ready` for smooth scrolling unless `prefers-reduced-motion: reduce`. |

All locales are present in the HTML; visibility is CSS-driven:

```css
/* global.css — every language is rendered; only the active data-lang shows */
[data-lang="en"] [data-t]:not([data-t="en"]),
[data-lang="zh"] [data-t]:not([data-t="zh"]),
[data-lang="ja"] [data-t]:not([data-t="ja"]),
[data-lang="ko"] [data-t]:not([data-t="ko"]) {
  display: none;
}
```

Static hosts must not strip inline `<script>` tags if language/theme/sound pre-paint is required.

## Share metadata and static assets

`Base.astro` builds absolute metadata from `Astro.site`:

| Field | Construction |
| --- | --- |
| Canonical | `new URL(Astro.url.pathname, Astro.site)` |
| OG / Twitter image | `new URL("/og.png", Astro.site)` → `https://killaislop.com/og.png` at production site |
| Favicon | `/favicon.svg` (`type="image/svg+xml"`) |
| OG size | width `1200`, height `630`, type `image/png` |
| Locales in OG | `en_US` plus alternates `zh_CN`, `ja_JP`, `ko_KR` |

Default document title/description (overridable via layout props):

- **title:** `Kill AI Slop — 杀死 AI slop`
- **description:** bilingual field-guide blurb (EN + ZH in the default string)

OG art source is noted in comments as `capture/og/og.html` (authoring reference for the share card); production serves `/og.png`.

## Verification checklist

After build and deploy:

| Check | Expected |
| --- | --- |
| `npm run build` | Completes; `dist/` present under `website/` |
| Open site root | Index loads (hero, catalogue of 23 tells, principles, skill CTAs) |
| View source / network | Static assets; favicon at `/favicon.svg` |
| Share card fetch | `/og.png` returns 1200×630 PNG when present on host |
| Language | First paint respects stored `kas-lang` or browser language among en/zh/ja/ko; CSS hides inactive `[data-t]` |
| Hash link | `/#catalogue` (or another entry id) lands on the section without long smooth-scroll from top on first load |

## Operational notes and limits

- **No package manager matrix in repo docs** — only `npm install` / `npm run dev` / `npm run build` are documented.
- **No host recipe** — no Netlify, Vercel, GitHub Pages, or nginx config is part of the supplied site surface; treat “deploy anywhere” as copy `dist/` to a static file root.
- **Subpath hosting not configured** — config has no `base` path; root deployment matches current absolute asset and `site` usage.
- **Do not couple skill deploy to site deploy** — scanner remains `node skill/scripts/scan.mjs …` and never edits files; it is not produced by `npm run build`.

## Related pages

<CardGroup>
  <Card title="Run the field guide site" href="/run-field-guide-site">
    Install, dev server, static build output, and how catalogue entries and demos render on the index.
  </Card>
  <Card title="Installation" href="/installation">
    Site dependencies for local development and skill install options.
  </Card>
  <Card title="Design tokens" href="/design-tokens">
    Paper/ink palette, single accent, and self-imposed style rules shipped with the site.
  </Card>
  <Card title="Contributing" href="/contributing">
    Where to change site components, catalogue data, or skill references while keeping taxonomy aligned.
  </Card>
</CardGroup>
