mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-11 21:57:14 +03:00
craft + brand: framework foundation, build-pipeline respect, image verification
Three closely-linked additions surfaced by an eval-harness session
investigating why the agent always shipped flat single-file HTML and
zero imagery on greenfield brand briefs.
1. craft.md gains a new Step 0 "Project Foundation" before Shape.
Detects existing framework / component library / icon set and
uses what's there. Greenfield: ask the user via AskUserQuestion
with sensible defaults framed by the brief (Astro for content/
brand sites, SvelteKit/Next/Nuxt for app surfaces, single
index.html only for one-shot demos). Skipping the framework
decision and writing flat HTML "to satisfy the spec" produces
work that reads as a 2018 prototype regardless of visual
quality.
2. craft.md Step 5 production bar gains two bullets:
- Respect the build pipeline. Edit source files and run the
project's `npm run build`; do not write to build/ / dist/ /
.next/ directly with cat/heredoc/Bash redirects. Bypassing
the pipeline skips asset hashing, image optimization, code
splitting, and CSS extraction.
- Verify external image URLs before referencing them. Use an
image-search MCP, web-fetch tool, or browser if available;
guessed photo IDs ship as broken-image placeholders.
3. brand.md "Imagery" section:
- Generalizes the Unsplash URL guidance to "verify URLs
before referencing them" with a hierarchy: image-search MCP
> web-fetch > confidence-restricted manual selection >
fewer photos.
- Tightens the tech/dev-tool exception. Old line "zero imagery
can be correct" gave models a permission slip. New framing
keeps the underlying truth (typography + code + diagrams
primarily carry voice) but raises the floor: imagery still
earns its place when it serves the brief, and skipping it
requires naming the typographic/diagrammatic move that's
carrying the visual weight instead. "Zero imagery is the
failure mode of laziness, not restraint."
Eval-harness corpus that prompted this: 19/19 brand landing tasks
shipped 0 images each, including ones where Opus had taste enough
to break the dev-tool color default lane. The skill needs to teach
both halves of the decision; the harness shouldn't have to nudge.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
8f98f36e3d
commit
e3ad2eff25
@@ -81,12 +81,12 @@ Brand surfaces lean on imagery. A restaurant, hotel, magazine, or product landin
|
||||
|
||||
**When the brief implies imagery (restaurants, hotels, magazines, photography, hobbyist communities, food, travel, fashion, product), you must ship imagery.** Zero images is a bug, not a design choice. "Restraint" is not an excuse. If the approved comp or brief is image-led, ship real project assets, generated raster assets, or a credible canvas/SVG/WebGL scene. Do not replace photographic, architectural, product, or place imagery with generic CSS panels, decorative diagrams, cards, bullets, or copy.
|
||||
|
||||
- **For greenfield work without local assets, use stock imagery.** Unsplash is the default. The URL shape is `https://images.unsplash.com/photo-{id}?auto=format&fit=crop&w=1600&q=80`. Pick real Unsplash photo IDs you're confident exist (`photo-1559339352-11d035aa65de`, `photo-1590490360182-c33d57733427`, etc.); if unsure, pick fewer photos but don't substitute colored `<div>` placeholders.
|
||||
- **For greenfield work without local assets, use stock imagery.** Unsplash is the default. The URL shape is `https://images.unsplash.com/photo-{id}?auto=format&fit=crop&w=1600&q=80`. **Verify the URLs before referencing them.** If you have an image-search MCP, web-fetch tool, or browser access, use it to find real photo IDs and confirm they resolve. Guessed IDs (even ones that look real) often 404 and ship as broken-image placeholders. Without a verification path, pick fewer photos you're confident exist over more that you guessed; never substitute colored `<div>` placeholders.
|
||||
- **Search for the brand's physical object**, not the generic category: "handmade pasta on a scratched wooden table" beats "Italian food"; "cypress trees above a limestone hotel facade at dusk" beats "luxury hotel".
|
||||
- **One decisive photo beats five mediocre ones.** Hero imagery should commit to a mood; padding with more stock doesn't rescue an indecisive one.
|
||||
- **Alt text is part of the voice.** "Coastal fettuccine, hand-cut, served on the terrace" beats "pasta dish".
|
||||
|
||||
Tech / dev-tool brands are the exception where zero imagery can be correct; a developer landing page often carries its voice through typography, code samples, diagrams. Know which kind of brand you're working on.
|
||||
"Imagery" here is broader than stock photography: product screenshots, custom data visualizations, generated SVG, and canvas/WebGL scenes are all imagery. Text-only pages where typography alone carries the entire visual weight are the failure mode.
|
||||
|
||||
## Motion
|
||||
|
||||
|
||||
@@ -6,6 +6,29 @@ Before writing code, you need: PRODUCT.md loaded, register identified and the ma
|
||||
|
||||
Treat any approved visual direction (generated mock or stated reference) as a concrete contract for composition, hierarchy, density, atmosphere, signature motifs, and distinctive visual moves. Don't let mocks replace structure, copy, accessibility, or state design. But if the live result lacks the approved direction's major ingredients, the implementation is wrong.
|
||||
|
||||
## Step 0: Project Foundation
|
||||
|
||||
Before shape, before code: figure out what kind of project you're working in.
|
||||
|
||||
Look at the working directory. Run `ls`. Check for:
|
||||
|
||||
- An existing framework: `astro.config.mjs/ts`, `next.config.js/ts`, `nuxt.config.ts`, `svelte.config.js`, `vite.config.js/ts`, `package.json` with framework deps, `Cargo.toml` + Leptos/Yew, `Gemfile` + Rails. **If found, use it.** Do not start a parallel build, do not introduce a second framework, do not write to `dist/` or `build/` directly. Whatever pipeline the project has, respect it.
|
||||
- An existing component library or design system: `src/components/`, `app/components/`, a `tokens.css` / `theme.ts`, an `astro.config` `integrations`. Read what's there before adding to it.
|
||||
- An existing icon set: `lucide-react`, `@phosphor-icons/react`, `@iconify/*`, hand-rolled SVG sprites in `assets/icons/`. **Use what's already in the project**; don't introduce a second set.
|
||||
|
||||
If the directory is empty (greenfield), don't pick a framework silently. Ask the user via the AskUserQuestion tool, with sensible defaults framed by the brief:
|
||||
|
||||
```text
|
||||
What should this be built on?
|
||||
- Astro (default for content-led brand sites, landing pages, marketing surfaces)
|
||||
- SvelteKit / Next.js / Nuxt (when the brief implies an app surface or significant interactivity)
|
||||
- Single index.html (one-shot demo, prototype, or a deliberately framework-free experiment)
|
||||
```
|
||||
|
||||
Default: Astro for brand briefs, the project's existing framework for product briefs. Ask once; don't re-ask mid-task.
|
||||
|
||||
**Why this matters.** A 1200-line single index.html with inline `<style>` is not how a 2026 designer-engineer ships a brand site. Picking a real framework gives you the asset pipeline (image optimization, font subscription, MDX), real component decomposition, and the ecosystem (icon libraries, design tokens). Skipping the framework decision and writing flat HTML "to satisfy the spec" produces work that reads as a 2018 prototype regardless of how good the visuals are.
|
||||
|
||||
## Step 1: Shape the Design
|
||||
|
||||
Run {{command_prefix}}impeccable shape, passing along whatever feature description the user provided. Shape is **required** for craft; it is what produces a confirmed direction.
|
||||
@@ -116,6 +139,8 @@ Implement the feature following the design brief. Build in passes so structure,
|
||||
- Design realistic state coverage: default, hover where supported, focus-visible, active, disabled, loading, error, success, empty, overflow, long text, short text, and first-run states where relevant.
|
||||
- Make interaction quality feel finished: keyboard paths, touch targets, feedback timing, scroll behavior, transitions between states, and no hover-only functionality.
|
||||
- Use icons from the project's established icon set when available. If no set exists, choose a coherent library or use accessible text controls; do not mix unrelated icon styles.
|
||||
- Respect the build pipeline. If the project uses Astro / SvelteKit / Next / Vite / etc., edit the source files and run the project's build (`npm run build` or equivalent); do not write to `build/` / `dist/` / `.next/` directly with `cat`, heredoc, or Bash redirects. Bypassing the pipeline skips asset hashing, image optimization, code splitting, and CSS extraction; it also produces output the project's own dev server won't serve.
|
||||
- Verify external image URLs before referencing them. If you have an image-search tool or web-fetch capability, use it to confirm the URL exists and matches the brand's physical object. Guessed photo IDs (Unsplash, CDN paths) often 404 and ship the page as broken-image placeholders. Without a verification tool, prefer fewer images you're confident about over more you guessed.
|
||||
- Optimize imagery and media: correct dimensions, useful alt text, lazy loading below the fold, modern formats when practical, responsive `srcset` / `picture` for raster assets, and no project-referenced asset left outside the workspace.
|
||||
- Make motion feel premium: use atmospheric blur, filter, mask, shadow, or reveal effects when they improve the experience; avoid casual layout-property animation, bound expensive effects, verify smoothness in-browser, respect reduced motion, and avoid choreography that blocks task completion.
|
||||
- Preserve maintainability: reusable local patterns, clear component boundaries, project conventions, no rasterized UI text, and no hard-coded one-off hacks when a better local pattern exists.
|
||||
|
||||
Reference in New Issue
Block a user