← Tool Factory

Generate a Vertical SaaS
from Any Niche

Describe your industry or niche and get a complete SaaS business plan with starter code: SWOT analysis, financial projections, pitch deck, 90-day launch roadmap, pricing strategy, risk assessment, landing page, and a downloadable Next.js + Tailwind starter project. All free.

Star on GitHub CLI Tool
{''}
New Full Project Code Generation

Now generates a complete, deployable Next.js project

Not just a business plan — get a full working codebase with niche-specific data models, dashboard, CRUD pages, API routes, Supabase database schema, Dockerfile, and TypeScript types. Ready to npm run dev.

Dental Restaurant Fitness Salon Real Estate Legal + any niche
python3 main.py project dental --name DentaFlow --output ./my-dental-app

Describe Your SaaS Idea

Use from the Command Line

Zero dependencies. No API keys. Runs offline. Works with any niche.

$ npx ai-saas-gen "pet grooming"
# Output as JSON for scripting
$ npx ai-saas-gen "dental" --json
# Save all outputs (plan, landing page, deploy guide)
$ npx ai-saas-gen "fitness" -o my-fitness-saas/
# List all 25 built-in industries
$ npx ai-saas-gen --list
View on GitHub API Docs

Get notified about new features

We add new verticals, AI enhancements, and export options regularly. No spam, unsubscribe anytime.

