# FABLE 25 — BUILD BRIEF

You are building **one** website in a 25-site showcase. Every site is a real, plausible
website for a real Florida/Texas small business that currently has **no website at all**.

The showcase exists to demonstrate what a frontier model can do in web design, taste and
artistic craft. Thousands of people will look at this. Your site will sit next to 24 others,
each with a completely different art direction. **Yours must be unmistakably its own thing.**

Two things must both be true:

1. A real customer of this business could land on it and immediately book the service.
2. A designer could land on it and think *"how did they do that in a browser?"*

If you only achieve #1, you failed. If you only achieve #2, you also failed.

---

## 1. HARD TECHNICAL CONTRACT

**Non-negotiable. A violation makes the site undeployable.**

### Output files (exactly two)

```
<site-dir>/index.html       ← the entire site, self-contained
<site-dir>/technique.json   ← machine-readable record of what you built
```

Do not create any other files. No CSS files, no JS files, no images on disk,
no README. Everything inline in `index.html`.

### Dependencies

Allowed, from these **pinned** CDN URLs only:

```html
<!-- three.js — ES module + importmap -->
<script type="importmap">
{"imports":{
  "three":"https://cdn.jsdelivr.net/npm/three@0.169.0/build/three.module.js",
  "three/addons/":"https://cdn.jsdelivr.net/npm/three@0.169.0/examples/jsm/"
}}
</script>
<script type="module"> import * as THREE from 'three'; </script>

<!-- GSAP + ScrollTrigger (classic script tags, not modules) -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollTrigger.min.js"></script>

<!-- Google Fonts -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=...&display=swap">
```

Nothing else. No React, no Tailwind CDN, no bundlers, no npm, no build step.
No external images, no `<img src="https://...">`. Every visual is **code you write**:
WebGL/GLSL, Canvas 2D, SVG, or CSS. That constraint is the point of the exercise.

You do not have to use three.js. Canvas 2D and SVG, used with real craft, beat a
mediocre WebGL scene every time. Pick the right tool for your assigned direction.

### Must not break

- **No JS = still a website.** All copy lives in the HTML source, never injected by JS.
  Turn JS off and you must still get a readable, usable, phone-number-visible page.
- **No WebGL = still beautiful.** Wrap WebGL init in try/catch and feature-detect.
  On failure, a designed CSS fallback (gradient/SVG/canvas) takes over. Never a blank box.
- **`prefers-reduced-motion: reduce`** — kill autoplay loops, parallax, and scroll-scrub.
  Keep opacity fades. The site must still look composed and intentional, not stripped.
- **Mobile is not an afterthought.** 390×844 must be genuinely great, not a squeezed
  desktop. Clamp `devicePixelRatio` to ≤1.75 on mobile, drop particle counts, and disable
  the heaviest effect below 720px if it can't hold 50fps.
- **Performance budget:** first paint under 1.5s on a throttled connection. Total inline
  HTML ≤ 150KB. Never block the main thread over 100ms in a scroll handler.
  RAF loops must pause when `document.hidden` and when the canvas is off-screen
  (IntersectionObserver).
- **No horizontal scroll at any width from 320px to 2560px.** Test it.
- **No console errors.** None.

### Accessibility floor

- Semantic landmarks: `<header> <main> <section> <footer>`, one `<h1>`, correct heading order.
- All body copy ≥ 4.5:1 contrast. Large display type ≥ 3:1. Check it, don't guess.
- Visible `:focus-visible` ring on every interactive element.
- Canvas/WebGL decoration gets `aria-hidden="true"`.
- Every control reachable and operable by keyboard.
- Real `<a href="tel:+1...">` and `<a href="mailto:...">`, not `onclick`.

### SEO / metadata (this is a real local business)

- `<title>` — Business — Service in City, ST
- meta description, canonical, `og:title`/`og:description`/`og:type`
- `theme-color` matching the site's dark or light chrome
- Valid JSON-LD `LocalBusiness` (or the right subtype) with `name`, `telephone`,
  `email`, `address` (locality + region, no invented street number), `areaServed`,
  `openingHoursSpecification`, `description`.

---

## 2. WHAT THE SITE MUST CONTAIN

This is a working business website, not a design demo with lorem ipsum.

**Required, in an order that makes sense for your direction:**

- Hero — business name, what they do, city, and a call-to-action within one screen
- The phone number, as a tappable link, reachable in under one second on mobile
  (sticky call dock on mobile is strongly encouraged — 48px+ tap target)
- Services — 4–8 specific, real offerings for this trade. Research what this trade
  actually does. "Quality service" is not a service. "Transmission fluid flush" is.
- Service area — named neighbouring towns/neighbourhoods around the real city
- Proof — years in business, response time, jobs completed, licensing, warranty.
  Invent plausible, modest numbers. Nothing absurd.
- 2–4 testimonials with first name + last initial + neighbourhood
- FAQ — 4–6 real questions this trade actually gets asked
- Contact — phone, email, hours, and a working form (client-side validated,
  no backend — on submit show a designed success state and a "or call now" fallback)
- Footer — business name, phone, email, city/state, service list, small print

**Copy voice.** Write like the owner would talk if the owner were good at writing.
Short declaratives. Specifics over adjectives. No "we pride ourselves on", no
"your trusted partner", no "in today's fast-paced world". Never use an em dash.
Trade-accurate vocabulary — a diesel tech says "aftertreatment" and "regen",
a detailer says "paint correction" and "ceramic coating". Get it right.

**Numbers must be internally consistent.** If the hero says 18 years, the about
section cannot say 12.

---

## 3. ANTI-SLOP — READ THIS TWICE

The single biggest risk is producing something that looks like every other AI-generated
site. These are the tells. **Every one is banned.**

