What does Site Forge do?
<execution_context> Phase 0 resolves the mode:
- auto (fast): Do as much as possible yourself. After the one plan/approval gate (Phase 3), run to completion without asking. Use only media you can make yourself for free (jina; MCP/Higgsfield if present). If a step blocks, needs interaction, or fails — skip it, keep going, list it under "Skipped / upgrade later" at the end. Bias to shipping.
- full (best quality): Interactive. Ask whenever a choice meaningfully changes the result, and use the best free media even when it needs the user (Google/Gemini for images, Veo 3.1 Fast in Flow for video — hand them exact prompts, they generate, drop the files). A blocked step → ask them to step in.
Both modes:
- 🟢 Auto: explore the environment, design, write code, extract frames, run ffmpeg, local-preview, and deploy after approval.
- 🟡 TWO mandatory gates in both modes: (1) the Phase 3 plan before building, and (2) the deploy itself — ask immediately before every deploy, every time. Approval for one deploy is never approval for the next. Default is local preview.
- 🔴 Never: invent fake credentials/keys; publish claims the user flagged as unverified without a disclaimer; enter the user's secrets into forms. </execution_context>
-
Pick the PROFILE before anything else. Read
references/design-profiles.mdand state it in one line: "Profile: creative-portfolio. Bending display-size ceiling, serif ban, scrim floor, conversion furniture. Craft floor unchanged." The default islocal-service;creative-portfoliocovers photographers, designers and artists;personal-agencyis Adam's own. The profile decides which of Adam's aesthetic rules are in force — the craft floor never bends, so 16px body, 4.5:1 contrast, 44px taps, reduced-motion, schema, the sixteen social tags and the security headers apply no matter what the brief or a reference site does. Getting this wrong produces a trades site wearing a portfolio's photographs. -
Read
references/page-composition.mdfirst (it is the difference between a page that feels designed and one that feels empty), then invokefrontend-designbefore any markup (installed → use it; else readreferences/frontend-design.md— the full skill, bundled verbatim, so you get its complete guidance even offline). -
Invoke
design-taste-frontend. State its one-line design read ("Reading this as: for , with a language…") and set the three dials. Use taste-skill's own defaults and presets. The one carve-out: its perpetual-motion unlock at MOTION_INTENSITY > 5 stays off — no pulse, shimmer, float, typewriter, or infinite loops. Skip its React/Tailwind stack section on static builds. -
Impeccable is already running: its hook fires on every write. Its commands are the Phase 7 gate.
Then use references/aesthetics.md as the theme/type/layout-derivation helper.
This is the anti-slop gate and the biggest quality lever. Commit to
a bold, brief-specific direction:
- One clear aesthetic, executed precisely; a distinctive font pairing (never Inter/Roboto/Arial); a cohesive palette as CSS variables.
- The structure — which sections, what hierarchy, the one memorable moment — derived from the brief. Do not reuse the last site's shape.
- Which capabilities fit, and which to leave out (see the Reference map). A simple brief may use none of the heavy effects; a flagship may use several. Write a 3–5 line design brief to carry into the plan.
Impeccable's hook fires on every write. Resolve its findings as they appear, not in a pile at the end — each one either gets fixed or explicitly classified as a false positive with a stated reason. Never inline-suppress a rule to skip fixing it; suppression needs Adam's confirmation. After ~6 edits it goes quiet to avoid noise, which is why the Phase 7 audit is a separate hard gate.
Single-page vs multi-page. A one-pager ships as a single index.html. A brief
with distinct audiences or real depth (a business site with patient / physician /
pricing / about sections, a marketing site with a Science page) earns a multi-page
set instead — separate *.html pages sharing one chrome. With no build step the
shared blocks are hand-copied, so drift is a real bug: keep the <head> (incl.
the no-FOUC theme snippet), nav, footer, and <script> tags byte-identical across
every page, and verify by hashing them before deploy — a page that quietly diverges
(different fonts, a missing toggle, a dead link) is the classic failure. Give each
page its own self-referential canonical/og:url + <title>/description, emit a
sitemap.xml + robots.txt, and noindex any private/app mockup pages. If the page
count or shared-block size makes hand-copying fragile, a tiny include step (Node
concat, or Eleventy/Astro) is a fair trade — but only when the brief earns it;
default to no-build.
Then three mechanical gates, all of which have caught real shipped defects:
python3 <skill>/scripts/audit-seo.py # SEO, local SEO, security. exit 1 on HIGH
python3 <skill>/scripts/check-crops.py # object-fit:cover discarding the subject
python3 <skill>/scripts/colour-system.py # one treatment per photograph, site-wide
And click every interactive element in a real browser, asserting a state
change. An FAQ, a filter bar and a map panel have all shipped with complete
markup, complete CSS and no handler at all: nothing looks broken in the source.
Use document.elementFromPoint at the control's own centre, not .click(),
which skips hit-testing and passes on a control that is completely buried.
If anything feels janky, TRACE it, do not sample it. performance_start_trace
then scroll then performance_analyze_insight("ForcedReflow") names the offending
function by file and line. Frame-rate sampling has plus or minus ten points of
variance and will send you after the wrong thing. See scroll-performance.md.
Design-stack gate — hard, before deploy, no exceptions:
/impeccable critique(UX review) then/impeccable audit(a11y, perf, responsive).- Every finding fixed, or classified a false positive with a stated reason. Never inline-suppress. Suppression needs Adam's confirmation.
- Run taste-skill's own pre-flight checklist (its Section 14).
- Grep the CSS for
infiniteanimations and tintedbox-shadow, and neutralize both. This catches the one taste-skill setting we deliberately override.
Default is LOCAL. Preview with python3 -m http.server 8080 in the build dir and
iterate there. Do not deploy unless the user asks in that moment — a live URL is
only warranted for a paying client or a scheduled demo, and every deploy costs Netlify
credits (38 deploys to one site exhausted a monthly allowance and forced a paid
upgrade). Batch every outstanding fix into ONE deploy per review round.
Mobile QA is deferred to the first real deploy — it cannot be done locally and the automation browser cannot emulate a true mobile viewport. Plan for a dedicated mobile pass at demo time rather than pretending it was verified earlier.
NEVER deploy the project root. .netlifyignore is NOT honoured by netlify deploy --dir,
and deploying a root once published a client's HOME ADDRESS and a tracker PASSWORD across the
fleet. Build an explicit publish directory and verify the live surface, every time:
python3 scripts/make-dist.py . # publishes only web files, withholds .py/.md/package.json
netlify deploy --prod --dir dist
scripts/verify-published.sh <host> [owner-street-name] # must print "clean"; non-zero exit = leak
When the user does approve, deploy with scripts/deploy-netlify.sh
(references/deploy.md) — Netlify is the only thing installed at the end;
enable Forms (ignore_html_forms) + the notification hook if there's a form.
Then set up Cloudflare Web Analytics by default (the user usually wants it):
ask for a beacon token for the deployed hostname, inject the snippet before
</body> with NO SRI (Cloudflare rotates it — the documented exception), and
redeploy. In auto, surface it as a "needs the user" item with the exact
hostname. Details in references/deploy.md.
Report the live URL, what was used, and (in auto) the Skipped / upgrade-later
list.
Reference map (read on demand — do NOT preload all of these)
| Need | File |
|---|---|
| Design profiles: the craft-floor / aesthetic-default split, and which genre bends what. Read at Phase 2 before designing. | references/design-profiles.md |
| Profile: photographers, designers, artists, studios | references/profile-creative-portfolio.md |
| Profile: Adam's own brand and agency site (stub) | references/profile-personal-agency.md |
| Adam's operation context: live demo fleet + URLs, required head steps (favicon files, OG card, site-name signals), media policy, truth discipline | ~/.claude/skills/site-prospector/references/adam-operation-context.md |
| GSAP+Lenis wiring, reduced-motion, CDN/SRI | references/stack-and-wiring.md |
| Why a page feels full or empty: no text-only bands, layering, masks, dividers | references/page-composition.md |
| Scroll scrub (frames), before/after, progress bar + back-to-top ring, reveals, perf rules | references/scroll-effects.md |
| Why a scroll effect janks: TRACE don't sample, layout thrashing, lazy-loading forces decode, when promotion hurts, dropping GSAP | references/scroll-performance.md |
| Scroll-drawn SVG line: page-height path, stacking, per-band gradient, tangent-continuous loops, monotonic anchor | references/svg-line-work.md |
| SEO + local SEO + security audit (run scripts/audit-seo.py) | references/seo-security-audit.md |
| Canvas pseudo-3D (no bundler, default) + Three.js (capability-gated) | references/interactive-3d.md |
| Carousel, video player, counters, Netlify Forms | references/components.md |
| The design stack: frontend-design + taste-skill + Impeccable, dials, commands, conflict table | references/design-stack.md |
| frontend-design — full skill, verbatim (offline fallback) | references/frontend-design.md |
| Theme system, fonts, deriving a unique look | references/aesthetics.md |
| Swipe file: real sites worth stealing from, what to copy vs leave (read at Phase 2 when the brief is a local trade) | references/reference-sites.md |
| AI image/video gen (auto vs full), free-vs-paid | references/ai-media.md |
| Image handling, height:auto fix, ffmpeg crop/scale | references/images.md |
| Remotion VO→captions→mix→render→stitch, macOS fix | references/remotion-video.md |
| Bug checklist before shipping | references/quality-checklist.md |
| Netlify deploy, Forms API, rename | references/deploy.md |
| Social card verifier (run after EVERY deploy) | scripts/verify-og.py <host> |
This is a toolkit, not a sequence. Use what the brief earns; ignore the rest.
<error_handling>
- Missing skill/tool →
autofalls back to the baked-in reference and notes it;fulloffers to install or asks. - Install fails / needs interaction →
autoskips + surfaces;fullasks. - macOS < 15 Remotion render abort → sequence-render + ffmpeg-stitch path
(
references/remotion-video.md), never the direct mp4 mux. - AI media unavailable / out of credits →
autoships image-only + flags upgrade;fullroutes to Gemini/Flow. - Netlify form not detected → set
ignore_html_forms:falsevia API + redeploy (references/deploy.md). </error_handling>
<success_criteria>
- Design is unique to the brief — not a reuse of a prior site's look.
- frontend-design applied (invoked, or its principles via aesthetics.md).
- taste-skill applied: design read declared, dials set, its pre-flight run.
-
/impeccable critique+/impeccable auditrun; every finding fixed or classified. - No
infiniteanimations, no tintedbox-shadow(grep-verified). - Icons from Phosphor (or HugeIcons/Radix/Tabler), one family, one strokeWidth.
- Self-contained site (one index.html, or a multi-page set sharing byte-identical chrome); console-clean; mobile passes.
- Only brief-earned capabilities included (no gratuitous effects).
- Plan approved before build (both modes).
- Deployed from an explicit
dist/, NOT the project root. -
verify-published.shrun against the live host and printed "clean". - Deployed; live URL reported;
autolists any skips/upgrades. </success_criteria>
CMS / "can I edit it myself?" — read references/cms-options.md before answering. Short version: default is NO CMS; content changes are included in the monthly, and that is a feature, not a gap (a trade changes their site ~twice a year and will forget the login). If one is genuinely warranted, the only category that fits hand-written static HTML is a git-based CMS (Sveltia or Decap), never WordPress — we sell against WordPress explicitly. A CMS is a paid tier feature, never a default.
Twilio / missed-call text-back / A2P 10DLC — read references/twilio-a2p-10dlc.md before quoting or building it. Three things that decide everything: (1) the reseller rule — brand registrations carry the CLIENT's email and address, not ours; using ours caps the business at 10 clients, silently; (2) campaign vetting takes WEEKS, not days — start the day they sign; (3) a live website + a business email on a real domain are REQUIRED FIELDS, and our gmail-using prospects have neither, which makes the website a prerequisite for texting rather than a nice-to-have. That is the strongest sales argument in the ladder.