`; } function generateDeployGuide(business, techStack, budget) { const name = business.name.toLowerCase(); if (budget === "bootstrap") { return `# Deploy ${business.name} — Bootstrap Guide ## 1. Project Setup \`\`\`bash npx create-react-app ${name}-app cd ${name}-app npm install firebase tailwindcss \`\`\` ## 2. Firebase Setup \`\`\`bash npm install -g firebase-tools firebase login firebase init hosting firebase init firestore firebase init auth \`\`\` ## 3. Environment Variables \`\`\`env REACT_APP_FIREBASE_API_KEY=your_key REACT_APP_FIREBASE_AUTH_DOMAIN=${name}.firebaseapp.com REACT_APP_FIREBASE_PROJECT_ID=${name}-prod REACT_APP_STRIPE_KEY=pk_live_xxx \`\`\` ## 4. Deploy \`\`\`bash npm run build firebase deploy \`\`\` ## 5. Custom Domain \`\`\`bash firebase hosting:channel:deploy preview # Then add custom domain in Firebase Console \`\`\` ## Estimated Cost: $0-25/month (Firebase Spark/Blaze free tier) `; } return `# Deploy ${business.name} — ${budget.charAt(0).toUpperCase()+budget.slice(1)} Guide ## 1. Project Setup \`\`\`bash npx create-next-app@latest ${name}-app --typescript --tailwind --app cd ${name}-app npm install @supabase/supabase-js stripe next-auth \`\`\` ## 2. Database (Supabase) \`\`\`bash npx supabase init npx supabase db push \`\`\` ## 3. Deploy to Vercel \`\`\`bash npm install -g vercel vercel --prod \`\`\` ## 4. Environment Variables (Vercel Dashboard) \`\`\` DATABASE_URL=postgresql://... NEXTAUTH_SECRET=your_secret STRIPE_SECRET_KEY=sk_live_xxx NEXT_PUBLIC_STRIPE_KEY=pk_live_xxx \`\`\` ## 5. CI/CD (GitHub Actions) \`\`\`yaml name: Deploy on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: amondnet/vercel-action@v25 with: vercel-token: \${{ secrets.VERCEL_TOKEN }} vercel-org-id: \${{ secrets.ORG_ID }} vercel-project-id: \${{ secrets.PROJECT_ID }} vercel-args: '--prod' \`\`\` ## Estimated Monthly Cost - Vercel Pro: $20/month - Supabase Pro: $25/month - Stripe: 2.9% + $0.30 per transaction - Domain: $12/year - Total: ~$50/month + transaction fees `; } // ===== GENERATION FLOW ===== // ===== 90-DAY LAUNCH ROADMAP ENGINE ===== function generateRoadmap(business, features, budget, timeline) { const phase1Features = features.filter(f => f.phase === 1).slice(0, 5); const niche = business.niche; const name = business.name; const budgetWeeks = { bootstrap: { validate: 2, build: 4, alpha: 2, prep: 2, launch: 1, grow: 2 }, seed: { validate: 1, build: 3, alpha: 2, prep: 2, launch: 1, grow: 4 }, funded: { validate: 1, build: 2, alpha: 1, prep: 2, launch: 1, grow: 6 }, enterprise: { validate: 1, build: 2, alpha: 1, prep: 2, launch: 1, grow: 6 } }; const w = budgetWeeks[budget] || budgetWeeks.seed; const phases = [ { name: "Validate", color: "var(--purple)", weeks: [ { week: 1, title: "Market Validation", tasks: [ `Create a landing page for ${name} with email capture (use generated HTML)`, `Post in 3 ${niche} communities/forums to gauge interest`, `Reach out to 10 potential ${niche} customers for 15-min interviews`, `Set up analytics (Google Analytics, Hotjar) to track landing page`, `Create ${name} social accounts (Twitter/X, LinkedIn)` ]}, ...(w.validate >= 2 ? [{ week: 2, title: "Demand Signals", tasks: [ `Analyze landing page conversion rate (target: 5%+ email signup)`, `Synthesize customer interview insights — top 3 pain points`, `Build a simple Typeform/Google Form survey and share in ${niche} groups`, `Research competitors: sign up for ${business.competitors.slice(0,2).join(' and ')} free trials`, `Define MVP scope based on validated pain points` ]}] : []) ] }, { name: "Build MVP", color: "var(--blue)", weeks: (() => { const buildWeeks = []; const weekStart = w.validate + 1; buildWeeks.push({ week: weekStart, title: "Foundation & Core Setup", tasks: [ `Set up project repo with CI/CD (GitHub Actions)`, `Configure auth system (${budget === 'bootstrap' ? 'Firebase Auth' : 'NextAuth.js / Clerk'})`, `Set up database schema for ${phase1Features[0]?.name || 'core feature'}`, `Build shared UI components (nav, sidebar, dashboard shell)`, `Set up staging environment` ]}); buildWeeks.push({ week: weekStart + 1, title: "Core Features Sprint 1", tasks: [ `Implement ${phase1Features[0]?.name || 'primary feature'} — the #1 must-have`, `Build ${phase1Features[1]?.name || 'secondary feature'} integration`, `Create basic ${niche} data models and API endpoints`, `Write integration tests for core flows`, `Set up error tracking (Sentry)` ]}); if (w.build >= 3) { buildWeeks.push({ week: weekStart + 2, title: "Core Features Sprint 2", tasks: [ `Implement ${phase1Features[2]?.name || 'third feature'}`, `Build ${phase1Features[3]?.name || 'payment processing'} module`, `Create dashboard with key ${niche} metrics`, `Add email notifications (transactional emails)`, `Mobile responsive pass on all screens` ]}); } if (w.build >= 4) { buildWeeks.push({ week: weekStart + 3, title: "Polish & Integration", tasks: [ `Implement ${phase1Features[4]?.name || 'analytics'}`, `Build onboarding flow (first-run wizard)`, `Add Stripe payment integration for subscriptions`, `Performance optimization pass (aim for <2s load time)`, `Security audit: check OWASP top 10` ]}); } return buildWeeks; })() }, { name: "Alpha Test", color: "var(--green)", weeks: (() => { const alphaStart = w.validate + w.build + 1; const alphaWeeks = [{ week: alphaStart, title: "Private Alpha", tasks: [ `Invite 10-20 people from validation interviews as alpha testers`, `Create a feedback channel (Slack/Discord group for ${name} beta)`, `Set up session recording (Hotjar / FullStory) to watch real usage`, `Fix critical bugs reported in first 48 hours`, `Daily check: NPS score and feature requests` ]}]; if (w.alpha >= 2) { alphaWeeks.push({ week: alphaStart + 1, title: "Iterate on Feedback", tasks: [ `Prioritize top 3 feature requests from alpha users`, `Fix UX friction points identified via session recordings`, `A/B test onboarding flow (short vs guided)`, `Collect 3-5 testimonials from happy alpha users`, `Prepare beta launch checklist` ]}); } return alphaWeeks; })() }, { name: "Launch Prep", color: "var(--orange)", weeks: (() => { const prepStart = w.validate + w.build + w.alpha + 1; const prepWeeks = [{ week: prepStart, title: "Content & Positioning", tasks: [ `Write Product Hunt listing: tagline, description, 4 screenshots`, `Create 3 blog posts: "${name} vs ${business.competitors[0]}", "Why ${niche} needs modern software", launch story`, `Design OG images and social media graphics`, `Draft launch day tweet thread / LinkedIn post`, `Prepare press kit: logo, screenshots, founder bio` ]}]; if (w.prep >= 2) { prepWeeks.push({ week: prepStart + 1, title: "Distribution Setup", tasks: [ `Schedule Product Hunt launch (Tuesday-Thursday, ask 5 friends to be Hunters)`, `Write "Show HN" post for Hacker News`, `Submit to BetaList, DevHunt, and 3 ${niche}-specific directories`, `Set up referral program (give 1 month free for each referral)`, `Pre-write 5 Reddit posts for r/SaaS, r/startups, niche subreddits` ]}); } return prepWeeks; })() }, { name: "Launch", color: "var(--red)", weeks: (() => { const launchWeek = w.validate + w.build + w.alpha + w.prep + 1; return [{ week: launchWeek, title: "Launch Week", tasks: [ `Launch on Product Hunt at 12:01 AM PT — engage with every comment`, `Post "Show HN" on Hacker News`, `Publish all pre-written Reddit and social media posts`, `Send launch email to all waitlist subscribers`, `Monitor: uptime, error rates, support tickets, conversion rate` ]}]; })() }, { name: "Growth", color: "var(--cyan)", weeks: (() => { const growStart = w.validate + w.build + w.alpha + w.prep + w.launch + 1; const growWeeks = [{ week: growStart, title: "Post-Launch Momentum", tasks: [ `Analyze launch metrics: signups, conversions, traffic sources`, `Respond to all Product Hunt and HN comments within 2 hours`, `Collect and publish customer testimonials on landing page`, `Set up automated drip email sequence (7-day trial nurture)`, `Start content marketing: publish 1 SEO blog post per week targeting "${niche} software" keywords` ]}]; if (w.grow >= 3) { growWeeks.push({ week: growStart + 1, title: "Retention & Conversion", tasks: [ `Analyze churn: interview every churned user`, `Implement in-app NPS survey (trigger at day 7 and day 30)`, `Build feature usage dashboard — find unused features`, `Optimize pricing page: add annual discount (save 20%)`, `Start outbound: personalized emails to ${niche} businesses from Google Maps` ]}); } if (w.grow >= 4) { growWeeks.push({ week: growStart + 2, title: "Scale Channels", tasks: [ `Start Google Ads campaign targeting "${niche} software" (budget: $500/mo)`, `Launch affiliate/partner program`, `Create comparison pages: "${name} vs ${business.competitors[0]}", "${name} vs ${business.competitors[1]}"`, `Guest post on 2 ${niche} industry blogs`, `Set up automated webinar / product demo` ]}); growWeeks.push({ week: growStart + 3, title: "Optimize & Expand", tasks: [ `Review unit economics: LTV, CAC, LTV:CAC ratio (target 3:1+)`, `Plan Phase 2 features based on customer requests`, `Hire first team member (support / content / engineering)`, `Set up customer advisory board (5-10 power users)`, `Plan next quarter OKRs based on first 90 days data` ]}); } return growWeeks; })() } ]; return { phases, totalWeeks: w.validate + w.build + w.alpha + w.prep + w.launch + w.grow, freeWeeks: 4 }; } // ===== SWOT ANALYSIS ENGINE ===== function generateSWOT(business, features, pricing, competitive) { const phase1Count = features.filter(f=>f.phase===1).length; const mustCount = features.filter(f=>f.priority==='must').length; const compCount = business.competitors.length; const strengths = [ `Focused on underserved ${business.niche} vertical with ${business.tam} TAM`, `${mustCount} must-have features addressing core pain: ${business.pain.split(',')[0]}`, phase1Count <= 7 ? 'Lean MVP scope enables fast time-to-market' : 'Comprehensive MVP covers key workflows', `Modern tech stack reduces infrastructure costs`, business.moat[0] || 'First-mover advantage in niche vertical' ]; const weaknesses = [ 'New entrant with no brand recognition or existing user base', 'Limited initial feature set vs established competitors', compCount > 0 ? `Competing against funded players like ${business.competitors[0]}` : 'Unproven market demand', 'Single-founder risk — no team redundancy initially', 'Revenue dependent on subscription adoption rate' ]; const opportunities = [ `${business.cagr} market growth creates expanding demand`, `AI integration can automate ${business.niche}-specific workflows others haven't addressed`, 'Vertical SaaS commands 2-3x higher willingness to pay vs horizontal tools', 'API-first architecture enables marketplace and integration partnerships', `Adjacent verticals can expand TAM beyond initial ${business.tam}` ]; const threats = [ `${business.competitors[0] || 'Incumbent players'} could add similar features`, 'Economic downturn may slow SMB software spending', 'Open-source alternatives could commoditize core features', 'Regulatory changes in ' + business.niche + ' could require costly compliance updates', 'Customer concentration risk during early traction phase' ]; return { strengths, weaknesses, opportunities, threats }; } // ===== RISK ASSESSMENT ENGINE ===== function generateRisks(business, budget) { const risks = [ { name: 'Market Adoption', level: 'high', mitigation: `Validate with 20 pre-launch interviews in ${business.niche}. Pivot pricing if trial-to-paid < 5% after 60 days.` }, { name: 'Competitor Response', level: budget === 'bootstrap' ? 'high' : 'med', mitigation: `Focus on vertical-specific features ${business.competitors[0] || 'incumbents'} won't prioritize. Ship faster.` }, { name: 'Technical Debt', level: 'med', mitigation: 'Allocate 20% of sprint capacity to refactoring. Maintain >80% test coverage from day 1.' }, { name: 'Cash Runway', level: budget === 'bootstrap' ? 'high' : 'low', mitigation: `Reach $5K MRR before month 6 or cut burn by 40%. Keep 3-month runway reserve.` }, { name: 'Churn', level: 'med', mitigation: 'Implement onboarding flow, health scoring, and automated re-engagement emails. Target <5% monthly churn.' }, { name: 'Hiring', level: 'low', mitigation: 'Start with contractors for non-core work. First full-time hire after $10K MRR milestone.' }, { name: 'Data Security', level: 'med', mitigation: `SOC 2 readiness from launch. ${business.niche} data encryption at rest and in transit. Annual pen testing.` }, ]; return risks; } // ===== EXECUTIVE SUMMARY ENGINE ===== function generateExecutiveSummary(business, features, pricing, financials) { const midTier = pricing.find(p => p.highlighted) || pricing[1] || pricing[0]; const m12 = financials.months[11]; const m24 = financials.months[23] || financials.months[financials.months.length - 1]; const phase1 = features.filter(f => f.phase === 1); return `${business.name} is a vertical SaaS platform for the ${business.niche} industry ` + `(${business.tam} market, growing at ${business.cagr} CAGR). ` + `The core problem: ${business.pain.split('.')[0]}. ` + `Our solution delivers ${phase1.length} purpose-built features starting at ${midTier.price}${midTier.period}, ` + `targeting ${business.audience}. ` + `Financial projections show $${m12.mrr.toLocaleString()} MRR by month 12 ` + `and $${m24.mrr.toLocaleString()} MRR by month 24, ` + `with ${m12.totalUsers.toLocaleString()} total users in year one. ` + `Key differentiator: ${business.moat[0] || 'deep vertical focus that horizontal tools cannot match'}.`; } async function generate() { const niche = document.getElementById('niche').value.trim(); if (!niche) { document.getElementById('niche').focus(); return; } const audience = document.getElementById('audience').value.trim(); const region = document.getElementById('region').value; const problem = document.getElementById('problem').value.trim(); const budget = document.getElementById('budget').value; const timeline = document.getElementById('timeline').value; const btn = document.getElementById('generateBtn'); btn.disabled = true; btn.textContent = 'Generating...'; const bar = document.getElementById('progressBar'); const fill = document.getElementById('progressFill'); const status = document.getElementById('progressStatus'); bar.classList.add('active'); const steps = [ { pct: 10, text: "Analyzing niche: " + niche + "..." }, { pct: 25, text: "Researching market size and competitors..." }, { pct: 40, text: "Generating business model..." }, { pct: 50, text: "Designing feature roadmap..." }, { pct: 60, text: "Selecting tech stack..." }, { pct: 70, text: "Creating pricing strategy..." }, { pct: 78, text: "Building 90-day launch roadmap..." }, { pct: 88, text: "Building landing page..." }, { pct: 95, text: "Generating deployment guide..." }, { pct: 100, text: "Complete!" }, ]; const vertical = findVertical(niche); for (const step of steps) { fill.style.width = step.pct + '%'; status.textContent = step.text; await new Promise(r => setTimeout(r, 300 + Math.random() * 200)); } const business = generateBusinessModel(niche, vertical, audience, problem, region, budget); const features = generateFeatures(vertical); const techStack = generateTechStack(budget); const pricing = generatePricing(budget); const competitive = generateCompetitiveAnalysis(business, features, vertical); const financials = generateFinancials(business, pricing, budget); const landingHTML = generateLandingHTML(business, features, pricing); const deployGuide = generateDeployGuide(business, techStack, budget); const roadmap = generateRoadmap(business, features, budget, timeline); const swot = generateSWOT(business, features, pricing, competitive); const risks = generateRisks(business, budget); const starterCode = generateStarterCode(business, features, techStack, pricing, budget); generatedData = { business, features, techStack, pricing, competitive, financials, roadmap, landingHTML, deployGuide, swot, risks, starterCode }; renderResults(generatedData); // Update URL hash and page title for sharing history.replaceState(null, '', '#' + encodeParams()); document.title = business.name + ' — AI SaaS Business Plan | Tool Factory'; btn.disabled = false; btn.textContent = 'Generate SaaS Plan'; bar.classList.remove('active'); } // ===== FINANCIAL PROJECTIONS ENGINE ===== function generateFinancials(business, pricing, budget) { // Extract pricing numbers const midTier = pricing.find(p => p.highlighted) || pricing[1] || pricing[0]; const arpu = parseInt((midTier.price || '$29').replace(/[^0-9]/g, '')) || 29; const lowTier = parseInt((pricing[0].price || '$0').replace(/[^0-9]/g, '')) || 0; const highTier = parseInt((pricing[pricing.length-1].price || '$99').replace(/[^0-9]/g, '')) || 99; // Budget-based assumptions const assumptions = { bootstrap: { initialCash: 5000, monthlyBurn: 2000, founders: 1, hireMonth: 12, marketingPct: 0.15, cac: 50, churnRate: 0.06, growthRate: 0.18 }, seed: { initialCash: 50000, monthlyBurn: 8000, founders: 2, hireMonth: 6, marketingPct: 0.25, cac: 120, churnRate: 0.05, growthRate: 0.22 }, funded: { initialCash: 500000, monthlyBurn: 40000, founders: 3, hireMonth: 3, marketingPct: 0.30, cac: 300, churnRate: 0.04, growthRate: 0.25 }, enterprise:{ initialCash: 2000000, monthlyBurn: 150000, founders: 5, hireMonth: 1, marketingPct: 0.35, cac: 800, churnRate: 0.03, growthRate: 0.20 } }; const a = assumptions[budget] || assumptions.seed; // Cost structure const costs = { serverPerUser: budget === 'bootstrap' ? 0.5 : budget === 'seed' ? 0.3 : 0.2, supportPerUser: budget === 'bootstrap' ? 0 : 0.8, salaryPerHire: budget === 'bootstrap' ? 4000 : budget === 'seed' ? 6000 : budget === 'funded' ? 8000 : 12000 }; // 60-month (5 year) projection const months = []; let totalUsers = 0, paidUsers = 0, cash = a.initialCash, totalRevenue = 0, totalCosts = 0; let breakEvenMonth = null; let team = a.founders; for (let m = 1; m <= 60; m++) { // User growth (compounding with seasonal variation) const seasonalFactor = 1 + 0.05 * Math.sin(m * Math.PI / 6); const growthMultiplier = m <= 3 ? 0.5 : m <= 6 ? 0.8 : m <= 12 ? 1.0 : m <= 24 ? 1.1 : 1.05; const newUsers = Math.max(10, Math.round(totalUsers * a.growthRate * growthMultiplier * seasonalFactor)); const churnedUsers = Math.round(paidUsers * a.churnRate); totalUsers += newUsers; // Conversion ramp: starts low, improves with product maturity const conversionRate = Math.min(0.08, 0.015 + m * 0.001); const newPaid = Math.round(newUsers * conversionRate); paidUsers = Math.max(0, paidUsers + newPaid - churnedUsers); // Blended ARPU shifts up over time as enterprise customers come const blendedArpu = arpu * (1 + Math.min(0.3, m * 0.005)); // Revenue const mrr = Math.round(paidUsers * blendedArpu); const arr = mrr * 12; totalRevenue += mrr; // Hiring plan if (m >= a.hireMonth && m % 4 === 0 && team < (budget === 'bootstrap' ? 3 : budget === 'seed' ? 8 : budget === 'funded' ? 25 : 60)) { team++; } // Costs const salaries = team * costs.salaryPerHire; const serverCosts = Math.round(totalUsers * costs.serverPerUser); const marketingSpend = Math.round(mrr * a.marketingPct + a.cac * newPaid * 0.3); const supportCost = Math.round(paidUsers * costs.supportPerUser); const otherCosts = Math.round(1000 + team * 200); // tools, subscriptions, etc. const totalMonthCost = salaries + serverCosts + marketingSpend + supportCost + otherCosts; totalCosts += totalMonthCost; // Cash flow const netIncome = mrr - totalMonthCost; cash += netIncome; if (!breakEvenMonth && netIncome > 0) breakEvenMonth = m; // Unit economics const ltv = blendedArpu / Math.max(0.01, a.churnRate); const ltvCacRatio = ltv / Math.max(1, a.cac); const cacPayback = a.cac / Math.max(1, blendedArpu); months.push({ month: m, totalUsers, paidUsers, newUsers, churnedUsers, mrr, arr, blendedArpu: Math.round(blendedArpu), salaries, serverCosts, marketingSpend, supportCost, otherCosts, totalCost: totalMonthCost, netIncome, cash: Math.round(cash), team, ltv: Math.round(ltv), ltvCacRatio: Math.round(ltvCacRatio * 10) / 10, cacPayback: Math.round(cacPayback * 10) / 10, conversionRate: Math.round(conversionRate * 1000) / 10 }); } // Summary metrics const y1 = months[11], y2 = months[23], y3 = months[35], y4 = months[47], y5 = months[59]; const runway = cash > 0 ? null : months.findIndex(m => m.cash <= 0) + 1; return { assumptions: a, costs, months, breakEvenMonth, runway, arpu, summary: { y1: { arr: y1.arr, mrr: y1.mrr, users: y1.totalUsers, paid: y1.paidUsers, cash: y1.cash, team: y1.team }, y2: { arr: y2.arr, mrr: y2.mrr, users: y2.totalUsers, paid: y2.paidUsers, cash: y2.cash, team: y2.team }, y3: { arr: y3.arr, mrr: y3.mrr, users: y3.totalUsers, paid: y3.paidUsers, cash: y3.cash, team: y3.team }, y4: { arr: y4.arr, mrr: y4.mrr, users: y4.totalUsers, paid: y4.paidUsers, cash: y4.cash, team: y4.team }, y5: { arr: y5.arr, mrr: y5.mrr, users: y5.totalUsers, paid: y5.paidUsers, cash: y5.cash, team: y5.team }, }, totalRevenue, totalCosts }; } function renderFinancialsChart(months) { const canvas = document.getElementById('financials-chart'); if (!canvas) return; const ctx = canvas.getContext('2d'); const W = canvas.width = canvas.parentElement.offsetWidth; const H = canvas.height = 280; const pad = { top: 20, right: 20, bottom: 40, left: 70 }; const plotW = W - pad.left - pad.right; const plotH = H - pad.top - pad.bottom; ctx.fillStyle = '#0a0a0a'; ctx.fillRect(0, 0, W, H); // Data: quarterly MRR and costs const quarterly = []; for (let i = 2; i < months.length; i += 3) { quarterly.push({ q: Math.floor(i/3)+1, mrr: months[i].mrr, cost: months[i].totalCost, cash: months[i].cash }); } const maxVal = Math.max(...quarterly.map(q => Math.max(q.mrr, q.cost))) * 1.1; // Grid lines ctx.strokeStyle = '#222'; ctx.lineWidth = 1; for (let i = 0; i <= 4; i++) { const y = pad.top + plotH - (i / 4) * plotH; ctx.beginPath(); ctx.moveTo(pad.left, y); ctx.lineTo(W - pad.right, y); ctx.stroke(); ctx.fillStyle = '#555'; ctx.font = '11px -apple-system, sans-serif'; ctx.textAlign = 'right'; ctx.fillText('$' + Math.round(maxVal * i / 4).toLocaleString(), pad.left - 8, y + 4); } // X labels ctx.textAlign = 'center'; ctx.fillStyle = '#555'; quarterly.forEach((q, idx) => { if (idx % 2 === 0) { const x = pad.left + (idx / (quarterly.length - 1)) * plotW; ctx.fillText('Q' + q.q, x, H - 10); } }); // MRR line (blue) function drawLine(data, key, color) { ctx.beginPath(); ctx.strokeStyle = color; ctx.lineWidth = 2.5; data.forEach((d, i) => { const x = pad.left + (i / (data.length - 1)) * plotW; const y = pad.top + plotH - (d[key] / maxVal) * plotH; i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y); }); ctx.stroke(); } // Area fill for MRR ctx.beginPath(); quarterly.forEach((d, i) => { const x = pad.left + (i / (quarterly.length - 1)) * plotW; const y = pad.top + plotH - (d.mrr / maxVal) * plotH; i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y); }); ctx.lineTo(pad.left + plotW, pad.top + plotH); ctx.lineTo(pad.left, pad.top + plotH); ctx.closePath(); ctx.fillStyle = 'rgba(59,130,246,0.1)'; ctx.fill(); drawLine(quarterly, 'mrr', '#3b82f6'); drawLine(quarterly, 'cost', '#ef4444'); // Legend ctx.font = '12px -apple-system, sans-serif'; [['Revenue (MRR)', '#3b82f6'], ['Costs', '#ef4444']].forEach(([label, color], i) => { const lx = pad.left + 10 + i * 130; ctx.fillStyle = color; ctx.fillRect(lx, pad.top, 12, 12); ctx.fillStyle = '#aaa'; ctx.textAlign = 'left'; ctx.fillText(label, lx + 18, pad.top + 10); }); } // ===== STARTER CODE GENERATION ===== function generateStarterCode(business, features, techStack, pricing, budget) { const slug = business.name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/-+$/,''); const phase1 = features.filter(f => f.phase === 1); const isFirebase = budget === 'bootstrap'; const dbName = isFirebase ? 'Firestore' : 'PostgreSQL (Supabase)'; // package.json const packageJson = JSON.stringify({ name: slug, version: "0.1.0", private: true, scripts: { dev: "next dev", build: "next build", start: "next start", lint: "next lint", ...(isFirebase ? { "deploy": "next build && firebase deploy" } : {}) }, dependencies: { "next": "^15.0.0", "react": "^19.0.0", "react-dom": "^19.0.0", ...(isFirebase ? { "firebase": "^11.0.0" } : { "@supabase/supabase-js": "^2.45.0", "@supabase/ssr": "^0.5.0" }), "tailwindcss": "^4.0.0", "@tailwindcss/postcss": "^4.0.0" }, devDependencies: { "typescript": "^5.7.0", "@types/react": "^19.0.0", "@types/node": "^22.0.0", "postcss": "^8.5.0" } }, null, 2); // .env.example const envExample = isFirebase ? `# Firebase Configuration NEXT_PUBLIC_FIREBASE_API_KEY=your_api_key NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=${slug}.firebaseapp.com NEXT_PUBLIC_FIREBASE_PROJECT_ID=${slug} NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=${slug}.appspot.com NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=000000000000 NEXT_PUBLIC_FIREBASE_APP_ID=1:000000000000:web:xxxxxxxxxxxx` : `# Supabase Configuration NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key SUPABASE_SERVICE_ROLE_KEY=your_service_key # App NEXT_PUBLIC_APP_URL=http://localhost:3000`; // DB client const dbClient = isFirebase ? `// lib/firebase.ts import { initializeApp, getApps } from 'firebase/app'; import { getAuth } from 'firebase/auth'; import { getFirestore } from 'firebase/firestore'; const firebaseConfig = { apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID, }; const app = getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0]; export const auth = getAuth(app); export const db = getFirestore(app);` : `// lib/supabase.ts import { createBrowserClient } from '@supabase/ssr'; export function createClient() { return createBrowserClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! ); }`; // Database schema const dbSchema = isFirebase ? `// Firestore Security Rules — firestore.rules rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // Users can read/write their own profile match /users/{userId} { allow read, write: if request.auth != null && request.auth.uid == userId; } // ${business.niche} data — owner access only match /data/{docId} { allow read: if request.auth != null && resource.data.ownerId == request.auth.uid; allow create: if request.auth != null && request.resource.data.ownerId == request.auth.uid; allow update, delete: if request.auth != null && resource.data.ownerId == request.auth.uid; } // Subscription status match /subscriptions/{userId} { allow read: if request.auth != null && request.auth.uid == userId; } } }` : `-- Database Schema — supabase/migrations/001_initial.sql -- Enable RLS alter default privileges in schema public grant all on tables to postgres, anon, authenticated, service_role; -- Users profile (extends Supabase Auth) create table public.profiles ( id uuid references auth.users on delete cascade primary key, full_name text, company_name text, plan text default 'free' check (plan in ('free', 'pro', 'business')), created_at timestamptz default now(), updated_at timestamptz default now() ); alter table public.profiles enable row level security; create policy "Users can view own profile" on public.profiles for select using (auth.uid() = id); create policy "Users can update own profile" on public.profiles for update using (auth.uid() = id); -- Core ${business.niche} data table create table public.records ( id uuid default gen_random_uuid() primary key, owner_id uuid references auth.users on delete cascade not null, title text not null, data jsonb default '{}', status text default 'active', created_at timestamptz default now(), updated_at timestamptz default now() ); alter table public.records enable row level security; create policy "Owner access" on public.records for all using (auth.uid() = owner_id); create index idx_records_owner on public.records(owner_id); -- Auto-create profile on signup create or replace function public.handle_new_user() returns trigger as $$ begin insert into public.profiles (id, full_name) values (new.id, new.raw_user_meta_data->>'full_name'); return new; end; $$ language plpgsql security definer; create trigger on_auth_user_created after insert on auth.users for each row execute procedure public.handle_new_user();`; // Feature route stubs const featureRoutes = phase1.slice(0, 4).map(f => { const routeName = f.name.toLowerCase().replace(/[^a-z0-9]+/g, '-'); return `// app/${routeName}/page.tsx export default function ${f.name.replace(/[^a-zA-Z0-9]/g, '')}Page() { return (

