Ship a Startup Website with AI Agents

Build a multi-page Next.js site using 5 parallel AI agents in Antigravity IDE.

Introduction

30 Second Summary

Every startup founder wants a website that looks like a million bucks, but most spend weeks going back and forth with designers and developers before anything goes live.

In this project, you will build and deploy a professional multi-page website for a fictional AI advisory startup called PineappleAI. You will use five parallel AI agents inside Google's Antigravity IDE to plan, build, test, and ship the entire site in under two hours.

What You'll Build

A fully deployed startup website built with Next.js 16, TypeScript, and Tailwind CSS, featuring a gold-and-black design system, accessible forms, automated tests, and a professional Git branching workflow.

By the end of this project, you'll have:

  • A live PineappleAI website deployed on Vercel with a landing page, services page, about page, and contact form.
  • A Playwright E2E test suite that validates navigation, form submission, and WCAG 2.2 AA accessibility compliance using automated axe-core scans.
  • A clean Git history with 5+ feature branches merged into main, built using Antigravity's parallel AI agents.
  • A case studies page with animated card transitions and an accessible dark/light mode toggle (Secret Mission).

Are there any prerequisites?

You need a Google account (for Antigravity sign-in), a GitHub account, and a free Vercel account. No prior experience with Next.js or Tailwind CSS is required. This guide walks you through installing and setting up every tool from scratch.

Set Up Your Development Environment

Before you can build the PineappleAI website, you need the right tools installed and talking to each other. Node.js runs your Next.js project locally, Git tracks every change you make, and Antigravity IDE gives you AI-powered coding with Gemini models built right in.

In this step, you will install all three tools, scaffold your Next.js project, and push it to GitHub.

In this step, get ready to:
  • Install Node.js and Git on your machine.
  • Install Antigravity IDE and sign in with your Google account.
  • Scaffold the PineappleAI Next.js project and push it to GitHub.
Install Node.js and Git

Next.js 16 requires Node.js version 20.9 or higher to run. Git lets you track changes and push your code to GitHub.

  • Open your browser and go to nodejs.org/en/download.
  • Download the Windows Installer (.msi) for the LTS version.
  • Run the installer and accept all the default options.
  • The installer will ask if you want to install tools for native modules. Check the box and click Next.

What is Node.js?

Node.js is a JavaScript runtime that lets you run JavaScript outside the browser. Next.js uses it to build and serve your website during development.

  • Open your browser and go to git-scm.com/install/windows.
  • Download the 64-bit Git for Windows Setup installer.
  • Run the installer and accept all the default options.

Now verify both tools are installed.

  • Press the Windows key to open your search bar.
  • Type PowerShell and press Enter to open it.
  • Check your Node.js version by running this command:
node --version
  • Check your Git version by running this command:
git --version

I see version numbers

Your Node.js version should be 20.9 or higher, and Git should show any version number. You are all set to move on.

Command not found

If either command shows an error, the installer did not add the tool to your system PATH.

  • Close PowerShell completely.
  • Reopen PowerShell and try the command again.
  • If it still fails, rerun the installer for the missing tool and make sure you accept all defaults.

Restarting PowerShell is the most common fix because the PATH update only takes effect in new terminal sessions.

Install Antigravity IDE and sign in

Antigravity IDE is Google's AI-powered code editor. It gives you access to Gemini 3 Pro and Gemini 3 Flash models directly in your editor, plus an Agent Manager for running multiple AI agents in parallel.

  • Open your browser and go to antigravity.google.
  • Click the Download button.
  • Download the Windows .exe installer.
  • Run the installer and follow the setup wizard.
  • Once installation completes, press the Windows key to open your search bar.
  • Type Antigravity and press Enter to launch it.

When Antigravity opens for the first time, it prompts you to sign in.

  • Sign in with your Google account when prompted.
  • This unlocks access to Gemini 3 Pro and Gemini 3 Flash models at no cost during the public preview.

Confirm that Antigravity is working by checking two views.

  • You should see the Editor view with a file explorer on the left and an editor pane in the center.
  • Press Ctrl+E to switch to the Agent Manager view.
  • Press Ctrl+E again to switch back to the Editor view.

What is the Agent Manager?

The Agent Manager is where you run multiple AI agents in parallel, each in its own workspace. You will use it in Step 4 to build two pages at the same time. For now, just confirm you can switch between the Editor and Agent Manager views.

Don't see the sign-in prompt?

Open the Command Palette with Ctrl+Shift+P and search for Sign In. Select the Google sign-in option.

Help me sign in to Antigravity IDE with my Google account.

Create the Next.js project and push to GitHub