| Banned | Do instead |
|---|---|
| Purple→blue `linear-gradient(135deg,#667eea,#764ba2)` | Build a palette from your assigned direction. Odd, specific, committed. |
| Generic glassmorphism cards: `blur(10px)` + `rgba(255,255,255,.1)` + 16px radius | If you use blur, make it structural and justified by the direction. |
| Three identical feature cards in a row with a centred icon | Asymmetry. Different sizes. Let one item dominate. |
| Emoji as icons | Custom inline SVG you draw, or type, or nothing. |
| Inter / Poppins / Montserrat / Roboto as the display face | Pick a face with a point of view. Use the variable axes. |
| Everything centred | Establish a real grid. Break it deliberately, once. |
| Uniform 16px radius on everything | Radius is a design decision. Often the answer is 0. |
| `box-shadow: 0 4px 6px rgba(0,0,0,.1)` | Shadows should come from the light source you invented. |
| Fade-up-on-scroll on every single element, same duration | Choreograph. Stagger. Vary. Most things should not animate at all. |
| A "Trusted by" logo wall of fake companies | Real proof for a local trade: licence number, years, response time. |
| Section → section → section, all `padding: 80px 0` | Vary rhythm. Let one section be full-bleed and one be tight. |
| Hero headline in a 60px centred sans with a subheading and two buttons | Make the hero the most interesting thing on the page. |

**Positive craft markers — aim for these:**

- A real light source, consistently applied across every element on the page
- Optical alignment, not just mathematical (large type usually needs negative left offset)
- Type scale from a ratio, with `clamp()` and sane min/max — never a raw `vw` font-size
- Tracking tightens as size increases; line-height tightens as size increases
- Motion with intent: things enter from where they logically come from
- One genuinely surprising moment. One. Not six.
- Restraint everywhere else so that one moment lands

---

## 4. THE THREE ITERATION PASSES — MANDATORY

After the site works, you run three passes. Each pass is a real critique with real edits.
You must record what you changed in each pass in `technique.json`. **A pass with no
changes is a failed pass** — look harder.

### Pass 1 — Correctness and craft
Read your own HTML top to bottom.
- Any horizontal overflow at 320 / 390 / 768 / 1024 / 1440 / 2560?
- Contrast failures? Check the actual hex pairs.
- Does it work with JS disabled? With WebGL disabled? With reduced motion?
- Any console error, any 404, any unused CSS, any duplicated block?
- Do the numbers contradict each other anywhere?
- Is every tap target ≥ 44px on mobile?
- Does the mobile layout look designed, or just narrow?

### Pass 2 — Push the design further
This is where the site stops being good and starts being memorable.
- Where is the design still generic? Name it, then replace it.
- What is the single most boring section? Redesign it entirely.
- Add one layer of visual depth that isn't there yet: grain, a light rake, a considered
  border treatment, a texture, a secondary motion system, a detail at the pixel level.
- Improve the typography: a better pairing, a sharper scale, better tracking, a display
  moment you didn't have.
- Is the hero the best thing on the page? If a later section is better, the hero is wrong.
- Make the transitions between sections deliberate instead of accidental.

### Pass 3 — Cohesion, performance, polish
- Does every element look like it came from the same world? Kill anything that doesn't.
- Reduce: what can be deleted without loss? Delete it.
- Profile the animation loop. Drop particle counts, cache uniforms, avoid layout thrash.
- Loading: does it look intentional in the first 200ms, before fonts and WebGL arrive?
  Design that state.
- Final read of every word of copy. Any AI tell, any em dash, any filler, any hedge — cut.
- Hover, focus, and active states on every interactive element, all deliberate.

---

## 5. `technique.json` FORMAT

```json
{
  "slug": "exotic-equipment-towing",
  "name": "Exotic Equipment Towing",
  "direction": "INDUSTRIAL TITAN",
  "tagline": "One line on the visual concept.",
  "stack": ["three.js r169", "GLSL", "GSAP ScrollTrigger", "Canvas 2D"],
  "fonts": ["Archivo Expanded", "IBM Plex Mono"],
  "palette": ["#0B0C0E", "#C4622D", "#E8E2D6"],
  "techniques": [
    { "title": "Volumetric fog via raymarched depth", "detail": "1-2 sentences, concrete and technical." }
  ],
  "passes": [
    { "pass": 1, "changes": ["Specific change.", "Specific change."] },
    { "pass": 2, "changes": ["..."] },
    { "pass": 3, "changes": ["..."] }
  ],
  "fallbacks": "What happens with no JS / no WebGL / reduced motion.",
  "perf": "Frame budget notes, DPR clamping, particle counts."
}
```

Between 3 and 6 `techniques`. Each `detail` must be specific enough that a competent
developer could reproduce the effect. No marketing language anywhere in this file.

---

## 6. SHARED FOOTER MARK

Every site ends with this exact block as the last child of `<footer>`, styled to sit
quietly inside your design (inherit your palette, small, low-contrast but ≥ 4.5:1):

```html
<p class="fable-mark">
  Designed and built by <strong>Claude</strong> for
  <a href="/">MacArthur Media</a> ·
  <a href="/guide">How this was made</a>
</p>
```

Do not add a "TEMP TEST BUILD" banner. These are finished pieces.

---

## 7. WORKING METHOD

1. Read your assignment (direction + brief + lead data).
2. Decide the light source, the palette, the type system, and the one surprising moment
   **before** you write markup.
3. Build the whole site.
4. Verify: open it, check every breakpoint, check the fallbacks.
5. Pass 1. Pass 2. Pass 3. Record each honestly.
6. Write `technique.json`.

Verify with the local Python server and a real browser check where available.
Never claim a pass you did not run. Never report done on a site with a console error.

Now go make something people screenshot.