${f.name}

${f.desc}

{/* TODO: Implement ${f.name} */}
); }`; }).join('\n\n'); // Layout const layoutCode = `// app/layout.tsx import type { Metadata } from 'next'; import './globals.css'; export const metadata: Metadata = { title: '${business.name} — ${business.positioning.split('.')[0]}', description: '${business.positioning}', }; export default function RootLayout({ children }: { children: React.ReactNode }) { return (
{children}
); }`; // Home page const homePageCode = `// app/page.tsx export default function Home() { return (

${business.name}

${business.positioning}

Get Started Free See Features
${phase1.slice(0, 4).map(f => `

${f.name}

${f.desc}

`).join('\n')}
); }`; // Pricing page const pricingPageCode = `// app/pricing/page.tsx const plans = ${JSON.stringify(pricing.map(p => ({name:p.name,price:p.price,period:p.period,features:p.features,highlighted:!!p.highlighted})), null, 2)}; export default function PricingPage() { return (

Pricing

Choose the plan that fits your ${business.niche.toLowerCase()} business

{plans.map((plan, i) => (

{plan.name}

{plan.price}{plan.period}
    {plan.features.map((f: string, j: number) => (
  • {f}
  • ))}
))}
); }`; // API route const apiRouteCode = isFirebase ? `// app/api/records/route.ts import { NextRequest, NextResponse } from 'next/server'; // In production, verify Firebase ID token server-side // import { getAuth } from 'firebase-admin/auth'; export async function GET(req: NextRequest) { // TODO: Verify auth token, fetch from Firestore return NextResponse.json({ records: [], message: 'Implement Firestore query' }); } export async function POST(req: NextRequest) { const body = await req.json(); // TODO: Verify auth, write to Firestore return NextResponse.json({ success: true, id: 'new-doc-id' }); }` : `// app/api/records/route.ts import { createClient } from '@/lib/supabase'; import { NextRequest, NextResponse } from 'next/server'; export async function GET(req: NextRequest) { const supabase = createClient(); const { data, error } = await supabase .from('records') .select('*') .order('created_at', { ascending: false }); if (error) return NextResponse.json({ error: error.message }, { status: 500 }); return NextResponse.json({ records: data }); } export async function POST(req: NextRequest) { const supabase = createClient(); const body = await req.json(); const { data, error } = await supabase .from('records') .insert(body) .select() .single(); if (error) return NextResponse.json({ error: error.message }, { status: 500 }); return NextResponse.json(data, { status: 201 }); }`; // globals.css const globalsCss = `/* app/globals.css */ @import "tailwindcss";`; // setup.sh const setupSh = `#!/bin/bash # ${business.name} — Quick Setup Script # Generated by Tool Factory AI SaaS Generator set -e echo "🚀 Setting up ${business.name}..." # Create project npx create-next-app@latest ${slug} --typescript --tailwind --eslint --app --src-dir=false --import-alias="@/*" --use-npm cd ${slug} # Install dependencies ${isFirebase ? 'npm install firebase' : 'npm install @supabase/supabase-js @supabase/ssr'} # Create env file cp .env.example .env.local echo "⚠️ Edit .env.local with your ${isFirebase ? 'Firebase' : 'Supabase'} credentials" echo "" echo "✅ ${business.name} is ready!" echo "" echo "Next steps:" echo " cd ${slug}" echo " npm run dev" echo "" echo "Open http://localhost:3000"`; return { slug, files: [ { name: 'package.json', code: packageJson, lang: 'json' }, { name: '.env.example', code: envExample, lang: 'bash' }, { name: 'app/layout.tsx', code: layoutCode, lang: 'tsx' }, { name: 'app/page.tsx', code: homePageCode, lang: 'tsx' }, { name: 'app/globals.css', code: globalsCss, lang: 'css' }, { name: 'app/pricing/page.tsx', code: pricingPageCode, lang: 'tsx' }, { name: 'app/api/records/route.ts', code: apiRouteCode, lang: 'ts' }, { name: isFirebase ? 'lib/firebase.ts' : 'lib/supabase.ts', code: dbClient, lang: 'ts' }, { name: isFirebase ? 'firestore.rules' : 'supabase/migrations/001_initial.sql', code: dbSchema, lang: isFirebase ? 'text' : 'sql' }, ...phase1.slice(0, 4).map(f => ({ name: `app/${f.name.toLowerCase().replace(/[^a-z0-9]+/g, '-')}/page.tsx`, code: featureRoutes.split('\n\n').find(block => block.includes(f.name)) || '', lang: 'tsx' })), { name: 'setup.sh', code: setupSh, lang: 'bash' }, ] }; } function renderResults(data) { const { business, features, techStack, pricing, competitive, financials, roadmap, landingHTML, deployGuide, swot, risks, starterCode } = data; const tabs = [ { id: "overview", label: "Overview", icon: "" }, { id: "features", label: "Features", icon: "" }, { id: "swot", label: "SWOT & Risks", icon: "" }, { id: "pitchdeck", label: "Pitch Deck", icon: "" }, { id: "roadmap", label: "90-Day Roadmap", icon: "" }, { id: "techstack", label: "Tech Stack", icon: "" }, { id: "pricing", label: "Pricing", icon: "" }, { id: "competitive", label: "Competitive", icon: "" }, { id: "financials", label: "Financials", icon: "" }, { id: "landing", label: "Landing Page", icon: "" }, { id: "deploy", label: "Deploy Guide", icon: "" }, { id: "startercode", label: "Starter Code", icon: "" }, ]; // Render tab bar const tabsBar = document.getElementById('tabsBar'); tabsBar.innerHTML = tabs.map((t,i) => `
${t.label}
`).join(''); // Tab click handlers tabsBar.querySelectorAll('.tab').forEach(tab => { tab.onclick = () => { tabsBar.querySelectorAll('.tab').forEach(t=>t.classList.remove('active')); document.querySelectorAll('.tab-content').forEach(c=>c.classList.remove('active')); tab.classList.add('active'); document.getElementById('tab-'+tab.dataset.tab).classList.add('active'); }; }); const phase1 = features.filter(f=>f.phase===1); const phase2 = features.filter(f=>f.phase===2); const mustHave = features.filter(f=>f.priority==='must'); // Render tab contents document.getElementById('tabContents').innerHTML = `
Business Overview: ${business.name}
${generateExecutiveSummary(business, features, pricing, financials)}
${business.tam}
Total Addressable Market
${business.cagr}
Market Growth (CAGR)
${business.kpis.targetMRR}
Target MRR (12 months)
${features.length}
Planned Features