Now you will scaffold the PineappleAI project using Next.js 16. The scaffolding command sets up TypeScript, Tailwind CSS, ESLint, and the App Router automatically.

  • Open the integrated terminal in Antigravity by pressing Ctrl+`.
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Scaffold the PineappleAI project by running this command:
npx create-next-app@latest pineapple-ai --yes

What does this command do?

  • `npx create-next-app@latest` downloads and runs the latest Next.js project scaffolding tool.
  • `pineapple-ai` is the name of your project folder.
  • `--yes` accepts all the recommended defaults: TypeScript, ESLint, Tailwind CSS, App Router, Turbopack, and an AGENTS.md file for AI coding agents.

This command also initializes a Git repository inside the pineapple-ai folder with a main branch and an initial commit.

  • Wait for the installation to finish. You will see a success message once all dependencies are installed.
  • Move into the project folder by running this command:
cd pineapple-ai

Now open the project in Antigravity so you can see all the files it created.

  • In Antigravity, click File in the top menu bar.
  • Click Open Folder.
  • Navigate to your Desktop, select the pineapple-ai folder, and click Select Folder.

Antigravity reopens with your pineapple-ai project loaded. You should see folders like app/, public/, and files like package.json and tailwind.config.ts in the Explorer sidebar on the left.

Don't see the project files?

If the Explorer sidebar is hidden, press Ctrl+Shift+E to open it. Make sure you selected the pineapple-ai folder itself, not the Desktop folder that contains it.

Help me open my pineapple-ai project in Antigravity IDE.

Now push your project to GitHub so you have a remote backup and can deploy later.

  • Open your browser and go to github.com/new.
  • Enter pineapple-ai as the Repository name.
  • Leave the repository set to Public.
  • Do not check any boxes for README, .gitignore, or license. Your project already has these.
  • Click Create repository.

GitHub shows a setup page with commands for pushing an existing repository.

  • Back in the Antigravity terminal, connect your local project to GitHub and push by running these commands:
git remote add origin https://github.com/[[GITHUB_USERNAME="your-github-username"]]/pineapple-ai.git
git push -u origin main

What do these commands do?

  • `git remote add origin` tells Git where your GitHub repository lives so it knows where to push code.
  • `git push -u origin main` uploads your code to GitHub and sets main as the default branch for future pushes.

Push succeeded

You should see output ending with a line like Branch 'main' set up to track remote branch 'main' from 'origin'. Your code is now on GitHub.

Authentication error

If Git asks for your username and password, GitHub no longer accepts passwords for command-line access. You need to set up a personal access token or use the GitHub CLI.

  • The fastest fix is to install the GitHub CLI by running this command:
winget install --id GitHub.cli
  • Close and reopen your terminal, then authenticate by running:
gh auth login
  • Follow the prompts: select GitHub.com, then HTTPS, then Login with a web browser.
  • After authenticating, try the git push command again.

Help me push my code to GitHub from the command line.

Finally, create the develop branch that you will use as your integration branch throughout the project.

  • Create and switch to the develop branch by running this command:
git checkout -b develop
  • Push the develop branch to GitHub by running:
git push -u origin develop

Why a develop branch?

The main branch is your production branch. It only receives code that has been tested and reviewed. The develop branch is your integration branch where feature branches get merged first. This keeps main stable at all times.

  • Verify your branch setup by running:
git branch -a

You should see main and * develop in the output, with the asterisk indicating you are on the develop branch.

Don't see both branches?

Make sure you ran git checkout -b develop from inside the pineapple-ai folder. If you are in the wrong directory, run cd ~/Desktop/pineapple-ai to get back.

Help me set up my Git branches for the PineappleAI project.

Your development environment is ready. Next up, you will use Gemini Pro to plan the site architecture, design system, and branching strategy before writing any code.

Plan the Architecture with Gemini Pro

Your Next.js project is scaffolded, pushed to GitHub, and ready for code.

Before writing a single component, you need a plan. In this step, you will use Gemini Pro inside Antigravity IDE to design the site architecture, define a design system, and set up a branching strategy. This follows a standardized software development lifecycle: plan first, build second.

In this step, get ready to:
  • Create an AGENTS.md configuration file that tells every Antigravity agent how to behave.
  • Prompt Gemini Pro to generate the full site architecture, component hierarchy, and design tokens.
  • Set up five Git feature branches that map to each phase of the build.
Create the AGENTS.md configuration file

AGENTS.md is a Markdown file that lives in your project root and tells every AI agent in Antigravity how to behave. It defines your coding standards, design tokens, accessibility requirements, and model selection rules. Every agent that works on your project reads this file automatically.

Why AGENTS.md instead of GEMINI.md?

Antigravity supports both AGENTS.md and GEMINI.md, but AGENTS.md is the universal standard. It works across Cursor, Windsurf, Claude Code, and other AI coding tools. If both files exist, AGENTS.md takes priority.

  • Open the Antigravity chat panel by pressing Ctrl+E (Windows) or Cmd+E (macOS).
  • Make sure the model selector at the top of the chat is set to Gemini 3 Pro.
  • Type the following prompt into the Antigravity chat and press Enter:
Create an AGENTS.md file in the project root for a Next.js 16 project called PineappleAI.

Include these sections:

1. Project Overview: PineappleAI is an AI integration advisory company. Mission: "Clarity Before Action."

2. Tech Stack: Next.js 16, TypeScript (strict mode), Tailwind CSS v4, Playwright for E2E testing.

3. Design System:
   - Gold: #D4A843
   - Black: #0A0A0A
   - Warm White: #F5F0E8
   - Use @theme in globals.css for Tailwind v4 color tokens.

4. Accessibility: All code must meet WCAG 2.2 AA. Use semantic HTML elements (nav, header, main, footer). Every input needs a programmatically associated label. Focus indicators must be at least 2px thick with 3:1 contrast.

5. Git Branching: Use a develop/main model. Feature branches follow the pattern feature/feature-name. Always branch from develop.

6. Model Selection Rules:
   - Use Gemini Pro for: architecture planning, debugging, accessibility audits, code review.
   - Use Gemini Flash for: component scaffolding, styling, documentation, test generation.
   - Rule of thumb: If the task has a clear correct answer you could verify in under 30 seconds, use Flash. If it requires reasoning about tradeoffs, use Pro.

What does this prompt do?

This prompt asks Gemini Pro to create a configuration file that every future agent will read before making changes to your project.

  • The design system section locks in the gold-and-black color palette so agents stay consistent.
  • The accessibility section ensures every agent follows WCAG 2.2 AA from the start.
  • The model selection rules help you pick the right Gemini model for each task throughout the project.
  • Review the generated AGENTS.md file. Gemini Pro will ask for your approval before writing it to disk.
  • Click Accept to approve the file creation.
  • Confirm the file exists by running:
ls AGENTS.md

You should see AGENTS.md listed in the output.

Don't see AGENTS.md?

  • Make sure your terminal is inside the pineapple-ai folder. Run pwd to check your current directory.
  • If Gemini Pro generated the content in the chat but did not create the file, copy the output and manually create AGENTS.md in the project root.
  • Why can't Antigravity find my project files?
Prompt Gemini Pro to generate the site architecture

PineappleAI needs four pages: a landing page, a services page, an about page, and a contact page. Before building any of them, you need Gemini Pro to plan the full folder structure, decide which components are shared versus page-specific, and define the design tokens.

  • In the same Antigravity chat (still using Gemini 3 Pro), type this prompt and press Enter:
Plan the full site architecture for PineappleAI. We need a landing page, services page, about page, and contact page. Use Next.js App Router with a shared layout.

For each page, list:
- The route path
- The page-specific components it needs
- Any shared components (Header, Footer, Button, etc.)

Create a component hierarchy showing which components are shared vs page-specific.

Output:
1. The complete folder structure under app/
2. A list of shared components under components/
3. The Tailwind v4 @theme color tokens I should add to app/globals.css for the gold-and-black design system (gold: #D4A843, black: #0A0A0A, warm white: #F5F0E8)

Why use Pro for architecture planning?

Architecture decisions affect every file in the project. A wrong folder structure or missing shared component means refactoring later. Gemini Pro excels at reasoning about tradeoffs and dependencies across an entire codebase. Gemini Flash is faster, but it is optimized for well-defined tasks with clear correct answers.

Gemini Pro will output a plan. Review it to make sure it includes these key elements:

  • Confirm the folder structure has route folders under app/ for each page: app/services/page.tsx, app/about/page.tsx, and app/contact/page.tsx.
  • Confirm there is a shared app/layout.tsx that wraps all pages with a common header and footer.
  • Confirm the Tailwind CSS v4 @theme block includes color tokens for gold, black, and warm white.

What are @theme tokens in Tailwind v4?

Tailwind CSS v4 replaced the old tailwind.config.ts approach with a CSS-first configuration. You define design tokens using the @theme directive directly in your CSS file (like app/globals.css). For example, defining --color-gold: #D4A843 inside @theme automatically creates utility classes like bg-gold, text-gold, and border-gold.

The color tokens Gemini Pro suggests should look something like this in your app/globals.css:

@import "tailwindcss";

@theme {
  /* PineappleAI gold-and-black design system */
  --color-gold: #D4A843;
  --color-black: #0A0A0A;
  --color-warm-white: #F5F0E8;
}

What does this code do?

  • @import "tailwindcss" loads Tailwind's default theme and utility classes.
  • The @theme block extends the default theme with three custom colors. Tailwind v4 automatically generates utility classes from these variables.
  • #D4A843 (muted gold) on #0A0A0A (black) has a contrast ratio of approximately 12.6:1, which comfortably passes the WCAG AA minimum of 4.5:1 for body text.
  • Do not apply these changes to globals.css yet. You will add the design tokens when you build the landing page in the next step.

Pro tip: save the plan

Copy Gemini Pro's architecture plan into a file called ARCHITECTURE.md in your project root. This gives you a reference document to check against as you build each page.

Set up the Git branching strategy

Each major phase of the build gets its own Git feature branch. This keeps work isolated and creates a clean merge history that demonstrates a professional branching workflow.

  • Make sure you are on the develop branch by running:
git checkout develop
  • Create all five feature branches by running these commands:
git branch feature/landing-page
git branch feature/services-about
git branch feature/contact-form
git branch feature/accessibility
git branch feature/e2e-tests

What does this do?

  • git branch creates a new branch from your current position without switching to it.
  • Each branch maps to a build step and an agent workspace in Antigravity.
  • feature/landing-page is for the hero section and navigation. feature/services-about covers the services and about pages. feature/contact-form is for the accessible contact form. feature/accessibility is for the site-wide accessibility audit. feature/e2e-tests is for Playwright tests.
  • Verify all five branches exist by running:
git branch

You should see all five feature branches listed, plus develop and main. The asterisk (*) next to develop shows it is your active branch.

Missing branches or seeing an error?

  • If you see "fatal: not a git repository", make sure your terminal is inside the pineapple-ai folder.
  • If the develop branch does not exist, you may have skipped creating it in Step 1. Run git checkout -b develop to create it now, then re-run the five git branch commands above.
  • Why are my Git branches not showing up?
  • Commit the AGENTS.md file to the develop branch by running these commands:
git add AGENTS.md
git commit -m "Add AGENTS.md project configuration"
git push origin develop

What does this do?

  • git add AGENTS.md stages the file for commit.
  • git commit saves the change to your local Git history with a descriptive message.
  • git push origin develop uploads the commit to your GitHub repository on the develop branch.

Your architecture plan is locked in and your branches are ready. Next up, you will switch to the feature/landing-page branch and start building the hero section, navigation, and the visual identity of PineappleAI.

Build the Landing Page

In the previous step, you planned the full site architecture with Gemini Pro. You have an AGENTS.md config file, a Tailwind theme with gold-and-black tokens, and five feature branches ready to go.

Now it is time to build the first thing visitors see. The landing page sets the tone for PineappleAI with a hero section, service highlights, and site-wide navigation. You will work on the feature/landing-page branch and use Gemini Flash to scaffold components quickly.

In this step, get ready to:
  • Build the root layout with a responsive header, navigation, and footer.
  • Create the hero section and service highlights for the landing page.
  • Test locally, commit, and merge into the develop branch.
Build the layout shell and navigation

Every page on the PineappleAI site shares the same header and footer. In Next.js, the root layout file wraps every page automatically. This is where you define the site-wide navigation, branding, and footer.

  • Switch to the feature/landing-page branch by running this command in the Antigravity terminal:
git checkout feature/landing-page
  • Open app/layout.tsx in the Antigravity editor. This is the root layout file that create-next-app generated for you.
  • Open the Antigravity chat panel and select Gemini 3 Flash as your model. Flash is the right choice here because scaffolding a layout is a well-defined task with clear requirements.
  • Enter this prompt to generate the layout shell:
Create a root layout for PineappleAI with a responsive header and footer.
The header should have the PineappleAI logo text on the left, navigation
links (Services, About, Case Studies, Contact) in the center, and a gold
CTA button 'Get Started' on the right. Use semantic HTML (nav, header,
main, footer). Mobile should collapse to a hamburger menu. Footer has
copyright and social links. Gold (#D4A843) on black (#0A0A0A) color
scheme. Warm white (#F5F0E8) for body text. All interactive elements
must meet the 24x24 CSS pixel minimum target size (WCAG 2.5.8).

Why Gemini Flash instead of Pro?

The model selection rule from your AGENTS.md applies here. Flash is 2-2.5x faster than Pro and matches Pro's quality on well-defined scaffolding tasks. Save Pro for architecture decisions, debugging, and accessibility audits where reasoning about tradeoffs matters.

  • Review the code that Gemini Flash generates. Before accepting, check that it uses semantic HTML elements.
  • Confirm the layout includes a <header> with a <nav> inside it, a <main> element wrapping {children}, and a <footer> at the bottom.
  • Accept the generated code to apply it to your app/layout.tsx file.

What is semantic HTML?

Semantic HTML means using elements that describe their purpose. A <nav> element tells browsers and screen readers "this is navigation." A <main> element says "this is the primary content." These landmarks help assistive technologies understand the page structure without relying on visual layout.

  • Save app/layout.tsx.
  • Start the dev server by running this command:
npm run dev
  • Open http://localhost:3000 in your browser. You should see the PineappleAI header with the logo text, navigation links, and a gold Get Started button on a black background.

Don't see the header?

  • Make sure you saved app/layout.tsx before checking the browser.
  • Check that npm run dev is still running in your terminal. If you see an error, read the terminal output for the specific issue.
  • Verify that the Tailwind color classes reference the correct hex values from your tailwind.config.ts theme tokens.
  • Why isn't my PineappleAI header showing up after saving layout.tsx?
Build the hero section and service highlights

The landing page is the first impression visitors get. The hero section communicates PineappleAI's mission with a bold headline, and the service highlights give visitors a quick overview of what the company offers.

  • Open app/page.tsx in the Antigravity editor. This is the home page component that renders at the root URL.
  • In the Antigravity chat (still using Gemini 3 Flash), enter this prompt:
Create the landing page for PineappleAI in app/page.tsx. Include:
1. A hero section with the headline 'Clarity Before Action' as an h1,
   a subheadline about AI strategy consulting, and a gold (#D4A843)
   CTA button.
2. A services overview section with an h2 heading and three service
   cards in a responsive grid: AI Strategy Consulting, Process
   Automation, and AI Integration. Each card has a heading, a short
   description, and a 'Learn More' link.
3. Use Tailwind CSS for all styling. The design should feel calm,
   spacious, and modern with generous whitespace.
4. Use semantic heading hierarchy (h1 for hero, h2 for sections,
   h3 for card titles).
5. Gold (#D4A843) and black (#0A0A0A) color scheme with warm white
   (#F5F0E8) text.

Why does heading hierarchy matter?

Screen readers use headings to build a page outline. An <h1> is the page title, <h2> marks major sections, and <h3> marks subsections. Skipping levels (jumping from <h1> to <h4>) breaks this outline and confuses assistive technology users. This is a WCAG best practice.

  • Review the generated code. Check that the hero section uses an <h1> for "Clarity Before Action" and the services section uses an <h2>.
  • Verify that each service card has an <h3> for its title.
  • Accept the generated code to apply it to app/page.tsx.

Pro tip: review before accepting

Always review AI-generated code before accepting it. Check for hardcoded colors instead of Tailwind theme tokens, missing alt attributes on images, and heading levels that skip from h1 to h3. Catching these early saves debugging time later.

  • Save app/page.tsx.
  • Check your browser at http://localhost:3000. You should see a large "Clarity Before Action" headline in warm white text on a black background, a gold CTA button below it, and three service cards in a grid further down the page.

Page looks unstyled or broken?

  • Check that app/globals.css is imported in your app/layout.tsx. Tailwind CSS classes only work if the global stylesheet is loaded.
  • Make sure the gold color references match your tailwind.config.ts theme tokens. If Flash used raw hex values instead of theme classes, the colors will not update consistently.
  • My PineappleAI landing page looks unstyled. How do I fix the Tailwind CSS configuration?
Test locally and commit

Before committing, you need to verify the landing page looks correct at three breakpoints. Responsive design ensures the site works on phones, tablets, and desktops.

  • Open your browser's DevTools by pressing Ctrl+Shift+I (Windows) or Cmd+Option+I (macOS).
  • Click the Toggle device toolbar button (the phone/tablet icon) in DevTools.
  • Set the viewport width to 375px to test mobile. Verify the navigation collapses to a hamburger menu and the hero headline is readable.
  • Set the viewport width to 768px to test tablet. Verify the service cards stack or rearrange appropriately.
  • Set the viewport width to 1280px to test desktop. Verify the full navigation is visible and the service cards display in a row.

What are responsive breakpoints?

Breakpoints are viewport widths where the layout changes. Tailwind CSS uses sm (640px), md (768px), lg (1024px), and xl (1280px) by default. Testing at 375px covers the smallest common phone screen. Testing at 768px and 1280px covers tablet and desktop.

  • Once the layout looks correct at all three breakpoints, commit your changes by running these commands:
git add .
git commit -m "feat: add landing page with hero section and service highlights"

What does this commit message mean?

The feat: prefix follows the Conventional Commits standard. It signals that this commit adds a new feature. This makes your Git history easy to scan when reviewing changes later.

  • Merge the landing page into the develop branch by running these commands:
git checkout develop
git merge feature/landing-page
  • Verify the merge succeeded by running:
git log --oneline -5
  • You should see your "feat: add landing page" commit in the log output. This confirms the landing page code is now on the develop branch.

Seeing a merge conflict?

  • Merge conflicts happen when the same file was changed on both branches. If you only worked on feature/landing-page, this should not occur.
  • If you do see a conflict, open the conflicting file in Antigravity. Look for the <<<<<<< and >>>>>>> markers. Keep the version you want, delete the markers, then save and run git add . followed by git commit.
  • I'm getting a merge conflict when merging feature/landing-page into develop. How do I resolve it?

Your landing page is live on the develop branch. Next up, you will use Antigravity's Agent Manager to build the Services and About pages simultaneously with parallel agents.

Build the Services and About Pages with Parallel Agents

Your landing page is live and merged into develop. Now it is time to add the two content pages that tell visitors what PineappleAI does and who the team is.

Instead of building these pages one after the other, you will use Antigravity's Agent Manager to run two agents in parallel. One agent builds the services page while the other builds the about page at the same time. This is the core workflow of AI-assisted parallel development: assign clear tasks, isolate the work, and review before merging.

In this step, get ready to:
  • Set up two parallel agents in Antigravity's Agent Manager.
  • Prompt each agent to build a separate page (services and about).
  • Review, approve, and merge both pages into the develop branch.
Set up parallel agents in Agent Manager

Up until now, you have been working in Antigravity's Editor view, which is a single-agent workflow. The Agent Manager is a separate view that lets you orchestrate multiple agents across workspaces at the same time.

  • First, switch to the feature/services-about branch by running this command in the Antigravity terminal:
git checkout feature/services-about
  • Switch to the Agent Manager view by pressing Cmd+E (macOS) or Ctrl+E (Windows).
  • You should see the Agent Manager dashboard with sections for Inbox, Start Conversation, and Workspaces.
  • Confirm your pineapple-ai project folder appears under Workspaces in the left sidebar.
  • If it does not appear, click the workspace button in the left sidebar and select your pineapple-ai folder to add it.

What is the Agent Manager?

The Agent Manager is Antigravity's "mission control" view. It lets you start multiple agent conversations across workspaces, monitor their progress, and approve their changes from a single dashboard. Each conversation you start becomes an independent agent working on its assigned task.

You will start two conversations in the same workspace. Because the services page and about page are completely separate files, the agents will not conflict with each other.

  • Click Start Conversation in the Agent Manager.
  • Select your pineapple-ai workspace.
  • Choose Gemini 3 Flash as the model.
  • Select Fast mode, since these are well-defined scaffolding tasks.

This starts your first agent (Agent 1), which you will assign to the services page. Leave this conversation open for now.

  • Click Start Conversation again to create a second conversation in the same pineapple-ai workspace.
  • Choose Gemini 3 Flash and Fast mode again.

You now have two agent conversations ready to receive prompts. Both point at the same project folder but will work on different files.

Why Gemini Flash for both agents?

These pages are content-focused scaffolding tasks with clear requirements. Gemini 3 Flash matches Pro quality on over 70% of well-defined tasks while running 2-2.5x faster. Save Pro for tasks that require reasoning about tradeoffs, like accessibility audits and debugging.

Don't see Start Conversation?

Make sure you are in the Agent Manager view, not the Editor view. Press Cmd+E (macOS) or Ctrl+E (Windows) to toggle between them. You can also click Open Agent Manager in the top-right corner of the menu bar.

Help me switch to the Agent Manager view in Antigravity

Prompt both agents with natural language

Each agent needs a detailed prompt describing what to build. The more specific your prompt, the closer the output matches your design system on the first pass.

  • Click on the first agent conversation (Agent 1) in the left sidebar.
  • Paste the following prompt into the chat to build the services page:
Build a services page at /services for PineappleAI. Create the file at app/services/page.tsx.

Show three service offerings in a responsive bento-grid layout:
1. AI Strategy Consulting
2. Process Automation
3. AI Integration

Each card should have:
- An icon (use a simple SVG or emoji placeholder)
- A heading (h2)
- A 2-sentence description
- A "Learn More" link

Use the gold (#D4A843) and black (#0A0A0A) theme from our design system.
Warm white (#F5F0E8) for card backgrounds.
Calm, spacious layout with generous padding.
Use semantic HTML elements.
All interactive elements must be at least 24x24 CSS pixels.
Add TypeScript types for the service data.

What does this prompt do?

  • It tells the agent exactly where to create the file (app/services/page.tsx) so the Next.js App Router automatically maps it to the /services URL.
  • It specifies the three service offerings, the card structure, and the exact color tokens from your design system.
  • It includes the WCAG 2.5.8 target size requirement (24x24 CSS pixels) so the agent builds accessibility in from the start.
  • Now click on the second agent conversation (Agent 2) in the left sidebar.
  • Paste the following prompt into the chat to build the about page:
Build an about page at /about for PineappleAI. Create the file at app/about/page.tsx.

Lead with the mission statement: "We provide clarity before action."

Follow with three core values, each with a heading (h2) and a short paragraph:
1. Transparency
2. Precision
3. Partnership

Single-column centered layout, max-width 768px.
Gold (#D4A843) accents on black (#0A0A0A) background.
Include a team section placeholder with a heading and a paragraph that says "Meet the team behind PineappleAI."
Use semantic HTML elements.
Add TypeScript types for the values data.
All interactive elements must be at least 24x24 CSS pixels.

Both agents start working as soon as you submit the prompts. You can watch their progress in the Agent Manager.

  • Check the Inbox section in the Agent Manager for any approval requests from either agent.
  • When an agent requests approval, review the proposed changes and click to approve.

Pro tip: watch the Inbox

The Inbox is your queue for pending actions from all active agents. Approval requests, clarifying questions, and completion notifications all appear here. Process them as they arrive so agents are not blocked waiting for your feedback.

Agent stuck or producing unexpected output?

If an agent creates files in the wrong location, check that your prompt specifies the exact path (app/services/page.tsx or app/about/page.tsx). You can add a follow-up message in the same conversation to correct the agent.

If the agent uses colors that do not match your design system, make sure your AGENTS.md file (created in Step 2) includes the gold and black color tokens. The agent reads this file for project-wide standards.

Help me fix my agent's output in Antigravity

Review, approve, and merge

Both agents have produced their pages. Before you commit anything, you need to verify that the output matches your design system and uses proper semantic HTML.

  • Switch back to the Editor view by pressing Cmd+E (macOS) or Ctrl+E (Windows).
  • Open app/services/page.tsx in the file explorer and verify the following:
  • Three service cards are present (AI Strategy Consulting, Process Automation, AI Integration).
  • The layout uses Tailwind CSS grid classes for the bento-grid pattern.
  • Headings use h2 elements (semantic heading hierarchy).
  • Gold (#D4A843) and black (#0A0A0A) colors are applied correctly.
  • Open app/about/page.tsx and verify the following:
  • The mission statement "We provide clarity before action." appears at the top.
  • Three core values (Transparency, Precision, Partnership) each have a heading and paragraph.
  • The layout is single-column and centered.
  • A team section placeholder is present.
  • Start the dev server to test both pages locally by running:
npm run dev
  • Open your browser and navigate to http://localhost:3000/services.
  • Verify the bento-grid layout displays three service cards with gold accents on a dark background.
  • Resize your browser window to check responsive behavior at mobile (375px), tablet (768px), and desktop (1280px) widths.
  • Navigate to http://localhost:3000/about.
  • Verify the mission statement, three values, and team placeholder all render in a clean single-column layout.

Pages showing a 404?

Make sure the agent created the files at the correct paths: app/services/page.tsx and app/about/page.tsx. The Next.js App Router uses folder-based routing. Each route needs its own folder inside app/ with a page.tsx file.

If the files are in the wrong location, move them to the correct folders and restart the dev server.

Help me fix my Next.js page routing

  • Once both pages look correct, commit your changes by running these commands:
git add .
git commit -m "Add services and about pages with bento-grid and values layout"

What does this commit include?

This single commit captures the work of both agents: the services page with its bento-grid layout and the about page with its single-column values layout. Both were built in parallel but committed together because they belong to the same feature branch.

  • Merge the feature branch into develop by running:
git checkout develop
git merge feature/services-about
  • Verify the merge succeeded by running npm run dev and checking both /services and /about one more time.

Merge conflict?

Merge conflicts are unlikely here because the services and about pages are entirely new files. If you do see a conflict, it is probably in a shared file like layout.tsx (if an agent modified the navigation). Open the conflicting file, choose which version to keep, save it, then run:

git add .
git commit -m "Resolve merge conflict in layout"

Help me resolve this Git merge conflict

Both content pages are merged and ready. Next up, you will build the contact form with full accessibility compliance using a Flash-then-Pro workflow.

Build the Accessible Contact Form

Your services and about pages are live on the develop branch. The next piece of PineappleAI that visitors will interact with is the contact form.

Forms are where accessibility matters most. A sighted mouse user can glance at a field and guess what goes there. A screen reader user relies entirely on programmatic labels, error announcements, and logical tab order. In this step, you will build the contact form with full WCAG 2.2 AA compliance using a Flash-then-Pro workflow: scaffold fast, then audit deep.

In this step, get ready to:
  • Scaffold the contact form with Gemini Flash and audit it with Gemini Pro for accessibility.
  • Add client-side validation with accessible error handling using aria-describedby and aria-live regions.
  • Verify keyboard navigation and focus indicators across the entire form.
Scaffold the form with Gemini Flash, then audit with Gemini Pro

This substep demonstrates a powerful AI workflow. You use Gemini Flash for fast scaffolding because the form structure is well-defined. Then you switch to Gemini Pro for the accessibility audit because catching WCAG violations requires reasoning about downstream impact.

Why Flash-then-Pro instead of Pro for everything?

Flash matches Pro quality on 70%+ of well-defined tasks while being 2-2.5x faster. Scaffolding a form with known fields is a well-defined task. Auditing that form for accessibility gaps requires reasoning about how screen readers interpret the DOM, which is where Pro excels. Using both models strategically saves time without sacrificing quality.

  • Switch to the feature/contact-form branch by running this command in the Antigravity terminal:
git checkout feature/contact-form

Branch not found?

Make sure you created this branch back in Step 2. If you skipped that, create it now with git checkout -b feature/contact-form.

Help me fix my branch issue.

  • Open the Antigravity chat panel and make sure Gemini Flash is selected as the model.
  • Paste this prompt to scaffold the contact form:
Create a contact form component for PineappleAI at /contact. Fields: Full Name (required), Email (required), Company Name, Service Interest (dropdown: Strategy, Automation, Integration, Not Sure), and Message (textarea, required). Gold submit button. Use the PineappleAI design system.

What does this prompt produce?

Flash generates a React component at app/contact/page.tsx with five form fields, a gold submit button, and basic Tailwind styling matching the gold-and-black theme. The output is functional but may have accessibility gaps that Pro will catch next.

  • Review the generated code in the Antigravity diff view.
  • Click Accept to apply the changes.

Now it is time to bring in the expert. Flash builds fast, but Pro catches what Flash misses.

  • Switch the model selector in the Antigravity chat to Gemini Pro.
  • Paste this accessibility audit prompt:
Audit this contact form for WCAG 2.2 AA compliance. Check: (1) Every input has a programmatically associated label, not just a placeholder. (2) Required fields are indicated before the user starts filling in. (3) Error messages use aria-describedby and are not color-only. (4) Focus indicators are at least 2px thick with 3:1 contrast. (5) All interactive targets are at least 24x24 CSS pixels. (6) Tab order matches visual order. Fix every issue you find.

What will Pro catch?

  • Placeholder-only labels. Placeholders disappear when you start typing, leaving screen reader users with no field description.
  • Missing aria-describedby on error messages. Without this attribute, screen readers cannot associate an error with its field.
  • Color-only error indicators. A red border alone fails WCAG because colorblind users cannot see it. Text-based messages are required.
  • Focus indicators that are too thin or low-contrast against the dark background.
  • Review the fixes Pro suggests in the diff view.
  • Click Accept to apply all accessibility fixes.
  • Save all modified files.
  • Start the dev server by running this command:
npm run dev
  • Open http://localhost:3000/contact in your browser.
  • You should see a contact form with five labeled fields, a gold Submit button, and visible required-field indicators (asterisks or "required" text) next to the Full Name, Email, and Message fields.

Form not showing up?

Check that the file is saved at app/contact/page.tsx (not pages/contact.tsx). Next.js App Router uses the app/ directory for routing.

Help me debug my contact page routing.

Add client-side validation with accessible error handling

Showing an error message is only half the job. The error must also be programmatically linked to its field so screen readers can announce it.

  • In the Antigravity chat (still using Gemini Pro), paste this prompt to add validation logic:
Add client-side validation to the PineappleAI contact form. Requirements: (1) On submit, validate that Full Name, Email, and Message are not empty. (2) Validate that Email matches a valid email format. (3) Show an error message below each invalid field. (4) Each error message must use aria-describedby to link it to its field. (5) Set aria-invalid="true" on invalid fields only after validation runs. (6) Wrap all error messages in an aria-live="polite" region so screen readers announce them. (7) Required fields must show "(required)" in their labels before the user interacts. Do not rely on color alone to indicate errors.

What are aria-describedby and aria-live doing here?

  • aria-describedby links an error message element to its input field by ID. When a screen reader focuses the field, it reads the label first, then the linked error description.
  • aria-invalid="true" tells assistive technologies that a field has failed validation. Screen readers like JAWS and NVDA announce "invalid entry" when the user tabs to the field.
  • aria-live="polite" creates a live region. When error text appears inside it, screen readers announce the new content without interrupting the user's current action.
  • Review the validation code Pro generates. Confirm that each error <span> has a unique id and that the matching input has aria-describedby pointing to that id.
  • Click Accept to apply the changes.
  • Save app/contact/page.tsx.
  • Refresh your browser at http://localhost:3000/contact.
  • Click the Submit button without filling in any fields.
  • You should see error messages below each required field, such as "Full Name is required."

Error messages not appearing?

Make sure the form's onSubmit handler calls e.preventDefault() to stop the browser's default form submission. Without this, the page reloads before your validation logic runs.

Help me fix my form validation.

Why mark required fields before the user starts filling in?

WCAG 3.3.2 (Labels or Instructions) requires that required fields be identified upfront. If a user fills out the entire form and only discovers on submission that three fields were mandatory, they have wasted effort. Showing "(required)" in the label from the start sets clear expectations.

Verify keyboard navigation and focus indicators

Automated tools catch about 30-40% of accessibility issues. The rest require manual testing. Keyboard navigation is one of those things you have to test by hand.

  • Click in the browser's URL bar at http://localhost:3000/contact to move focus out of the page.
  • Press Tab repeatedly to move through every interactive element on the page.
  • Confirm that focus moves in a logical order: navigation links first, then Full Name, Email, Company Name, Service Interest dropdown, Message textarea, and finally the Submit button.
  • At each field, check that a visible focus ring appears around the element. The ring should be clearly visible against the dark background.
  • Press Enter or Space on the Submit button to confirm it is activatable via keyboard.

What makes a focus indicator WCAG-compliant?

  • The indicator must be at least 2 CSS pixels thick (WCAG 2.4.7 Focus Visible requires a visible indicator, and 1.4.11 Non-text Contrast requires 3:1 contrast for UI components).
  • The focused element must not be entirely hidden by sticky headers or footers (WCAG 2.4.11 Focus Not Obscured).
  • The gold color #D4A843 on the black background #0A0A0A has a contrast ratio of approximately 21:1. This far exceeds the 3:1 minimum for focus indicators and the 4.5:1 minimum for body text.

If any field is unreachable by Tab, or the focus ring is invisible or too thin, you need to fix it before moving on.

  • If focus indicators need fixing, paste this prompt into Antigravity with Gemini Pro selected:
The focus indicators on the PineappleAI contact form are not visible enough against the dark background. Add a custom focus style to all interactive elements: outline: 2px solid #D4A843 with outline-offset: 2px. Make sure the focus ring is visible on inputs, the select dropdown, the textarea, and the submit button. Use the :focus-visible pseudo-class so mouse users don't see the ring unnecessarily.

Why :focus-visible instead of :focus?

The :focus pseudo-class applies to every focus event, including mouse clicks. This creates distracting outlines when users click buttons. The :focus-visible pseudo-class only activates when the browser determines focus was triggered by keyboard navigation. Keyboard users see the ring. Mouse users do not.

  • After applying any fixes, tab through the form one more time to confirm every field has a visible gold focus ring.
  • Try completing the entire form using only your keyboard. Fill in each field, select a dropdown option with arrow keys, and submit with Enter.

Pro tip: the mouse-free test

If you can complete the entire contact form without touching your mouse, the form passes keyboard accessibility. This is the single most important manual test you can run.

  • Commit your changes and merge into develop by running these commands:
git add .
git commit -m "Add accessible contact form with validation"
git checkout develop
git merge feature/contact-form

What do these commands do?

  • git add . stages all changed files for commit.
  • git commit -m saves the staged changes with a descriptive message.
  • git checkout develop switches to the integration branch.
  • git merge feature/contact-form brings the contact form code into develop.

You should see a "merge made" or "fast-forward" message confirming the merge succeeded.

Merge conflict?

If you see a conflict, it likely means another branch modified the same layout file. Open the conflicting file, look for the <<<<<<< HEAD markers, keep both sets of changes, remove the markers, save, and run git add . followed by git commit.

Help me resolve my merge conflict.

Your contact form is accessible, validated, and merged. Next up, you will run an automated accessibility audit across every page to catch anything the manual checks might have missed.

Run an Accessibility Audit Across All Pages

In the previous step, you built an accessible contact form with client-side validation and keyboard navigation. The form handles errors gracefully and every field is reachable by keyboard.

Now it is time to verify the entire site meets WCAG 2.2 AA standards, not just the contact form. You will install @axe-core/playwright, run automated scans against every page, feed the results to Gemini Pro for fixes, and finish with a manual keyboard check.

In this step, get ready to:
  • Run automated accessibility scans on every page using @axe-core/playwright.
  • Fix all violations with Gemini Pro and verify the gold-and-black design system still works.
  • Complete a manual keyboard and screen reader check across the site.
Install axe-core and run automated scans

Automated accessibility scanners catch issues that are easy to miss by eye. Things like missing alt text, insufficient color contrast, and duplicate IDs.

What is axe-core?

axe-core is an open-source accessibility testing engine built by Deque Systems. It checks your rendered HTML against WCAG rules and reports every violation with a description and fix suggestion. The @axe-core/playwright package lets you run axe-core inside Playwright tests, so scans happen in a real browser against your actual rendered pages.

  • Switch to the feature/accessibility branch by running this command in the Antigravity terminal:
git checkout feature/accessibility
  • Install @axe-core/playwright as a dev dependency by running:
npm install -D @axe-core/playwright
  • Confirm the install succeeded by running:
ls node_modules/@axe-core/playwright

You should see files like dist and package.json listed in the output.

Seeing 'No such file or directory'?

Make sure you ran the install command from inside your pineapple-ai project folder. Run pwd to check your current directory.

help me fix my @axe-core/playwright installation

Now you need a script that visits every page and runs the axe-core scanner. This is a standalone Playwright script, not a test file.

  • Create a file called a11y-scan.ts in the root of your pineapple-ai folder by running:
touch a11y-scan.ts
  • Open a11y-scan.ts and paste the following code:
import { chromium } from 'playwright';
import AxeBuilder from '@axe-core/playwright';
import fs from 'fs';

// Pages to scan for accessibility violations
const pages = ['/', '/services', '/about', '/contact'];

async function runA11yScan() {
  const browser = await chromium.launch();
  const context = await browser.newContext();
  const allResults: Record<string, any> = {};

  for (const path of pages) {
    const page = await context.newPage();
    // Navigate to each page on the local dev server
    await page.goto(`http://localhost:3000${path}`);

    // Run axe-core with WCAG 2.1 A and AA rule tags
    const results = await new AxeBuilder({ page })
      .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
      .analyze();

    // Store violations keyed by page path
    allResults[path] = results.violations;
    console.log(`${path}: ${results.violations.length} violation(s)`);
    await page.close();
  }

  // Save the full report as a JSON file
  fs.writeFileSync('a11y-report.json', JSON.stringify(allResults, null, 2));
  console.log('Full report saved to a11y-report.json');

  await context.close();
  await browser.close();
}

