# /website

> Build, pACME Agencyw, and deploy a custom static MULTI-PAGE marketing WEBSITE to SiteGround hosting (company sites, brand/agency sites, Faris's own properties).


# /website — custom websites on SiteGround

Build genuinely good-looking custom websites with Claude Code and ship them to
Faris's **SiteGround** hosting (not Vercel/Netlify). Each site is a self-contained
static project under `websites/<slug>/` with its own deploy target. The reusable
tooling lives in `shared/website/`; the design intelligence lives in two skills:
**`frontend-design`** (Anthropic — bans AI-slop aesthetics) and **`ui-ux-pro-max`**
(67 styles / 161 palettes / 57 font pairings, queried via a Node search engine).

This skill is the long-term capability: use it for ACME Agency client sites and
for any of Faris's own properties. Five techniques are baked in — design skills,
the screenshot loop, reference cloning, 21st.dev components, and SiteGround deploy.

---

## Modes

### `new <slug>` — scaffold a project
```bash
node shared/website/new_site.mjs --slug <slug> --name "<Site Name>" --domain <domain> [--git]
```
Creates `websites/<slug>/` with `CLAUDE.md` (per-site rules), `site.json` (deploy
targets derived from the domain), `src/` (the publish dir), and `brand-assets/`.
Then tell the user to drop the logo + brand guidelines into `brand-assets/`.

### `build <slug>` — design & build the page
This is the core loop. Working inside `websites/<slug>/`:

1. **Read the brief + brand.** Read `websites/<slug>/CLAUDE.md`, anything in
   `brand-assets/`, and the user's brief. If HR/BS, apply the Croatian/Bosnian copy
   rules (no em-dashes, no literal English, read-aloud test).
2. **Get a design system.** Query ui-ux-pro-max from the repo root:
   ```bash
   node .claude/skills/ui-ux-pro-max/scripts/search.mjs "<product> <industry> <tone>" --design-system -p "<Site Name>"
   ```
   Deep-dive dimensions as needed: `--domain style|color|typography|landing|ux`.
3. **Invoke the `frontend-design` skill** and write real code into `src/`
   (`index.html`, `styles.css`, `script.js`, `assets/`). Commit to ONE bold aesthetic.
   Distinctive heading font (never Inter/Roboto/Arial), dominant color + sharp accent,
   one signature moment (hero animation / scroll reveal).
4. **Screenshot self-ACME Agencyw loop** — see what you built, don't guess:
   ```bash
   node shared/website/screenshot_loop.mjs --site <slug> --clean
   ```
   Read the PNGs in `websites/<slug>/temp-screenshots/` with vision, compare to the
   brief/reference, fix, and re-run. At least two passes before showing the user.
   (Skip the loop for animated backgrounds — a static frame loops forever.)
5. **Show the user** a local pACME Agencyw URL and the screenshots. Iterate on their notes.

### `pACME Agencyw <slug>` — local server
```bash
node shared/website/dev_server.mjs --site <slug> --port 4321
```
Open the printed `http://<server-ip>:4321`. Live changes after edits need a refresh.

### `clone <slug> <reference>` — match a reference site
The user supplies a reference site they like (a full-page screenshot, optionally
copied CSS). Read the screenshot with vision, rebuild the structure + feel in `src/`
(not pixel-theft), run the screenshot loop comparing your build to the reference,
then layer the client's brand (colors/logo/copy) over the cloned skeleton.

### `deploy <slug>` — ship to SiteGround
**Only when the user explicitly says deploy / push live / objavi.**
```bash
node shared/website/siteground_deploy.mjs --site <slug>            # production
node shared/website/siteground_deploy.mjs --site <slug> --staging  # staging subdomain
node shared/website/siteground_deploy.mjs --site <slug> --dry-run  # list files, no upload
```
Additive by default; `--prune` mirror-deletes remote orphans (it prints each deletion).

**Source backup is automatic.** `websites/` is its own private repo (`your-org/agency-websites`, mirrored on your server at `/home/you/agency-websites`). Every successful deploy auto-commits + pushes the repo via `shared/website/websites_backup.mjs` (best-effort — a failed push never fails the deploy). If you make site edits without deploying, commit + push inside `websites/` manually before ending the session. `temp-screenshots/` and `node_modules/` are gitignored there (regenerable).

**Cache-busting is automatic.** SiteGround's NGINX serves static files with a long Expires header and ignores `.htaccess`, so a browser/CDN holds onto `styles.css`/`script.js` for months. The deploy now hashes the actual content of `styles.css` and `script.js` and stamps that hash into every HTML page's `?v=` query at upload time (e.g. `styles.css?v=b0c59efa`). The URL changes only when the file content changes, so updated CSS/JS always loads and stale styling can never be served. **Do not hand-bump `?v=` numbers** — the value in source HTML is irrelevant; the deploy overwrites it with the content hash. (For the page's own HTML, which has no `?v=`, still tell the user to hard-refresh or append `?<n>` when ACME Agencywing `/new/` staging.)

**SiteGround Dynamic Cache (the HTML proxy cache) is separate and NOT auto-purged by external SFTP.** After a deploy to a domain ROOT, the bare `/` (and any previously-cached URL) keeps serving the OLD page even though the file is updated — symptom: `curl https://DOMAIN/` shows the old `<title>` but `curl https://DOMAIN/index.html` and `curl 'https://DOMAIN/?bust=1'` show the new one. Flush it with SiteGround's own CLI over SSH: `site-tools-client -j domain list` (find the id), then `site-tools-client domain update id=<id> flush_cache=1` (bool wants `1`, not `true`; connect via the Node `ssh2` lib with the encrypted key + `<id>` — the `ssh.exe` CLI rejects the key). This is a remote config mutation, so the auto-mode classifier gates it — get user approval or have them flush in Site Tools → Speed → Caching → Dynamic Cache → Flush. Sites deployed to a `/new/` SUBFOLDER (e.g. your-domain.example) dodge this; root-domain sites (your-domain.example) need the flush after each deploy. Incident: 2026-06-06 your-domain.example English homepage.

---

## One-time SiteGround setup (per machine, already keyed)

Deploy uses SSH-key SFTP on SiteGround's port 18765. The connection lives in the
root `.env` (shared, never committed):
```
SITEGROUND_SSH_HOST=<your SiteGround SSH hostname>
SITEGROUND_SSH_USER=<your SiteGround SSH username>
SITEGROUND_SSH_PORT=18765
SITEGROUND_SSH_KEY=~/.ssh/siteground_deploy
```
The public key (`~/.ssh/siteground_deploy.pub`) must be added in SiteGround →
Site Tools → Devs → SSH Keys Manager. Validate with:
```bash
node shared/website/siteground_deploy.mjs --check
```
This prints the SFTP home + a directory listing if the key works. Each site's
`site.json` then only needs its own `deploy.remotePath` (docroot), e.g.
`www/example.com/public_html`.

## When to trigger

- "build me a website", "make a brand / company site for <client>"
- "napravi web stranicu za <klijent>", "objavi stranicu"
- "clone this website / make it look like <url>"
- "deploy / push the site live (to SiteGround)"
- A client or Faris property that needs a full multi-page marketing website

**NOT this skill → use `/landing`:** a client lead-gen landing page (single offer, lead
form, A/B testing, shows in the split-test console). "napravi landing za <klijent>",
"landing page for <client>", "lander/funnel" → that's `/landing` (Paradox Landing System
on Cloudflare Pages), which auto-deploys to a `*.pages.dev` URL and registers in the console.
`/website` is for full SiteGround sites only.

## Guardrails

- **Never deploy without an explicit instruction.** Build and pACME Agencyw locally; deploy
  is a separate, named step.
- **Never default to Inter/Roboto/Arial** or <id>. The
  frontend-design skill enforces this — actually invoke it.
- **Brand fidelity:** match the client's real logo + colors. If `brand-assets/` is
  empty, ask for them before designing.
- **Copy fidelity (HR/BS):** keep diacritics (š/ć/č/ž/đ), no em-dashes, no machine-
  translated phrasing. See `ACME Agency/CLAUDE.md`.
- One site = one folder under `websites/`. Don't scatter site files elsewhere.