Positioning

${business.positioning}

Target Audience

${business.audience}

Core Problem

${business.pain}

Competitive Moat
${business.moat.map(m => `

${m}

`).join('')}
Revenue Streams
${business.revenueStreams.map(r => ``).join('')}
Stream% of RevenueDescription
${r.stream}${r.pct}${r.desc}
Key Metrics (12-Month Targets)
MetricTarget
Monthly Recurring Revenue${business.kpis.targetMRR}
Active Users${business.kpis.targetUsers}
Monthly Churn Rate${business.kpis.churnTarget}
Customer Lifetime Value${business.kpis.ltv}
Customer Acquisition Cost${business.kpis.cac}
LTV:CAC Ratio${(parseFloat(business.kpis.ltv.replace(/[^0-9.]/g,''))/parseFloat(business.kpis.cac.replace(/[^0-9.]/g,''))).toFixed(1)}:1
Phase 1 — MVP (${mustHave.length} must-have features)
${phase1.map(f => `

${f.name}

${f.desc}

${f.priority.toUpperCase()} Phase 1
`).join('')}
${phase2.length ? `
Phase 2 — Growth
${phase2.map(f => `

${f.name}

${f.desc}

${f.priority.toUpperCase()} Phase 2
`).join('')}
` : ''}
Effort Estimation
${features.map(f => ``).join('')}
FeaturePriorityPhaseEffort (weeks)
${f.name}${f.priority.toUpperCase()}Phase ${f.phase}${f.effort}
SWOT Analysis