runA11yScan();

What does this script do?

  • It launches a real Chromium browser using the Playwright library (not the test runner).
  • It loops through all four pages of the PineappleAI site.
  • For each page, it runs AxeBuilder with .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa']) to filter checks to WCAG 2.1 A and AA rules only.
  • It saves every violation to a11y-report.json so you have a permanent record of what needs fixing.
  • Start your dev server in one terminal by running:
npm run dev
  • Open a second terminal in Antigravity.
  • Run the accessibility scan by executing:
npx tsx a11y-scan.ts
  • Review the terminal output. You should see a line for each page showing the number of violations found.

What should I see?

Each page prints a line like /: 3 violation(s) or /contact: 0 violation(s). The exact numbers depend on your code. A file called a11y-report.json now exists in your project root with the full details.

Seeing 'AxeBuilder is not a constructor'?

This error usually means you have an older version of @axe-core/playwright with an ESM/CJS mismatch. Reinstall with the latest version by running npm install -D @axe-core/playwright@latest.

help me fix the AxeBuilder import error

Fix violations with Gemini Pro

You have a violation report. Now you need to fix every issue without breaking the gold-and-black design system. Gemini Pro is the right model here because each fix requires reasoning about downstream impact.

  • Open a11y-report.json and copy its full contents.
  • Open the Antigravity chat panel.
  • Make sure the model selector at the top of the chat is set to Gemini Pro.
  • Paste the following prompt into the chat, replacing the placeholder with your report contents:
