- Design Loop — Autonomous Site Builder
- Build complete multi-page websites through an autonomous loop. Each iteration reads a task, generates a page, integrates it, verifies it visually, then writes the next task to keep going.
- Overview
- The Design Loop uses a "baton" pattern — a file (
- .design/next-prompt.md
- ) acts as a relay baton between iterations. Each cycle:
- Reads the current task from the baton
- Generates the page (via Claude or Google Stitch)
- Integrates into the site structure (navigation, links)
- Verifies visually via browser automation (if available)
- Updates site documentation
- Writes the NEXT task to the baton — keeping the loop alive
- This is orchestration-agnostic. The loop can be driven by:
- Human-in-loop
-
- User reviews each page, then says "next" or "keep going"
- Fully autonomous
-
- Claude runs continuously until the site is complete
- CI/CD
- Triggered on .design/next-prompt.md changes Generation Backends Backend Setup Quality Speed Best for Claude (default) Zero dependencies Great — production-ready HTML/Tailwind Fast Most projects, full code control Google Stitch npm install @google/stitch-sdk + API key Higher fidelity AI designs ~10-20s/screen Design-heavy projects, visual polish Detecting Stitch At the start of each loop, check if Stitch is available: Check if @google/stitch-sdk is installed: ls node_modules/@google/stitch-sdk 2>/dev/null Check if STITCH_API_KEY is set in .dev.vars or environment Check if .design/metadata.json exists (contains Stitch project ID) If all three are present, use Stitch. Otherwise, fall back to Claude generation. Stitch SDK Reference Install: npm install @google/stitch-sdk . Set STITCH_API_KEY in environment or .dev.vars . import { stitch } from "@google/stitch-sdk" ; // Create a project const result = await stitch . callTool ( "create_project" , { title : "My Site" } ) ; // Reference an existing project const project = stitch . project ( "4044680601076201931" ) ; // Generate a screen const screen = await project . generate ( "A modern landing page with hero section" , "DESKTOP" ) ; // Get assets const htmlUrl = await screen . getHtml ( ) ; // Download URL for HTML const imageUrl = await screen . getImage ( ) ; // Download URL for screenshot // Edit an existing screen (prefer this for refinements) const edited = await screen . edit ( "Make the background dark and enlarge the CTA button" ) ; // Generate variants const variants = await screen . variants ( "Try different colour schemes" , { variantCount : 3 , creativeRange : "EXPLORE" , // "REFINE" | "EXPLORE" | "REIMAGINE" aspects : [ "COLOR_SCHEME" ] , // "LAYOUT" | "COLOR_SCHEME" | "IMAGES" | "TEXT_FONT" | "TEXT_CONTENT" } ) ; Device types: "MOBILE" | "DESKTOP" | "TABLET" | "AGNOSTIC" . Model selection: pass "GEMINI_3_PRO" | "GEMINI_3_FLASH" as third arg to generate() . Other operations: stitch.projects() lists projects, project.screens() lists screens, project.getScreen("id") fetches one. getHtml() and getImage() return download URLs. Append =w1280 to image URLs for full resolution. Auth: STITCH_API_KEY required (or STITCH_ACCESS_TOKEN + GOOGLE_CLOUD_PROJECT for OAuth). Errors throw StitchError with codes: AUTH_FAILED , NOT_FOUND , RATE_LIMITED . Stitch Project Persistence Save Stitch identifiers to .design/metadata.json so future iterations can reference them: { "projectId" : "4044680601076201931" , "screens" : { "index" : { "screenId" : "d7237c7d78f44befa4f60afb17c818c1" } , "about" : { "screenId" : "bf6a3fe5c75348e58cf21fc7a9ddeafb" } } } Stitch integration tips: Persist project ID in .design/metadata.json — don't create a new project each iteration Use screen.edit() for refinements rather than full regeneration Post-process Stitch HTML — replace headers/footers with your shared elements Include DESIGN.md context in prompts — Stitch generates better results with explicit design system instructions Getting Started First Run: Bootstrap the Project If .design/ doesn't exist yet, create the project scaffolding: Ask the user for: Site name and purpose Target audience Desired aesthetic (minimal, bold, warm, etc.) List of pages they want Brand colours (or extract from existing site with /design-system ) Create the project files : project/ ├── .design/ │ ├── SITE.md # Vision, sitemap, roadmap — the project's long-term memory │ ├── DESIGN.md # Visual design system — the source of truth for consistency │ └── next-prompt.md # The baton — current task with page frontmatter └── site/ └── public/ # Production pages live here Write SITE.md from the template in the "SITE.md Template" section below Write DESIGN.md — either manually from user input, or use the design-system skill to extract from an existing site Write the first baton ( .design/next-prompt.md ) for the homepage Subsequent Runs: Read the Baton If .design/next-prompt.md already exists, parse it and continue the loop. The Baton File .design/next-prompt.md has YAML frontmatter + a prompt body:
page : about layout : standard
- An about page for Acme Plumbing describing the company's 20-year history in Newcastle.
- **
- DESIGN SYSTEM:
- **
- [Copied from .design/DESIGN.md Section 6]
- **
- Page Structure:
- **
- 1.
- Header with navigation (consistent with index.html)
- 2.
- Hero with company photo and tagline
- 3.
- Story timeline showing company milestones
- 4.
- Team section with photo grid
- 5.
- CTA section: "Get a Free Quote"
- 6.
- Footer (consistent with index.html)
- Field
- Required
- Purpose
- page
- Yes
- Output filename (without .html)
- layout
- No
- standard
- ,
- wide
- ,
- sidebar
- — defaults to
- standard
- Execution Protocol
- Step 1: Read the Baton
- Read .design/next-prompt.md
- Extract: page name, layout, prompt body
- Step 2: Consult Context Files
- Before generating, read:
- File
- What to check
- .design/SITE.md
- Section 4 (Sitemap) — don't recreate existing pages
- .design/DESIGN.md
- Colour palette, typography, component styles
- Existing pages in
- site/public/
- Header/footer/nav patterns to match
- Critical
- Read the most recent page's HTML to extract the exact header, navigation, and footer markup. New pages must use identical shared elements. Step 3: Generate the Page Option A: Claude Generation (Default) Generate a complete HTML file using Tailwind CSS (via CDN). The page must: Match the design system from .design/DESIGN.md exactly Reuse the same header/nav/footer from existing pages (copy verbatim) Be self-contained — single HTML file with Tailwind CDN, no build step Be responsive — mobile-first, works at all breakpoints Include dark mode if the design system specifies it Use semantic HTML — proper heading hierarchy, landmarks, alt text Wire real navigation — all nav links point to actual pages (existing or planned) Write the generated file to site/public/{page}.html . Option B: Stitch Generation (If Available) If Stitch SDK is available: Build the prompt by combining the baton body with the DESIGN.md system block Call project.generate(prompt, deviceType) to generate the screen Download the HTML from screen.getHtml() to .design/designs/{page}.html Download the screenshot from screen.getImage() to .design/screenshots/{page}.png Post-process the Stitch HTML: Replace the header/nav/footer with your project's shared elements Ensure consistent Tailwind config Wire internal navigation links Save the processed file to site/public/{page}.html Update .design/metadata.json with the new screen ID For iterative edits on an existing Stitch screen, use screen.edit(prompt) instead of regenerating. Step 4: Integrate into the Site After generating the new page: Update navigation across ALL existing pages — add the new page to nav menus Fix placeholder links — replace any href="#" with real page URLs Verify cross-page consistency — header, footer, nav must be identical everywhere Check internal links — no broken links between pages Step 5: Visual Verification (If Browser Available) If Playwright CLI or Chrome MCP is available: Start a local server: npx serve site/public -p 3456 Screenshot the new page at desktop (1280px) and mobile (375px) widths Save screenshots to .design/screenshots/{page}-desktop.png and {page}-mobile.png Compare visually against the design system Fix any issues (broken layout, wrong colours, inconsistent nav) Stop the server If no browser automation is available, skip to Step 6. Step 6: Update Site Documentation Edit .design/SITE.md : Mark the page as complete in Section 4 (Sitemap): [x] {page}.html — {description} Remove any consumed item from Section 5 (Roadmap) or Section 6 (Ideas) Add any new ideas discovered during generation Step 7: Write the Next Baton (CRITICAL) You MUST update .design/next-prompt.md before completing. This keeps the loop alive. Choose the next page : First: Check Section 5 (Roadmap) for pending high-priority items Second: Check Section 5 for medium-priority items Third: Pick from Section 6 (Ideas) Last resort: Invent something that fits the site vision Write the baton with: YAML frontmatter ( page , optional layout ) Description of the page purpose and content Design system block copied from .design/DESIGN.md Section 6 Detailed page structure (numbered sections) If the site is complete (all roadmap items done, no more ideas): Write a baton with page: _complete and a summary of what was built This signals the loop is finished Loop Completion The loop ends when: All pages in the roadmap are built ( [x] in SITE.md Section 4) The user says to stop The baton contains page: _complete On completion, output a summary: Pages built (with links) Screenshots (if captured) Any remaining ideas for future work Cross-Page Consistency Rules The #1 risk in multi-page generation is drift — pages looking slightly different. Prevent this: Element Rule Header/Nav Copy exact HTML from the most recent page. Never regenerate. Footer Same — copy verbatim, only change active page indicator Tailwind config If using