Strengths

    ${swot.strengths.map(s => `
  • ${s}
  • `).join('')}

Weaknesses

    ${swot.weaknesses.map(s => `
  • ${s}
  • `).join('')}

Opportunities

    ${swot.opportunities.map(s => `
  • ${s}
  • `).join('')}

Threats

    ${swot.threats.map(s => `
  • ${s}
  • `).join('')}
Risk Assessment
${risks.map(r => `
${r.level === 'high' ? 'High' : r.level === 'med' ? 'Medium' : 'Low'} ${r.name} ${r.mitigation}
`).join('')}
Strategic Recommendations

Short-term (0-3 months)

Focus on ${swot.strengths[0].split(' with ')[0]}. Validate demand with pre-launch interviews and landing page signups. Ship MVP with ${features.filter(f=>f.priority==='must').length} must-have features only.

Medium-term (3-6 months)

Address key weakness: build brand through content marketing and case studies. Pursue integration partnerships to expand distribution. Target ${business.kpis.targetUsers} users.

Long-term (6-12 months)

Capitalize on ${business.cagr} market growth. Explore adjacent verticals. Build competitive moat through data network effects and customer lock-in via workflow automation.

Investor Pitch Deck: ${business.name}

A 10-slide investor-ready pitch deck generated from your business plan. Each slide includes speaker notes and key talking points.