Here is the axe-core violation report for PineappleAI:

[PASTE YOUR a11y-report.json CONTENTS HERE]

Fix every violation. For each fix, explain what WCAG criterion it addresses and why the fix is correct. Make sure fixes do not break the gold-and-black design system (gold #D4A843, black #0A0A0A, warm white #F5F0E8).

What are the most common violations?

  • Missing alt text on images. Every <img> needs descriptive alt text, or alt="" if it is purely decorative.
  • Insufficient color contrast. Body text needs a 4.5:1 contrast ratio. The gold #D4A843 on black #0A0A0A passes at approximately 12.6:1, but gold on warm white may not.
  • Missing landmark roles. Pages should have <main>, <nav>, and <footer> elements so screen readers can navigate by region.
  • Review each fix Gemini Pro suggests in the chat.
  • Approve the changes when they look correct.
  • Save all modified files.

Why Gemini Pro instead of Flash?

Accessibility fixes require reasoning about how a change in one component affects the rest of the page. For example, changing a heading level to fix a hierarchy violation could break the visual layout if the CSS targets heading tags. Pro handles this kind of cross-cutting reasoning better than Flash.

After applying fixes, re-run the scan to confirm they worked.

  • Make sure your dev server is still running.
  • Run the scan again by executing:
npx tsx a11y-scan.ts
  • Check the terminal output. Every page should now show 0 violation(s).

I see 0 violations on every page

Your automated accessibility audit is clean. Move on to the manual checks below.

I still have violations

  • Open a11y-report.json again and check which violations remain.
  • Paste the updated report into the Antigravity chat with Gemini Pro and ask it to fix the remaining issues.
  • Re-run npx tsx a11y-scan.ts after each round of fixes until you reach zero violations.

help me fix my remaining axe-core violations

Manual keyboard and screen reader checks

Automated scans catch about 30-50% of accessibility issues. The rest require a human to verify.

  • Open your site at http://localhost:3000 in your browser.
  • Press Tab repeatedly to move through every interactive element on the landing page.
  • Verify that every link, button, and form field receives a visible focus indicator.
  • Check that the tab order follows the visual layout from top to bottom, left to right.
  • Navigate to /services, /about, and /contact and repeat the Tab test on each page.

What am I looking for?

  • Focus indicators should be at least 2px thick with a 3:1 contrast ratio against the background (WCAG 2.4.11).
  • No element should be hidden behind a sticky header or footer when focused (WCAG 2.4.12).
  • Every interactive element should be reachable by Tab and activatable by Enter or Space.

If you have NVDA installed (a free screen reader for Windows), test the contact form with it.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type NVDA and press Enter to launch it.
  • Navigate to http://localhost:3000/contact in your browser.
  • Tab through each form field and listen for NVDA to announce the field label, required state, and any error messages.

Pro tip: NVDA is optional

Screen reader testing is valuable but not required to complete this step. If you do not have NVDA installed, the keyboard Tab test is sufficient. You can download NVDA for free from nvaccess.org if you want to try it.

If you found any issues during the manual check (focus indicators missing, tab order wrong, elements unreachable), fix them now.

  • Describe the issue to Gemini Pro in the Antigravity chat and ask it to fix the component.
  • Save all modified files.
  • Commit your accessibility fixes and merge into develop by running:
git add .
git commit -m "fix: resolve all axe-core a11y violations"
git checkout develop
git merge feature/accessibility

What do these commands do?

  • git add . stages all changed files for commit.
  • git commit -m saves a snapshot of your changes with a descriptive message.
  • git checkout develop switches to the integration branch.
  • git merge feature/accessibility brings your accessibility fixes into the develop branch.
  • Verify the merge succeeded by running:
git log --oneline -5

You should see your accessibility commit at the top of the log.

Seeing a merge conflict?

If another branch modified the same files, Git will flag a conflict. Open the conflicting file, look for the <<<<<<< and >>>>>>> markers, and keep the version with your accessibility fixes. Then run git add . and git commit to complete the merge.

help me resolve this Git merge conflict

Your site now passes automated WCAG 2.2 AA scans with zero violations and you have manually verified keyboard navigation. Next up, you will write a full Playwright E2E test suite that locks in these quality standards so they never regress.

Write E2E Tests with Playwright

Your site is accessible, your pages are built, and your contact form handles validation gracefully. But how do you prove all of that works every time someone changes the code?

In this step, you will build a Playwright E2E test suite that automatically navigates your site, fills out forms, and runs accessibility scans. Once these tests pass, anyone can clone your repo, run a single command, and verify the entire site works.

In this step, get ready to:
  • Set up Playwright with a webServer config that auto-starts your Next.js dev server.
  • Write E2E tests for page navigation, contact form submission, and form validation.
  • Write accessibility tests that run automated WCAG 2.2 AA scans on every page.
Set up Playwright with the webServer config

Playwright needs a running server to test against. Instead of making you start the dev server manually in a separate terminal, Playwright's webServer config option auto-starts your Next.js dev server before tests run.

  • Switch to the feature/e2e-tests branch by running this command:
git checkout feature/e2e-tests
  • Install Playwright by running:
npm init playwright@latest

The installer asks a series of prompts. Answer each one as follows.

  • Select TypeScript when asked for the language.
  • Enter tests for the tests folder name (or accept the default).
  • Enter false when asked to add a GitHub Actions workflow.
  • Enter true when asked to install Playwright browsers.

What does this install?

Playwright downloads browser binaries for Chromium, Firefox, and WebKit so your tests can run in real browsers. It also creates a playwright.config.ts file and a tests/ folder with a starter test.

The default config runs tests across three browsers. For this project, you only need Chromium, and you need the webServer option to auto-start your dev server.

  • Open playwright.config.ts in the Antigravity editor and replace its entire contents with the following configuration:
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  // Look for test files in the "tests" directory
  testDir: './tests',

  // Run tests one at a time for stability
  fullyParallel: false,

  // Fail the build on CI if test.only was left in
  forbidOnly: !!process.env.CI,

  // Retry failed tests once on CI, never locally
  retries: process.env.CI ? 2 : 0,

  // Use 1 worker for consistent results
  workers: 1,

  // Generate an HTML report after each run
  reporter: 'html',

  use: {
    // Base URL for all page.goto('/') calls
    baseURL: 'http://localhost:3000',

    // Capture a trace on the first retry of a failed test
    trace: 'on-first-retry',
  },

  // Only run tests in Chromium
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
  ],

  // Auto-start the Next.js dev server before tests run
  webServer: {
    command: 'npm run dev',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
  },
});

