idle-web-developer
# Website Builder
Autonomously build and ship a polished web app.
The idea and design are determined automatically using a **dice-based system**.
---
# Workflow
## 0. First-Time Setup (Onboarding Wizard)
Before doing anything else, check whether the skill has been configured.
**Config file location:**
```
~/.openclaw/workspace/skills/idle-web-developer/.skill-config
```
If `.skill-config` **does not exist** (or the user explicitly asks to re-run setup with `--setup`), run the **interactive onboarding wizard** below.
---
### Onboarding Wizard
Ask the user each question in order. Collect the answers, then write them all to `.skill-config` at the end. Present each question clearly — one at a time, conversationally.
---
#### Step A — Vercel Token (required)
> "To deploy your sites, I need your Vercel token.
> You can find it at: https://vercel.com/account/tokens
> What is your Vercel token?"
Save as `VERCEL_TOKEN`.
---
#### Step B — Google Analytics (optional)
> "Would you like to enable Google Analytics on your sites? This is optional — it lets you track page views and user behaviour.
> (yes / no)"
- If **no** → skip to Step C. Leave `GA_MEASUREMENT_ID` and `GOOGLE_APPLICATION_CREDENTIALS` blank.
- If **yes** → ask:
> "What is your Google Application Credentials JSON file path?
> (e.g. /home/you/.config/gcloud/service-account.json)"
Save as `GOOGLE_APPLICATION_CREDENTIALS`.
> "What is your GA4 Measurement ID?
> (e.g. G-XXXXXXXXXX — found in Google Analytics → Admin → Data Streams)"
Save as `GA_MEASUREMENT_ID`.
---
#### Step C — Supabase Waitlist (optional)
> "Every site includes a 'Join the Waitlist' section so visitors can sign up.
> Would you like to connect this to Supabase so emails are actually saved? This is optional — the section always appears, but without credentials submissions won't be stored.
> (yes / no)"
- If **no** → skip. Leave `SUPABASE_URL` and `SUPABASE_ANON_KEY` blank. The waitlist UI will still be included on every site.
- If **yes** → ask:
> "What is your Supabase project URL?
> (e.g. https://abcdefgh.supabase.co)"
Save as `SUPABASE_URL`.
> "What is your Supabase anon/public key?
> (found in Supabase → Project Settings → API → Project API Keys)"
Save as `SUPABASE_ANON_KEY`.
---
#### Saving the Config
After collecting all answers, write the config file:
```bash
CONFIG="~/.openclaw/workspace/skills/idle-web-developer/.skill-config"
cat > "$CONFIG" <<EOF
VERCEL_TOKEN="${VERCEL_TOKEN}"
GOOGLE_APPLICATION_CREDENTIALS="${GOOGLE_APPLICATION_CREDENTIALS}"
GA_MEASUREMENT_ID="${GA_MEASUREMENT_ID}"
SUPABASE_URL="${SUPABASE_URL}"
SUPABASE_ANON_KEY="${SUPABASE_ANON_KEY}"
EOF
```
Confirm to the user:
> "✅ Setup complete! Your config has been saved.
> You can re-run setup anytime by saying 'set up the website builder' or passing `--setup` to the script."
Then proceed with the rest of the workflow.
---
### If `.skill-config` already exists
Load it and continue. No questions needed.
```bash
source ~/.openclaw/workspace/skills/idle-web-developer/.skill-config
```
---
## 1. Check for Vercel Token
Verify that deployment is possible.
- Confirm `$VERCEL_TOKEN` is set (from config or environment).
- If not available: stop and inform the user to run setup.
Never deploy without authentication.
---
## 2. 🎲 Roll 1 — What to Build
Generate a number from **1–5**:
```bash
python3 -c "import random; print(random.randint(1,5))"
```
| Roll | What to build |
|-----|---------------|
| 1, 2 | 🤖 **AI Tool** |
| 3 | 🏗️ **OpenClaw Web Tool** |
| 4, 5 | 💰 **Niche Clone** |
---
### If Roll = 1 or 2 → AI Tool
Research current AI opportunities.
Search:
```
web_search "trending AI tools 2026"
```
Find something **original and useful** that can realistically be built as a web app.
Examples:
- AI workflow generators
- AI niche productivity tools
- AI dev utilities
- AI writing or research helpers
The result must be **practical and usable**, not just a landing page.
---
### If Roll = 3 → OpenClaw Tool
Research inspiration from the OpenClaw project.
Run:
```
gh issue list -R openclaw/openclaw --limit 20
```
Then build something that **extends or promotes the OpenClaw ecosystem**, such as:
- Interactive docs
- Prompt playground
- Demo tool
- Developer utility
- Visual onboarding experience
The result should help **developers understand or use OpenClaw faster**.
---
### If Roll = 4 or 5 → Niche Clone
**Do not use a predefined list.** Research what's actually making money right now.
Run multiple searches across these sources:
```
web_search "most profitable micro SaaS 2025 site:starterstory.com"
web_search "bootstrapped SaaS revenue 2025 site:starterstory.com"
web_search "fastest growing AI SaaS startups 2025 site:crunchbase.com"
web_search "profitable niche SaaS ideas 2025"
```
Look for:
- **StarterStory.com** — real founders sharing actual MRR, growth, and what's working
- **Crunchbase** — recently funded startups (seed/Series A) in AI/SaaS — funding = validated demand
- **Indie Hackers** — $10k–$100k MRR solo/small-team products
- **Product Hunt** — trending tools with strong upvote momentum
**Selection criteria:**
1. The product has **demonstrated revenue or traction** (not just hype)
2. A clear **underserved niche** exists (industry, role, geography, workflow)
3. The niche version can be **meaningfully differentiated** — not just a rebrand
**Then:**
1. Pick the most promising product with clear revenue signal
2. Identify a **specific underserved niche** — be precise:
- ❌ "small businesses"
- ✅ "independent veterinary clinics"
3. Build a **focused version targeting that niche exactly**
The **niche is the moat** — the narrower, the better.
**Example:**
Research finds → Otter.ai ($50M ARR, meeting transcription)
Instead of:
> AI meeting transcription
Build:
> AI meeting transcription **for real estate showings** — auto-generates buyer feedback summaries and follow-up emails for agents
---
## 3. 🎲 Roll 2 — Color Palette
Roll **two more times**.
### Primary Color
```bash
python3 -c "import random; print(random.randint(1,6))"
```
| Roll | Color | Hex | Vibe |
|-----|------|------|------|
| 1 | Electric Blue | #2563EB | Trustworthy, tech, precise |
| 2 | Deep Violet | #7C3AED | Creative, premium, mysterious |
| 3 | Emerald | #059669 | Growth, calm, fresh |
| 4 | Crimson Red | #DC2626 | Bold, urgent, powerful |
| 5 | Amber | #D97706 | Confident, warm, energetic |
| 6 | Cyan / Teal | #0891B2 | Clean, modern, sharp |
---
### Background Mode
```bash
python3 -c "import random; print(random.randint(1,6))"
```
| Roll | Mode | Style |
|-----|------|-------|
| 1, 2, 3 | ☀️ Light | White or `#FAFAFA` base, dark text |
| 4, 5, 6 | 🌙 Dark | `#070B14` or deep neutral base, light text |
Pair the primary with **1–2 derived accent colors** and a neutral set.
The palette should feel **curated and intentional** — never generic.
---
## 4. 🔨 Building Web Apps
Before building, check previous builds:
```
memory/side-hustle-builds.md
```
Do **not duplicate existing ideas**.
---
### Stack
- **React + TypeScript + Vite**
- **Tailwind CSS** (via npm)
- **Framer Motion** for animations
- **lucide-react** for icons
- **Pexels** for stock photos (link only, never download)
---
### Design Standards (non-negotiable)
- Full-viewport animated **Hero** — bold headline, subheadline, primary CTA
- Fixed **Nav** with smooth scroll and CTA button
- **Features / How It Works** with icons or a 3-step flow
- **Social Proof** — testimonials, logos, or user counts
- **Waitlist Signup Section** — **ALWAYS included, no exceptions** (see below)
- **CTA section** mid-page + bottom — urgent, outcome-focused copy
- **Footer** — links, legal, socials
- Optional: **Demo section** (interactive product simulation), **Pricing**, **FAQ**
- Apple/Stripe level polish — every page a bespoke masterpiece
- 8px grid, fluid responsive, mobile-first
- Scroll-triggered animations, hover states, microinteractions
- Benefit-driven copy — outcomes not features
---
### ✉️ Waitlist Signup Section (Required — Always)
**Every single site must include a waitlist signup section.** This is non-negotiable, regardless of whether Supabase credentials are configured.
The section should be visually prominent — a full-width band, typically placed between the main CTA and the footer. It should:
- Have a compelling headline (e.g. "Be the first to know", "Get early access", "Join the waitlist")
- Have a subheadline matching the product's value proposition
- Have an email input + submit button
- Show a success state after submission
**Placement:** Between the mid-page CTA and the Footer (or at the bottom of the hero if the page is short).
**Component file:** `src/components/Waitlist.tsx`
---
### Project Structure
```
apps/<app-name>/
package.json
vite.config.ts
tailwind.config.ts
tsconfig.json
index.html
src/
main.tsx
App.tsx
components/
Nav.tsx
Hero.tsx
Features.tsx
Waitlist.tsx ← always present
Testimonials.tsx
CTA.tsx
Footer.tsx
(+ Demo.tsx, Pricing.tsx, FAQ.tsx as needed)
```
---
#### Wiring: With Supabase Credentials
If `$SUPABASE_URL` and `$SUPABASE_ANON_KEY` are set, the form should POST to Supabase.
Assume the table is named `waitlist` with columns `email`, `app_name`, and `app_url`. The agent should note in the output that the user may need to create this table in Supabase if it doesn't exist.
SQL to create the table:
```sql
create table if not exists waitlist (
id uuid default gen_random_uuid() primary key,
email text not null unique,
app_name text not null,
app_url text,
created_at timestamptz default now()
);
```
The fetch call in the component — **always include `app_name` and `app_url`**:
```typescript
const res = await fetch(`${SUPABASE_URL}/rest/v1/waitlist`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': SUPABASE_ANON_KEY,
'Authorization': `Bearer ${SUPABASE_ANON_KEY}`,
'Prefer': 'return=minimal',
},
body: JSON.stringify({ email, app_name: APP_NAME, app_url: window.location.origin }),
});
```
`APP_NAME` should be a constant at the top of the Waitlist component, set to the product name (e.g. `const APP_NAME = 'ErrorLens'`).
Inject the values at build time via Vite env vars — never hardcode in source:
In `vite.config.ts`, expose:
```typescript
define: {
__SUPABASE_URL__: JSON.stringify(process.env.SUPABASE_URL ?? ''),
__SUPABASE_ANON_KEY__: JSON.stringify(process.env.SUPABASE_ANON_KEY ?? ''),
}
```
Use `__SUPABASE_URL__` and `__SUPABASE_ANON_KEY__` in the component.
---
#### Wiring: Without Supabase Credentials
If credentials are absent, still include the full waitlist UI. The form should render and look identical, but on submit show:
> "✅ Thanks! We'll be in touch soon."
(The submission does nothing server-side — it's a polished placeholder.)
Log a note in build output:
```
⚠️ Waitlist is UI-only — set SUPABASE_URL and SUPABASE_ANON_KEY to enable real sign-ups
```
---
### Analytics (Optional)
Check for both conditions **before** adding any analytics code:
1. `$GA_MEASUREMENT_ID` is set
2. `$GOOGLE_APPLICATION_CREDENTIALS` is set or the file exists
**If either is missing → skip analytics entirely. Do not add any tracking code.**
Only when both are present, add the following to `index.html` before `</body>`, replacing `<MEASUREMENT_ID>` with the actual value:
```html
<script async src="https://www.googletagmanager.com/gtag/js?id=<MEASUREMENT_ID>"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '<MEASUREMENT_ID>', { page_title: document.title, page_location: location.href });
gtag('event', 'page_view', { product_id: location.hostname });
</script>
```
Check at build time:
```bash
if [ -n "$GA_MEASUREMENT_ID" ] && ([ -n "$GOOGLE_APPLICATION_CREDENTIALS" ] || [ -f "$HOME/.openclaw/workspace/secrets/ga-service-account.json" ]); then
echo "✅ Analytics enabled — Measurement ID: $GA_MEASUREMENT_ID"
else
echo "⚠️ Analytics skipped — set GA_MEASUREMENT_ID and GOOGLE_APPLICATION_CREDENTIALS to enable"
fi
```
---
## 5. Deploy
**Important:** Deploy the pre-built `dist/` folder, NOT the project root. Vercel rebuilds from source on their servers where your env vars don't exist — Supabase credentials and analytics would be baked in as empty strings. Deploying `dist/` sends the already-built static files with credentials properly baked in.
```bash
cd apps/<app-name>
# Load credentials from config
source ~/.openclaw/workspace/skills/idle-web-developer/.skill-config
# Export for Vite build (bakes values into the JS bundle locally)
export SUPABASE_URL SUPABASE_ANON_KEY GA_MEASUREMENT_ID GOOGLE_APPLICATION_CREDENTIALS
npm install
npm run build
# Tell Vercel: skip server-side build, serve static files as-is
cat > dist/vercel.json <<'EOF'
{ "buildCommand": "", "outputDirectory": "." }
EOF
# Deploy the LOCAL build output — NOT the source
vercel deploy dist/ --prod --yes --token "$VERCEL_TOKEN"
```
**Why this works:** `npm run build` runs locally where env vars are set, so Vite's `define` bakes Supabase/GA values into the JS bundle. The `vercel.json` in `dist/` tells Vercel to skip rebuilding and serve the files directly.
---
## 6. After Every Build
- Add to `memory/side-hustle-builds.md` (name, URL or path, idea, date)
- Log in `memory/YYYY-MM-DD.md`
- Update `lastBuild` in `memory/heartbeat-state.json`
---
## 7. After Deployment Return
- **Deployed URL**
- **Dice roll results**
- **The generated idea**
- **How the product works**
- **Why it could succeed**
- **Color palette used**
- **Analytics:** enabled or skipped (state which env var was missing if skipped)
- **Waitlist:** confirm the section is included; state whether Supabase is wired or placeholder mode. If wired, remind the user to create the `waitlist` table in Supabase if not already done. The table must include `app_name text not null` and `app_url text` columns.
---
## Commands
```bash
# Normal build + deploy
bash skills/idle-web-developer/scripts/build-and-deploy.sh --name "my-auto-saas"
# Re-run onboarding setup
bash skills/idle-web-developer/scripts/build-and-deploy.sh --setup
# Skip deploy (scaffold only)
bash skills/idle-web-developer/scripts/build-and-deploy.sh --name "my-site" --skip-deploy
```
---
## Notes
- **Onboarding runs once** — after setup, the config is reused automatically.
- **Re-setup:** say "set up the website builder" or pass `--setup` to the script.
- **Waitlist section is mandatory** on every site — no exceptions.
- Never hardcode secrets or tokens into source files.
- Never embed the Supabase anon key directly in JSX — always use Vite define injection.
- Prefer polished dark UI defaults unless user asks otherwise.
- For larger projects, scaffold first, then iterate in follow-up turns.
See `references/workflow.md` for detailed operational guidance.
标签
skill
ai