${(() => { const isPro = typeof ToolFactoryPayment !== 'undefined' && ToolFactoryPayment.isPro(); const phase1 = features.filter(f=>f.phase===1); const mustHave = features.filter(f=>f.priority==='must'); const avgPrice = pricing.find(p=>p.highlighted)?.price || pricing[1]?.price || '$29'; const m12 = financials.months[11]; const m24 = financials.months[23] || financials.months[financials.months.length-1]; const breakeven = financials.months.findIndex(m=>m.netIncome>=0); const slides = [ { num: 1, title: 'Title Slide', content: '
' + business.name + '
' + business.positioning + '
' + business.niche + ' | ' + business.tam + ' Market
', notes: 'Open with your one-liner. State the market size immediately to capture attention. This is your 10-second hook.', free: true }, { num: 2, title: 'The Problem', content: '

Pain Point

' + business.pain + '

Time Wasted

Hours per week lost to manual processes

Money Lost

Revenue leaking from inefficiency

Frustration

Teams stuck with outdated tools

', notes: 'Make the pain visceral. Use specific examples from your customer interviews. Investors need to FEEL the problem before they see the solution.', free: true }, { num: 3, title: 'The Solution', content: '
' + business.name + ': ' + business.positioning + '
' + phase1.slice(0,4).map(f => '

' + f.name + '

' + f.desc + '

').join('') + '
', notes: 'Show your top 3-4 features. Focus on outcomes not features. "Reduces scheduling time by 80%" beats "Has a scheduling module."', free: true }, { num: 4, title: 'Market Opportunity', content: '
' + business.tam + '
Total Addressable Market
' + business.cagr + '
Annual Growth
' + business.audience + '
Target Segment

Why Now?

AI/automation costs dropped 10x in 2 years. Vertical SaaS in ' + business.niche + ' is still fragmented. First-mover advantage is real.

', notes: 'TAM/SAM/SOM breakdown. Explain why THIS moment is the right time. Reference industry trends, regulatory changes, or technology shifts.', free: false }, { num: 5, title: 'Business Model', content: '
' + pricing.map(p => '
' + p.name + '
' + p.price + '' + p.period + '
    ' + p.features.slice(0,3).map(f=>'
  • ✓ '+f+'
  • ').join('') + '
').join('') + '
', notes: 'Walk through pricing tiers. Explain your land-and-expand strategy. Highlight the path from free trial to enterprise.', free: false }, { num: 6, title: 'Traction & Milestones', content: '
' + m12.totalUsers.toLocaleString() + '
Users (Month 12)
$' + m12.mrr.toLocaleString() + '
MRR (Month 12)
' + (breakeven>0?'Month '+breakeven:'Pre-revenue') + '
Break-even

Key Milestones

', notes: 'Show progression, not just current numbers. Even if pre-revenue, show pipeline, waitlist, LOIs, or pilot agreements.', free: false }, { num: 7, title: 'Competitive Landscape', content: '

How We Win

' + competitive.rows.filter(r=>r[business.name]==='full').slice(0,5).map(r => '').join('') + '
Capability' + business.name + 'Others
' + r.feature + 'Partial / No

Key Competitors

' + competitive.competitors.filter(c=>c!==business.name).join(', ') + '

', notes: 'Position against 2-3 direct competitors. Show your unfair advantage clearly. Avoid badmouthing — show differentiation.', free: false }, { num: 8, title: 'Go-to-Market Strategy', content: '

Phase 1: Launch

Content marketing, ' + business.niche + ' communities, Product Hunt launch. Target: 500 signups in 30 days.

Phase 2: Growth

SEO, partnerships with ' + business.niche + ' associations, referral program. Target: 10% MoM growth.

Phase 3: Scale

Inside sales team, conference presence, enterprise pilot program. Target: $50K MRR.

Phase 4: Expand

Adjacent verticals, marketplace/platform play, international expansion.

', notes: 'Be specific about channels. "Content marketing" is too vague. "Weekly blog posts targeting 15 long-tail keywords in ' + business.niche + '" is better.', free: false }, { num: 9, title: 'Financial Projections', content: '
$' + m12.mrr.toLocaleString() + '
Year 1 MRR
$' + m24.mrr.toLocaleString() + '
Year 2 MRR
$' + m24.cash.toLocaleString() + '
Cash Position (Y2)

Unit Economics

MetricValue
CAC$' + financials.assumptions.cac + '
LTV$' + Math.round(financials.months[11].ltvCacRatio * financials.assumptions.cac) + '
LTV:CAC Ratio' + financials.months[11].ltvCacRatio + ':1
Gross Margin~80%
', notes: 'Focus on unit economics: CAC, LTV, payback period. Show you understand the numbers, not just the vision.', free: false }, { num: 10, title: 'The Ask', content: '
Raising: Seed Round

Use of Funds

  • 40% Engineering
  • 30% Go-to-Market
  • 20% Operations
  • 10% Reserve

18-Month Goals

  • $50K+ MRR
  • 500+ paying customers
  • Series A ready
  • 3 adjacent verticals
', notes: 'State the raise amount, use of funds, and what milestones this gets you to. End with a clear call-to-action.', free: false } ]; let html = '
'; slides.forEach(slide => { const locked = !slide.free && !isPro; html += '
'; html += '
'; html += '
' + slide.num + '
'; html += '
' + slide.title + '
'; if (locked) html += 'PRO'; html += '
'; if (locked) { html += '
' + slide.content + '
'; html += '
'; html += '
Unlock Full Pitch Deck
Pro $29/mo — all 10 slides + speaker notes
'; } else { html += slide.content; } // Speaker notes (always visible for free slides, blurred for locked) if (!locked) { html += '
'; html += '
Speaker Notes
'; html += '

' + slide.notes + '

'; } html += '
'; }); html += '
'; if (isPro) { html += '
'; } return html; })()}
90-Day Launch Roadmap for ${business.name}

A week-by-week execution plan customized for your ${business.budget} budget and ${business.niche} niche. ${roadmap.totalWeeks} weeks to launch and grow.

${roadmap.totalWeeks}
Total Weeks
${roadmap.phases.length}
Phases
${roadmap.phases.reduce((s,p)=>s+p.weeks.reduce((s2,w)=>s2+w.tasks.length,0),0)}
Action Items
${roadmap.phases.find(p=>p.name==='Launch')?.weeks[0]?.week || '?'}
Launch Week
${roadmap.phases.map((phase, pi) => { const totalTasksBefore = roadmap.phases.slice(0, pi).reduce((s, p) => s + p.weeks.reduce((s2, w) => s2 + w.tasks.length, 0), 0); const lastFreeWeek = roadmap.freeWeeks; const isLocked = phase.weeks[0]?.week > lastFreeWeek; const isPro = typeof ToolFactoryPayment !== 'undefined' && ToolFactoryPayment.isPro(); return '
' + '
' + phase.name + '
' + (isLocked && !isPro ? '
' + '
' + phase.weeks.map(w => '
Week ' + w.week + '
' + w.title + '
' + w.tasks.map(t => '
' + t + '
').join('') + '
' ).join('') + '
' + '
' + '
🔒
' + '
Unlock Full Roadmap
' + '
Weeks ' + phase.weeks[0].week + '-' + roadmap.totalWeeks + ' available with Pro ($29/mo)
' + '
' + '
' : phase.weeks.map(w => '
Week ' + w.week + '
' + w.title + '
' + w.tasks.map(t => '
' + t + '
').join('') + '
' ).join('') ) + '
'; }).join('')}
Recommended Tech Stack
LayerTechnology
Frontend${techStack.frontend}
Backend${techStack.backend}
Database${techStack.db}
Hosting${techStack.hosting}
Authentication${techStack.auth}
Payments${techStack.payments}
Additional Services
${techStack.extras.map(e => `${e}`).join('')}
Project Structure
${business.name.toLowerCase()}-app/ +-- src/ | +-- app/ | | +-- (auth)/ | | | +-- login/page.tsx | | | +-- register/page.tsx | | +-- (dashboard)/ | | | +-- page.tsx | | | +-- settings/page.tsx ${features.filter(f=>f.phase===1).slice(0,4).map(f => `| | | +-- ${f.name.toLowerCase().replace(/[^a-z0-9]+/g,'-')}/page.tsx`).join('\n')} | | +-- api/ | | | +-- auth/[...nextauth]/route.ts | | | +-- webhooks/stripe/route.ts | | +-- layout.tsx | | +-- page.tsx | +-- components/ | | +-- ui/ | | +-- forms/ | | +-- layouts/ | +-- lib/ | | +-- db.ts | | +-- auth.ts | | +-- stripe.ts | +-- types/ +-- prisma/ | +-- schema.prisma +-- public/ +-- package.json +-- tailwind.config.ts +-- next.config.ts
Pricing Strategy
${pricing.map(p => `
${p.name}
${p.price}${p.period}
    ${p.features.map(f=>`
  • ✓ ${f}
  • `).join('')}
`).join('')}
Revenue Projections (12 Months)
${(() => { let users = 50, paid = 0, cumulative = 0; const midPrice = pricing.find(p=>p.highlighted)?.price || pricing[1]?.price || "$29"; const price = parseInt(midPrice.replace(/[^0-9]/g,'')) || 29; const rows = []; for(let m=1;m<=12;m++){ users = Math.round(users * (1.25 + Math.random()*0.15)); paid = Math.round(users * (0.02 + m*0.003)); const mrr = paid * price; cumulative += mrr; rows.push(``); } return rows.join(''); })()}
MonthUsersPaidMRRCumulative
Month ${m}${users.toLocaleString()}${paid}$${mrr.toLocaleString()}$${cumulative.toLocaleString()}
Competitive Analysis
${competitive.competitors.map(c => ``).join('')}${competitive.rows.map(r => `${competitive.competitors.map(c => { const v = r[c]; return v === 'full' ? '' : v === 'partial' ? '' : ''; }).join('')}`).join('')}
Feature${c}
${r.feature}~
Key Differentiators
${business.moat.map(m => `

${m}

`).join('')}
Go-to-Market Strategy
ChannelTimelineExpected CAC
SEO / Content MarketingMonth 1-12 (compounds)$5-15
Product Hunt LaunchMonth 2$0 (organic)
Niche Communities / RedditMonth 1-6$10-30
Google Ads (branded + niche)Month 3+$50-150
Partnerships / IntegrationsMonth 4+$20-50
Referral ProgramMonth 2+$15-25
5-Year Financial Projections
${financials.breakEvenMonth ? 'Month ' + financials.breakEvenMonth : 'N/A'}
Break-Even Point
$${financials.summary.y1.arr.toLocaleString()}
Year 1 ARR
$${financials.summary.y3.arr.toLocaleString()}
Year 3 ARR
$${financials.summary.y5.arr.toLocaleString()}
Year 5 ARR
Revenue vs Costs
Annual Summary
${['y1','y2','y3','y4','y5'].map((y,i) => { const s = financials.summary[y]; return ''; }).join('')}
YearARRMRRUsersPaidTeamCash Position
Year '+(i+1)+'$'+s.arr.toLocaleString()+'$'+s.mrr.toLocaleString()+''+s.users.toLocaleString()+''+s.paid.toLocaleString()+''+s.team+'$'+s.cash.toLocaleString()+'
Unit Economics
$${financials.arpu}
ARPU (base)
$${financials.months[11].ltv.toLocaleString()}
Customer LTV
$${financials.assumptions.cac}
CAC
${financials.months[11].ltvCacRatio}:1
LTV:CAC Ratio
Assumptions
ParameterValue
Initial Cash$${financials.assumptions.initialCash.toLocaleString()}
Monthly Growth Rate${(financials.assumptions.growthRate * 100).toFixed(0)}%
Monthly Churn Rate${(financials.assumptions.churnRate * 100).toFixed(0)}%
Marketing Spend (% of MRR)${(financials.assumptions.marketingPct * 100).toFixed(0)}%
Server Cost Per User$${financials.costs.serverPerUser}/mo
Founding Team${financials.assumptions.founders} people
${(() => { const isPro = typeof ToolFactoryPayment !== 'undefined' && ToolFactoryPayment.isPro(); if (isPro) { // Full monthly breakdown for Pro users return '
Monthly Breakdown (60 months)
' + '
' + '' + financials.months.map(m => '' ).join('') + '
MonthUsersPaidMRRCostsNetCash
'+m.month+''+m.totalUsers.toLocaleString()+''+m.paidUsers+'$'+m.mrr.toLocaleString()+'$'+m.totalCost.toLocaleString()+'$'+m.netIncome.toLocaleString()+'$'+m.cash.toLocaleString()+'
' + '
Cost Breakdown (Year 1)
' + '' + (() => { const y1months = financials.months.slice(0,12); const avgSalaries = Math.round(y1months.reduce((s,m)=>s+m.salaries,0)/12); const avgServer = Math.round(y1months.reduce((s,m)=>s+m.serverCosts,0)/12); const avgMarketing = Math.round(y1months.reduce((s,m)=>s+m.marketingSpend,0)/12); const avgSupport = Math.round(y1months.reduce((s,m)=>s+m.supportCost,0)/12); const avgOther = Math.round(y1months.reduce((s,m)=>s+m.otherCosts,0)/12); const total = avgSalaries+avgServer+avgMarketing+avgSupport+avgOther; return [ ['Salaries', avgSalaries], ['Infrastructure', avgServer], ['Marketing', avgMarketing], ['Support', avgSupport], ['Other', avgOther] ].map(([name,val]) => '' ).join(''); })() + '
CategoryMonthly AvgAnnual% of Total
'+name+'$'+val.toLocaleString()+'$'+(val*12).toLocaleString()+''+(total?Math.round(val/total*100):0)+'%
' + '
'; } else { return '
' + '
Pro: Full 60-Month Financial Model
' + '
Unlock detailed monthly breakdown, cost analysis by category, CAC payback period, burn rate analysis, and CSV export. Upgrade to Pro ($29/mo).
'; } })()}
Generated Landing Page
Deployment Guide
${deployGuide.replace(//g,'>')}
Starter Code — ${business.name}

Complete Next.js + Tailwind CSS + ${starterCode.files.find(f=>f.name.includes('firebase')) ? 'Firebase' : 'Supabase'} starter project. Download as ZIP or copy individual files.

${starterCode.files.map(f => `
${f.name.endsWith('.tsx') || f.name.endsWith('.ts') ? '📘' : f.name.endsWith('.json') ? '📋' : f.name.endsWith('.css') ? '🎨' : f.name.endsWith('.sh') ? '⚙' : f.name.endsWith('.sql') ? '🗃' : '📄'} ${f.name}
${f.code.replace(//g,'>')}
`).join('')}
`; // Render landing page in iframe setTimeout(() => { const frame = document.getElementById('landingFrame'); if (frame) { const doc = frame.contentDocument || frame.contentWindow.document; doc.open(); doc.write(landingHTML); doc.close(); } }, 100); // Render financials chart setTimeout(() => renderFinancialsChart(financials.months), 200); document.getElementById('results').classList.add('active'); document.getElementById('exportBar').style.display = 'flex'; // Scroll to results document.getElementById('results').scrollIntoView({ behavior: 'smooth', block: 'start' }); } // ===== EXPORT FUNCTIONS ===== function exportJSON() { if (!generatedData) return; const blob = new Blob([JSON.stringify(generatedData, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = generatedData.business.name.toLowerCase() + '-saas-plan.json'; a.click(); URL.revokeObjectURL(url); } function exportMarkdown() { if (!generatedData) return; const { business, features, techStack, pricing } = generatedData; let md = `# ${business.name} — ${business.niche} SaaS Business Plan\n\n`; md += `## Overview\n${business.positioning}\n\n`; md += `**Market Size:** ${business.tam} | **Growth:** ${business.cagr}\n\n`; md += `## Target Audience\n${business.audience}\n\n`; md += `## Core Problem\n${business.pain}\n\n`; md += `## Features\n\n### Phase 1 (MVP)\n`; features.filter(f=>f.phase===1).forEach(f => { md += `- **${f.name}**: ${f.desc}\n`; }); md += `\n### Phase 2 (Growth)\n`; features.filter(f=>f.phase===2).forEach(f => { md += `- **${f.name}**: ${f.desc}\n`; }); md += `\n## Tech Stack\n- Frontend: ${techStack.frontend}\n- Backend: ${techStack.backend}\n- Database: ${techStack.db}\n- Hosting: ${techStack.hosting}\n\n`; md += `## Pricing\n`; pricing.forEach(p => { md += `- **${p.name}**: ${p.price}${p.period}\n`; }); md += `\n## Competitive Moat\n`; business.moat.forEach(m => { md += `- ${m}\n`; }); if (generatedData.swot) { const s = generatedData.swot; md += `\n## SWOT Analysis\n\n### Strengths\n`; s.strengths.forEach(x => { md += `- ${x}\n`; }); md += `\n### Weaknesses\n`; s.weaknesses.forEach(x => { md += `- ${x}\n`; }); md += `\n### Opportunities\n`; s.opportunities.forEach(x => { md += `- ${x}\n`; }); md += `\n### Threats\n`; s.threats.forEach(x => { md += `- ${x}\n`; }); } if (generatedData.risks) { md += `\n## Risk Assessment\n`; generatedData.risks.forEach(r => { md += `- **${r.name}** [${r.level.toUpperCase()}]: ${r.mitigation}\n`; }); } md += `\n---\nGenerated by [Tool Factory SaaS Generator](https://tool-factory-prod.web.app/saas-generator/)\n`; const blob = new Blob([md], { type: 'text/markdown' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = business.name.toLowerCase() + '-plan.md'; a.click(); URL.revokeObjectURL(url); } function copyLandingHTML() { if (!generatedData) return; navigator.clipboard.writeText(generatedData.landingHTML).then(() => { const btn = event.target; btn.textContent = 'Copied!'; setTimeout(() => { btn.textContent = 'Copy Landing HTML'; }, 2000); }); } function downloadLanding() { if (!generatedData) return; const blob = new Blob([generatedData.landingHTML], { type: 'text/html' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = generatedData.business.name.toLowerCase() + '-landing.html'; a.click(); URL.revokeObjectURL(url); } function copyCode(btn) { const block = btn.parentElement; const text = block.textContent.replace('Copy','').trim(); navigator.clipboard.writeText(text).then(() => { btn.textContent = 'Copied!'; setTimeout(() => { btn.textContent = 'Copy'; }, 2000); }); } function exportPitchDeckHTML() { if (!generatedData) return; const d = generatedData; const html = '' + d.business.name + ' — Investor Pitch Deck' + '

' + d.business.name + '

' + d.business.positioning + '

' + d.business.niche + ' | ' + d.business.tam + ' Market

' + '

The Problem

' + d.business.pain + '

' + '

The Solution

' + d.business.positioning + '

' + d.features.filter(f=>f.phase===1).slice(0,4).map(f=>'

'+f.name+'

'+f.desc+'

').join('') + '
' + '

Market Opportunity

' + d.business.tam + '
TAM
' + d.business.cagr + '
CAGR
' + '

Business Model

' + d.pricing.map(p=>'

'+p.name+' — '+p.price+p.period+'

    '+p.features.map(f=>'
  • '+f+'
  • ').join('')+'
').join('') + '
' + '

Financial Projections

$'+d.financials.months[11].mrr.toLocaleString()+'
Year 1 MRR
$'+(d.financials.months[23]||d.financials.months[d.financials.months.length-1]).mrr.toLocaleString()+'
Year 2 MRR
' + '

Let\'s Build the Future of ' + d.business.niche + '

Contact us to learn more

' + ''; const blob = new Blob([html], { type: 'text/html' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = d.business.name.toLowerCase().replace(/\s+/g,'-') + '-pitch-deck.html'; a.click(); URL.revokeObjectURL(url); } function exportPitchDeckMD() { if (!generatedData) return; const d = generatedData; const m12 = d.financials.months[11]; const m24 = d.financials.months[23] || d.financials.months[d.financials.months.length-1]; let md = '# ' + d.business.name + ' — Investor Pitch Deck\n\n'; md += '---\n\n## Slide 1: ' + d.business.name + '\n\n' + d.business.positioning + '\n\n'; md += '**Market:** ' + d.business.tam + ' | **Growth:** ' + d.business.cagr + '\n\n'; md += '---\n\n## Slide 2: The Problem\n\n' + d.business.pain + '\n\n'; md += '---\n\n## Slide 3: The Solution\n\n'; d.features.filter(f=>f.phase===1).slice(0,4).forEach(f => { md += '- **' + f.name + '**: ' + f.desc + '\n'; }); md += '\n---\n\n## Slide 4: Market Opportunity\n\n- TAM: ' + d.business.tam + '\n- CAGR: ' + d.business.cagr + '\n- Target: ' + d.business.audience + '\n\n'; md += '---\n\n## Slide 5: Business Model\n\n'; d.pricing.forEach(p => { md += '### ' + p.name + ' — ' + p.price + p.period + '\n'; p.features.forEach(f => { md += '- ' + f + '\n'; }); md += '\n'; }); md += '---\n\n## Slide 6: Financial Projections\n\n- Year 1 MRR: $' + m12.mrr.toLocaleString() + '\n- Year 2 MRR: $' + m24.mrr.toLocaleString() + '\n- Year 1 Users: ' + m12.totalUsers.toLocaleString() + '\n\n'; md += '---\n\n## Slide 7: The Ask\n\n- 40% Engineering\n- 30% Go-to-Market\n- 20% Operations\n- 10% Reserve\n\n'; md += '---\n\n*Generated by [Tool Factory AI SaaS Generator](https://tool-factory-prod.web.app/saas-generator/)*\n'; const blob = new Blob([md], { type: 'text/markdown' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = d.business.name.toLowerCase().replace(/\s+/g,'-') + '-pitch-deck.md'; a.click(); URL.revokeObjectURL(url); } function exportFinancialsCSV() { if (!generatedData || !generatedData.financials) return; const f = generatedData.financials; let csv = 'Month,Total Users,Paid Users,New Users,Churned,MRR,ARR,ARPU,Salaries,Server,Marketing,Support,Other,Total Cost,Net Income,Cash,Team,LTV,LTV:CAC,CAC Payback\n'; f.months.forEach(m => { csv += [m.month,m.totalUsers,m.paidUsers,m.newUsers,m.churnedUsers,m.mrr,m.arr,m.blendedArpu,m.salaries,m.serverCosts,m.marketingSpend,m.supportCost,m.otherCosts,m.totalCost,m.netIncome,m.cash,m.team,m.ltv,m.ltvCacRatio,m.cacPayback].join(',') + '\n'; }); const blob = new Blob([csv], { type: 'text/csv' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = generatedData.business.name.toLowerCase() + '-financials.csv'; a.click(); URL.revokeObjectURL(url); } function exportPDF() { if (!generatedData) return; const b = generatedData.business; // Set print header const header = document.getElementById('printHeader'); header.innerHTML = '

' + b.name + '

' + b.niche + ' SaaS Business Plan — Generated by Tool Factory

' + new Date().toLocaleDateString('en-US', {year:'numeric',month:'long',day:'numeric'}) + '

'; // Set print footer const footer = document.getElementById('printFooter'); footer.innerHTML = 'Generated by Tool Factory SaaS Generator — tool-factory-prod.web.app/saas-generator/ — ' + new Date().toLocaleDateString(); // Add print titles to all tab-content elements document.querySelectorAll('.tab-content').forEach(el => { if (!el.dataset.printTitle) { const id = el.id.replace('tab-',''); const titles = {overview:'Business Overview',features:'Feature Roadmap',swot:'SWOT Analysis & Risk Assessment',pitchdeck:'Pitch Deck',roadmap:'90-Day Launch Roadmap',techstack:'Technology Stack',pricing:'Pricing Strategy',competitive:'Competitive Analysis',financials:'Financial Projections',landing:'Landing Page',deploy:'Deployment Guide',startercode:'Starter Code'}; el.dataset.printTitle = titles[id] || id; } }); window.print(); } function copyStarterFile(filename) { if (!generatedData || !generatedData.starterCode) return; const file = generatedData.starterCode.files.find(f => f.name === filename); if (!file) return; navigator.clipboard.writeText(file.code).then(() => { const btn = event.target; btn.textContent = 'Copied!'; setTimeout(() => { btn.textContent = 'Copy'; }, 2000); }); } function copySetupScript() { if (!generatedData || !generatedData.starterCode) return; const setup = generatedData.starterCode.files.find(f => f.name === 'setup.sh'); if (!setup) return; navigator.clipboard.writeText(setup.code).then(() => { const btn = event.target; const orig = btn.innerHTML; btn.innerHTML = '✅ Copied!'; setTimeout(() => { btn.innerHTML = orig; }, 2000); }); } function downloadStarterZIP() { if (!generatedData || !generatedData.starterCode) return; const sc = generatedData.starterCode; // Load JSZip from CDN if not loaded if (typeof JSZip === 'undefined') { const script = document.createElement('script'); script.src = 'https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js'; script.onload = () => _buildZip(sc); document.head.appendChild(script); } else { _buildZip(sc); } } function _buildZip(sc) { const zip = new JSZip(); const folder = zip.folder(sc.slug); sc.files.forEach(f => { folder.file(f.name, f.code); }); // Add README const readme = `# ${generatedData.business.name}\n\n${generatedData.business.positioning}\n\n## Quick Start\n\n\`\`\`bash\nbash setup.sh\n# or manually:\nnpm install\nnpm run dev\n\`\`\`\n\nOpen [http://localhost:3000](http://localhost:3000)\n\n## Tech Stack\n\n- **Frontend:** ${generatedData.techStack.frontend}\n- **Backend:** ${generatedData.techStack.backend}\n- **Database:** ${generatedData.techStack.db}\n- **Auth:** ${generatedData.techStack.auth}\n\n---\n\nGenerated by [Tool Factory AI SaaS Generator](https://tool-factory-prod.web.app/saas-generator/)\n`; folder.file('README.md', readme); zip.generateAsync({ type: 'blob' }).then(blob => { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = sc.slug + '-starter.zip'; a.click(); URL.revokeObjectURL(url); }); } function showProGate(feature) { if (typeof ToolFactoryPayment !== 'undefined') { ToolFactoryPayment.requirePro(() => {}, feature); } else { alert('Pro feature: ' + feature + '\n\nUpgrade to Pro ($29/mo) for access.'); } } // ===== SHAREABLE URL ===== function encodeParams() { const params = { n: document.getElementById('niche').value.trim(), a: document.getElementById('audience').value.trim(), r: document.getElementById('region').value, p: document.getElementById('problem').value.trim(), b: document.getElementById('budget').value, t: document.getElementById('timeline').value, }; // Remove empty optional fields if (!params.a) delete params.a; if (!params.p) delete params.p; if (params.r === 'global') delete params.r; if (params.b === 'seed') delete params.b; if (params.t === '1month') delete params.t; return btoa(unescape(encodeURIComponent(JSON.stringify(params)))); } function decodeParams(hash) { try { return JSON.parse(decodeURIComponent(escape(atob(hash)))); } catch(e) { return null; } } function sharePlan() { const encoded = encodeParams(); const url = window.location.origin + window.location.pathname + '#' + encoded; navigator.clipboard.writeText(url).then(() => { const btn = document.getElementById('shareBtn'); btn.innerHTML = '✅ Link Copied!'; setTimeout(() => { btn.innerHTML = '🔗 Share Plan'; }, 2500); }).catch(() => { prompt('Copy this link to share your plan:', url); }); // Update URL without reload history.replaceState(null, '', '#' + encoded); } // Auto-generate from URL hash on page load (function loadFromHash() { const hash = window.location.hash.slice(1); if (!hash) return; const params = decodeParams(hash); if (!params || !params.n) return; document.getElementById('niche').value = params.n; if (params.a) document.getElementById('audience').value = params.a; if (params.r) document.getElementById('region').value = params.r; if (params.p) document.getElementById('problem').value = params.p; if (params.b) document.getElementById('budget').value = params.b; if (params.t) document.getElementById('timeline').value = params.t; // Auto-generate after short delay setTimeout(() => generate(), 500); })(); function handleEmailSubmit(e) { e.preventDefault(); const email = document.getElementById('emailInput').value; // Store email in localStorage for now (will connect to backend later) const emails = JSON.parse(localStorage.getItem('tf_subscribers') || '[]'); if (!emails.includes(email)) { emails.push(email); localStorage.setItem('tf_subscribers', JSON.stringify(emails)); } // Track the conversion if (typeof gtag === 'function') gtag('event', 'subscribe', { method: 'email', tool: 'saas-generator' }); document.getElementById('emailForm').style.display = 'none'; document.getElementById('emailSuccess').style.display = 'block'; return false; }