What does this config do?

  • webServer tells Playwright to run npm run dev automatically and wait for localhost:3000 to respond before running any tests.
  • reuseExistingServer skips starting a new server if one is already running locally. On CI it always starts fresh.
  • workers: 1 runs tests sequentially. This prevents flaky results from parallel tests competing for the same server.
  • baseURL means every page.goto('/') call automatically resolves to http://localhost:3000/.
  • Save playwright.config.ts.

Seeing an error during install?

If the browser download fails, your network or firewall may be blocking it. Try running the install again. If Playwright prompts that tests already exists, it will suggest e2e as the folder name instead. Accept e2e and update the testDir in your config to match.

Help me troubleshoot my Playwright installation

Write navigation and form tests

Playwright uses role-based locators like getByRole and getByLabel to find elements the same way a screen reader would. This means your tests double as accessibility checks. If a test cannot find a button by its role, the button is not accessible.

You will prompt Gemini Flash to generate these tests. Flash is the right model here because the test patterns are well-defined and the expected output is clear.

  • Delete the example test file that Playwright created. It is named example.spec.ts inside the tests/ folder.
  • Open the Antigravity chat panel and switch to Gemini Flash.
  • Paste this prompt into the chat:
Write Playwright E2E tests for PineappleAI. Create a file called tests/navigation.spec.ts with these tests:

Test 1: Navigate to each page (/, /services, /about, /contact) and verify the page loads with the correct heading.
Test 2: Fill out the contact form with valid data (Full Name, Email, Company Name, Service Interest dropdown, Message) and verify submission.
Test 3: Submit the contact form with empty required fields and verify error messages appear.

Rules:
- Use getByRole and getByLabel selectors only. No CSS class selectors.
- Import from '@playwright/test'.
- Use test.describe to group related tests.
- Each test should navigate to the page using page.goto('/').
  • Review the generated test file. Gemini Flash creates the file for you.

The generated tests should look similar to this structure. Your exact headings and field labels will match what you built in earlier steps.

  • Create tests/navigation.spec.ts with the generated code. Verify it follows this pattern:
import { test, expect } from '@playwright/test';

test.describe('Page Navigation', () => {
  test('landing page loads with correct heading', async ({ page }) => {
    await page.goto('/');

    // Verify the hero heading is visible
    await expect(
      page.getByRole('heading', { name: /clarity before action/i })
    ).toBeVisible();
  });

  test('services page loads with correct heading', async ({ page }) => {
    await page.goto('/services');

    // Verify the services page heading
    await expect(
      page.getByRole('heading', { name: /services/i })
    ).toBeVisible();
  });

  test('about page loads with correct heading', async ({ page }) => {
    await page.goto('/about');

    // Verify the about page heading
    await expect(
      page.getByRole('heading', { name: /about/i })
    ).toBeVisible();
  });

  test('contact page loads with correct heading', async ({ page }) => {
    await page.goto('/contact');

    // Verify the contact page heading
    await expect(
      page.getByRole('heading', { name: /contact/i })
    ).toBeVisible();
  });
});

Why getByRole instead of CSS selectors?

Playwright's getByRole locator finds elements by their ARIA role and accessible name. This mirrors how assistive technology perceives the page. If getByRole('heading', { name: 'Clarity Before Action' }) cannot find the element, it means a screen reader cannot find it either.

Similarly, getByLabel finds form inputs by their associated label text. If this locator fails, the input is missing a programmatic label, which is a WCAG violation.

Now add the contact form tests. These go in a separate describe block in the same file, or in a new file.

  • Create tests/contact-form.spec.ts with the form tests that Gemini Flash generated. Verify the tests follow this pattern:
import { test, expect } from '@playwright/test';

test.describe('Contact Form', () => {
  test('submits with valid data', async ({ page }) => {
    await page.goto('/contact');

    // Fill in all required fields using label-based locators
    await page.getByLabel(/full name/i).fill('Jane Smith');
    await page.getByLabel(/email/i).fill('jane@pineappleai.com');
    await page.getByLabel(/company/i).fill('PineappleAI');
    await page.getByLabel(/service interest/i).selectOption('Strategy');
    await page.getByLabel(/message/i).fill('I need help with AI strategy.');

    // Click the submit button
    await page.getByRole('button', { name: /submit/i }).click();

    // Verify a success message appears
    await expect(page.getByText(/thank you/i)).toBeVisible();
  });

  test('shows errors for empty required fields', async ({ page }) => {
    await page.goto('/contact');

    // Click submit without filling anything
    await page.getByRole('button', { name: /submit/i }).click();

    // Verify error messages appear for required fields
    await expect(page.getByText(/name is required/i)).toBeVisible();
    await expect(page.getByText(/email is required/i)).toBeVisible();
    await expect(page.getByText(/message is required/i)).toBeVisible();
  });
});

What does this code do?

  • getByLabel(/full name/i) finds the input by its associated label text. The /i flag makes the match case-insensitive.
  • selectOption('Strategy') picks a value from the service interest dropdown.
  • The validation test clicks submit on an empty form and checks that error messages appear. This verifies your aria-describedby error handling from Step 5 works correctly.

Pro tip: match your labels

The regex patterns in getByLabel must match the actual label text in your contact form. If Gemini Flash used different field names in Step 5, update the test patterns to match. For example, if your label says "Your Name" instead of "Full Name", change /full name/i to /your name/i.

  • Save both test files.
  • Run the navigation and form tests by running:
npx playwright test

Playwright auto-starts your Next.js dev server, opens a headless Chromium browser, and runs every test. You should see green checkmarks for each passing test in the terminal output.

Tests failing?

  • If you see "locator resolved to no elements," the heading text or label text in your test does not match what your pages actually render. Open localhost:3000 in your browser and check the exact text.
  • If the dev server fails to start, make sure port 3000 is not already in use. Close any other terminal running npm run dev.
  • Run npx playwright test --headed to watch the browser in real time and see exactly where the test fails.

Help me debug my failing Playwright tests

Write accessibility tests with axe-core

In Step 6, you ran axe-core scans manually. Now you will bake those scans into your Playwright test suite so they run automatically every time.

  • Install the @axe-core/playwright package by running:
npm install -D @axe-core/playwright

What is @axe-core/playwright?

This package injects the axe-core accessibility engine into a real browser page and runs a full scan. It integrates directly with Playwright's test runner, so you can write accessibility checks as regular test assertions.

  • Create tests/accessibility.spec.ts with the following accessibility tests:
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';

// Pages to scan for accessibility violations
const pages = [
  { name: 'Landing', path: '/' },
  { name: 'Services', path: '/services' },
  { name: 'About', path: '/about' },
  { name: 'Contact', path: '/contact' },
];

test.describe('Accessibility', () => {
  // Run a WCAG 2.2 AA scan on every page
  for (const { name, path } of pages) {
    test(`${name} page has no WCAG AA violations`, async ({ page }) => {
      await page.goto(path);

      // Run axe-core filtered to WCAG 2.x A and AA rules
      const results = await new AxeBuilder({ page })
        .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
        .analyze();

      // Assert zero violations
      expect(results.violations).toEqual([]);
    });
  }

  // Run a scoped scan on just the contact form
  test('contact form has no accessibility violations', async ({ page }) => {
    await page.goto('/contact');

    // Scope the scan to only the contact form element
    const results = await new AxeBuilder({ page })
      .include('#contact-form')
      .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
      .analyze();

    expect(results.violations).toEqual([]);
  });
});

What does this code do?

  • AxeBuilder({ page }) injects the axe-core engine into the current browser page.
  • .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa']) filters the scan to only WCAG 2.x level A and AA rules. This matches the WCAG 2.2 AA compliance target for PineappleAI.
  • .include('#contact-form') scopes the scan to just the contact form element. This catches form-specific issues like missing labels or broken aria-describedby links.
  • expect(results.violations).toEqual([]) asserts that axe-core found zero violations. If any violation exists, the test fails and prints the exact issue.

Pro tip: the #contact-form ID

The scoped scan uses .include('#contact-form'). Make sure your contact form component has id="contact-form" on the <form> element. If Gemini Flash used a different ID in Step 5, update the selector to match.

  • Save tests/accessibility.spec.ts.
  • Run the full test suite by running:
npx playwright test

You should see all navigation, form, and accessibility tests pass with green checkmarks.

Seeing accessibility violations?

If axe-core reports violations, the test output shows the exact rule ID, the affected element, and a description of the issue. Copy the violation output and paste it into the Antigravity chat with Gemini Pro. Ask Pro to fix each violation while preserving the gold-and-black design system.

If you see AxeBuilder is not a constructor, make sure you installed the latest version of @axe-core/playwright and that your import uses import AxeBuilder from '@axe-core/playwright' (default import, not destructured).

Help me fix my axe-core accessibility violations

  • Once all tests pass, commit your changes and merge into develop by running these commands:
git add .
git commit -m "Add Playwright E2E and accessibility tests"
git checkout develop
git merge feature/e2e-tests
  • Verify the merge completed by running:
git log --oneline -5

You should see your merge commit and the E2E test commit in the log.

Merge conflicts?

If Git reports conflicts during the merge, open the conflicting files in Antigravity and look for the <<<<<<< markers. Resolve each conflict by keeping the correct version, then run git add . and git commit to complete the merge.

Help me resolve my Git merge conflicts

Awesome, I've got everything!

Great. Double check you have saved all three test files in the tests/ folder.

I'd like to double check the full code

Here is the complete tests/accessibility.spec.ts file for comparison.

import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';

// Pages to scan for accessibility violations
const pages = [
  { name: 'Landing', path: '/' },
  { name: 'Services', path: '/services' },
  { name: 'About', path: '/about' },
  { name: 'Contact', path: '/contact' },
];

test.describe('Accessibility', () => {
  // Run a WCAG 2.2 AA scan on every page
  for (const { name, path } of pages) {
    test(`${name} page has no WCAG AA violations`, async ({ page }) => {
      await page.goto(path);

      // Run axe-core filtered to WCAG 2.x A and AA rules
      const results = await new AxeBuilder({ page })
        .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
        .analyze();

      // Assert zero violations
      expect(results.violations).toEqual([]);
    });
  }

  // Run a scoped scan on just the contact form
  test('contact form has no accessibility violations', async ({ page }) => {
    await page.goto('/contact');

    // Scope the scan to only the contact form element
    const results = await new AxeBuilder({ page })
      .include('#contact-form')
      .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
      .analyze();

    expect(results.violations).toEqual([]);
  });
});

Your test suite is now a repeatable quality gate. Anyone can clone your repo, run npx playwright test, and verify the entire site works and passes WCAG 2.2 AA compliance. Next up, you will merge everything into main and deploy to Vercel.

Merge All Branches and Deploy to Vercel

In the previous steps, you built every page, wrote a full test suite, and ran an accessibility audit. All of that work lives on the develop branch.

Now it is time to bring everything together. You will merge develop into main, deploy the site to Vercel, and run your Playwright tests against the live production URL.

In this step, get ready to:
  • Merge all feature branches into main and review the Git history.
  • Deploy the PineappleAI site to Vercel from your GitHub repository.
  • Run the full E2E test suite against the live deployment URL.
Merge develop into main

Your develop branch contains the merged work from all five feature branches. The final step in a professional Git workflow is promoting develop into main for production release.

  • Switch to the main branch by running this command:
git checkout main
  • Merge develop into main by running this command:
git merge develop

What does this do?

This takes all the commits from develop (which already includes every feature branch) and applies them to main. Since main has not diverged, Git performs a fast-forward merge.

  • Visualize your full branch and merge history by running this command:
git log --oneline --graph --all

You should see a text-based graph showing your five feature branches merging into develop, and develop merging into main.

What does this command show?

  • The --oneline flag shows each commit on a single line with its short hash and message.
  • The --graph flag draws a text-based graph connecting commits to their parents.
  • The --all flag includes every branch, not just the one you are on.

This visual proof demonstrates your professional branching workflow. You can see exactly where each feature branch was created and where it was merged back.

  • Push main to GitHub by running this command:
git push origin main

Merge conflict or push rejected?

If you see a merge conflict, it means main has commits that develop does not. Open the conflicting files, resolve the conflicts, then run git add . and git commit to complete the merge.

If the push is rejected, pull first with git pull origin main, resolve any conflicts, then push again.

Help me resolve a merge conflict between develop and main.

Deploy to Vercel

Vercel auto-detects Next.js projects and handles the build configuration for you. You will connect your GitHub repository so that every future push to main triggers an automatic production deployment.

  • Open your browser and go to vercel.com.
  • Sign in with your GitHub account. If this is your first time, Vercel will ask you to authorize the GitHub integration.
  • Click Add New... in the top-right area of the dashboard.
  • Select Project.
  • Find your pineapple-ai repository in the list and click Import.

What if I don't see my repository?

If your repository does not appear, click Adjust GitHub App Permissions at the bottom of the repository list. Grant Vercel access to the pineapple-ai repository, then return to the import page.

  • On the Configure Project screen, verify that Vercel has auto-detected the framework as Next.js.
  • Leave all other settings at their defaults (root directory ./, build command auto-detected, output directory auto-detected).
  • Click Deploy.

Vercel streams the build output in real time. The build typically completes in 30 to 60 seconds.

  • Once the build finishes, Vercel shows a Congratulations screen with your live production URL (e.g. https://pineapple-ai.vercel.app).
  • Click Visit to open your live site in a new tab.
  • Click through each page (landing, services, about, contact) to confirm everything renders correctly.

Why Vercel for this project?

Vercel is built by the Next.js team and is optimized for Next.js deployments. It provides zero-configuration builds, a global CDN, and automatic preview deployments for every Git push. The free hobby tier has no cost for personal projects.

Build failed on Vercel?

Check the build logs in the Vercel dashboard for the specific error. Common causes include missing dependencies, TypeScript type errors, or ESLint violations that were not caught locally.

Run npm run build locally in your terminal first. If the local build passes, the Vercel build should pass too.

Help me debug my Vercel build failure.

Run E2E tests against the live site

Your Playwright tests have been running against localhost:3000 so far. Running them against the live Vercel URL is the final quality gate. It proves your site works in a real production environment.

You will override the baseURL in your Playwright config using an environment variable so your tests point to the live deployment.

  • Open playwright.config.ts in the Antigravity editor.
  • Find the use section and update the baseURL line to read from an environment variable, so the line now looks like this:
// Use the BASE_URL environment variable if set, otherwise fall back to localhost
baseURL: process.env.BASE_URL || 'http://localhost:3000',

What does this change do?

When BASE_URL is set, Playwright sends all requests to that URL instead of localhost:3000. When it is not set, tests still work locally against the dev server. This pattern lets you test against any environment without editing the config file.

  • Save playwright.config.ts.
  • Copy your Vercel deployment URL from the Vercel dashboard (e.g. https://pineapple-ai.vercel.app).

Now run the full test suite against your live site. The command differs slightly between macOS and Windows.

macOS

  • Run your Playwright tests against the live URL by running this command:
BASE_URL=[[VERCEL_URL="your Vercel deployment URL (e.g. https://pineapple-ai.vercel.app)"]] npx playwright test

Windows

  • Set the environment variable and run your Playwright tests by running these commands:
$env:BASE_URL="[[VERCEL_URL="your Vercel deployment URL (e.g. https://pineapple-ai.vercel.app)"]]"; npx playwright test

All navigation, form, and accessibility tests should pass. This confirms your site is WCAG 2.2 AA compliant in production.

What should I see?

Playwright outputs a summary showing the number of tests that passed, failed, and were skipped. You should see all tests passing with green checkmarks. If any test fails, the output includes the test name and the specific assertion that failed.

Tests failing against the live URL?

  • Make sure you copied the full Vercel URL including https://.
  • Check that the Vercel deployment finished successfully before running tests. A deployment still in progress returns incomplete pages.
  • If you see timeout errors, the live site may be cold-starting. Run the tests a second time.

Help me debug Playwright test failures against my live Vercel URL.

  • Commit the updated playwright.config.ts and push to GitHub by running these commands:
git add playwright.config.ts
git commit -m "feat: support BASE_URL env var for production testing"
git push origin main

Vercel automatically detects the push and triggers a new deployment. Your site stays up to date with every push to main.

Secret mission

Case Studies Page with Animations and Dark/Light Mode

Your PineappleAI site looks professional. But right now, every visitor sees the same experience. What if you could add a case studies page that showcases real results, with animated cards that feel alive when you hover over them? And what if visitors could switch between a dark gold-on-black theme and a light gold-on-white theme with a single click? This secret mission adds the polish that turns a good portfolio piece into an impressive one.

Before you go

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs on the Vercel free hobby tier and uses local files, so there are no ongoing costs.

Resources you used:

  • Local pineapple-ai Next.js project folder.
  • GitHub repository for pineapple-ai.
  • Vercel deployment (free hobby tier).
  • Antigravity IDE project and workspaces.
  • Playwright test configuration and browser binaries.

Keep everything running

No action needed. Choose this if you are still actively building or want to keep your PineappleAI site live as a working demo.

  • Your Vercel deployment stays live at your project URL for free.
  • Your GitHub repository remains available for future updates.
  • Any push to main will trigger an automatic redeployment on Vercel.

Pause - I'll come back to this later

Free up local disk space while keeping your cloud resources intact. You can pick up right where you left off later.

  • Your Vercel deployment and GitHub repository cost nothing to keep running. Leave them as they are.
  • To free up local space, you can delete the Playwright browser binaries by running:
npx playwright uninstall --all
  • When you return, clone your repo from GitHub and run npm install to restore your dependencies.

Delete - I don't want to use this again

Remove all project resources and start fresh. This permanently deletes your deployment and repository.

  • Go to your Vercel dashboard at vercel.com.
  • Select your pineapple-ai project, then open Settings.
  • Scroll to the bottom and click Delete Project.
  • To delete the GitHub repository, go to your repo page on GitHub.
  • Open Settings, scroll to the Danger Zone, and click Delete this repository.
  • Delete the local pineapple-ai folder from your computer.
  • Remove Playwright browser binaries by running:
npx playwright uninstall --all

Mission accomplished

That's a Wrap!

Nice work! You just shipped a real startup website from scratch using 5 parallel AI agents. PineappleAI is live on Vercel, fully accessible, and backed by automated tests that anyone can run to verify quality.

Here's what you pulled off:

  • Built and deployed a multi-page Next.js 16 website with TypeScript, Tailwind CSS, and a gold-and-black design system, orchestrated end-to-end through Antigravity IDE using natural language prompts with Gemini Pro and Gemini Flash.
  • Made the entire site WCAG 2.2 AA accessible, verified by automated @axe-core/playwright scans with zero violations and manual keyboard navigation checks.
  • Wrote Playwright E2E tests covering navigation, form submission, form validation, and accessibility. Then ran them against your live Vercel deployment as a production quality gate.
  • Completed the Secret Mission by adding a case studies page with animated card transitions and an accessible dark/light mode toggle.

Ready to quiz yourself?