vibe-ship-it 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/README.md +133 -0
  2. package/bin/init.js +135 -0
  3. package/package.json +30 -0
  4. package/template/CLAUDE.md +71 -0
  5. package/template/_claude/commands/check.md +6 -0
  6. package/template/_claude/commands/save.md +9 -0
  7. package/template/_claude/commands/ship.md +8 -0
  8. package/template/_claude/commands/stuck.md +10 -0
  9. package/template/_claude/commands/wow.md +10 -0
  10. package/template/_github/agents/assistant.agent.md +60 -0
  11. package/template/_github/agents/checker.agent.md +93 -0
  12. package/template/_github/agents/investigator.agent.md +196 -0
  13. package/template/_github/agents/shipper.agent.md +180 -0
  14. package/template/_github/copilot-instructions.md +60 -0
  15. package/template/skills/add-login/SKILL.md +204 -0
  16. package/template/skills/before-you-ship/SKILL.md +132 -0
  17. package/template/skills/build-page/SKILL.md +137 -0
  18. package/template/skills/make-it-wow/SKILL.md +139 -0
  19. package/template/skills/noob-mode/SKILL.md +135 -0
  20. package/template/skills/platforms/web-nextjs/SKILL.md +160 -0
  21. package/template/skills/platforms/web-nextjs/references/tailwind-shortcuts.md +97 -0
  22. package/template/skills/quick-check/SKILL.md +89 -0
  23. package/template/skills/save-data/SKILL.md +155 -0
  24. package/template/skills/send-email/SKILL.md +164 -0
  25. package/template/skills/show-data/SKILL.md +209 -0
  26. package/template/skills/unstuck/SKILL.md +105 -0
  27. package/template/skills/upload-file/SKILL.md +188 -0
  28. package/template/skills/what-am-i-building/SKILL.md +129 -0
  29. package/template/skills/what-am-i-building/references/platform-routing.md +66 -0
@@ -0,0 +1,209 @@
1
+ ---
2
+ name: show-data
3
+ description: "Displays saved data as lists, tables, cards, or dashboards. Triggers: 'show me all the', 'list all', 'dashboard', 'display', 'table of', 'view submissions', 'view entries', 'see the data', 'admin page', 'show bookings', 'show messages', 'show orders', 'data page', 'overview'."
4
+ ---
5
+
6
+ # Show Data
7
+
8
+ Displays saved data in a styled, readable format. Turns raw database rows into cards, tables, or dashboard views.
9
+
10
+ ## Process
11
+
12
+ ### Step 1: Identify What to Show
13
+
14
+ From context, determine:
15
+ - Which table/data source (what did `save-data` create?)
16
+ - Who sees it (public visitors or admin only?)
17
+ - How many items expected (handful or hundreds?)
18
+
19
+ ### Step 2: Choose Display Format
20
+
21
+ | Best for | Format | Use when |
22
+ |---|---|---|
23
+ | Few items with details | Cards | Portfolio items, testimonials, team members |
24
+ | Many items to scan | Table | Admin view of submissions, orders, bookings |
25
+ | Stats overview | Dashboard | Counts, recent activity, key numbers |
26
+ | Timeline | List | Activity log, blog posts, updates |
27
+
28
+ Don't ask the designer which format — pick the best one for their data. They'll say "actually, can it be cards instead?" if they want something different.
29
+
30
+ ### Step 3: Build the View
31
+
32
+ **Server component that fetches data** (Next.js App Router):
33
+
34
+ ```tsx
35
+ import { createClient } from '@/utils/supabase/server'
36
+
37
+ export default async function DashboardPage() {
38
+ const supabase = await createClient()
39
+ const { data: items } = await supabase
40
+ .from('table_name')
41
+ .select('*')
42
+ .order('created_at', { ascending: false })
43
+
44
+ return (
45
+ <div className="max-w-4xl mx-auto px-4 py-12">
46
+ <h1 className="text-3xl font-bold mb-8">Your [Items]</h1>
47
+
48
+ {items?.length === 0 ? (
49
+ <EmptyState />
50
+ ) : (
51
+ <div className="space-y-4">
52
+ {items?.map((item) => (
53
+ <ItemCard key={item.id} item={item} />
54
+ ))}
55
+ </div>
56
+ )}
57
+ </div>
58
+ )
59
+ }
60
+ ```
61
+
62
+ ### Step 4: Empty State
63
+
64
+ Never show a blank page. Always show an empty state:
65
+
66
+ ```tsx
67
+ function EmptyState() {
68
+ return (
69
+ <div className="text-center py-16">
70
+ <p className="text-gray-400 text-lg">No entries yet.</p>
71
+ <p className="text-gray-400 text-sm mt-2">
72
+ When someone submits the form, their entry will appear here.
73
+ </p>
74
+ </div>
75
+ )
76
+ }
77
+ ```
78
+
79
+ ### Step 5: Test
80
+
81
+ > "Check your dashboard page. If you submitted test data through your form earlier, you'll see it here. If not, go submit the form, then refresh the dashboard."
82
+
83
+ ## Display Templates
84
+
85
+ ### Card Layout (for rich content)
86
+ ```tsx
87
+ function ItemCard({ item }: { item: any }) {
88
+ return (
89
+ <div className="bg-white border rounded-xl p-6 shadow-sm">
90
+ <div className="flex justify-between items-start">
91
+ <div>
92
+ <h3 className="font-semibold text-lg">{item.name}</h3>
93
+ <p className="text-gray-500 text-sm">{item.email}</p>
94
+ </div>
95
+ <span className="text-gray-400 text-sm">
96
+ {new Date(item.created_at).toLocaleDateString()}
97
+ </span>
98
+ </div>
99
+ <p className="text-gray-700 mt-3">{item.message}</p>
100
+ </div>
101
+ )
102
+ }
103
+ ```
104
+
105
+ ### Table Layout (for scanning)
106
+ ```tsx
107
+ <div className="overflow-x-auto">
108
+ <table className="w-full text-left">
109
+ <thead>
110
+ <tr className="border-b text-sm text-gray-500">
111
+ <th className="py-3 px-4 font-medium">Name</th>
112
+ <th className="py-3 px-4 font-medium">Email</th>
113
+ <th className="py-3 px-4 font-medium">Date</th>
114
+ </tr>
115
+ </thead>
116
+ <tbody>
117
+ {items?.map((item) => (
118
+ <tr key={item.id} className="border-b hover:bg-gray-50">
119
+ <td className="py-3 px-4">{item.name}</td>
120
+ <td className="py-3 px-4 text-gray-500">{item.email}</td>
121
+ <td className="py-3 px-4 text-gray-400 text-sm">
122
+ {new Date(item.created_at).toLocaleDateString()}
123
+ </td>
124
+ </tr>
125
+ ))}
126
+ </tbody>
127
+ </table>
128
+ </div>
129
+ ```
130
+
131
+ ### Dashboard Stats (for overview)
132
+ ```tsx
133
+ async function DashboardStats() {
134
+ const supabase = await createClient()
135
+ const { count: total } = await supabase
136
+ .from('table_name')
137
+ .select('*', { count: 'exact', head: true })
138
+
139
+ const { count: today } = await supabase
140
+ .from('table_name')
141
+ .select('*', { count: 'exact', head: true })
142
+ .gte('created_at', new Date().toISOString().split('T')[0])
143
+
144
+ return (
145
+ <div className="grid grid-cols-2 md:grid-cols-3 gap-4 mb-8">
146
+ <StatCard label="Total" value={total ?? 0} />
147
+ <StatCard label="Today" value={today ?? 0} />
148
+ </div>
149
+ )
150
+ }
151
+
152
+ function StatCard({ label, value }: { label: string; value: number }) {
153
+ return (
154
+ <div className="bg-white border rounded-xl p-6">
155
+ <p className="text-sm text-gray-500">{label}</p>
156
+ <p className="text-3xl font-bold mt-1">{value}</p>
157
+ </div>
158
+ )
159
+ }
160
+ ```
161
+
162
+ ## Access Control
163
+
164
+ If this is an admin-only view:
165
+ - Ensure the route is protected by middleware (from `add-login` skill)
166
+ - Add sign-out button on the page
167
+ - Show the user's email: "Signed in as you@email.com"
168
+
169
+ If this is public (like a portfolio or directory):
170
+ - No auth needed
171
+ - Make sure the Supabase RLS policy allows public reads
172
+
173
+ ## Real-Time Updates (Optional)
174
+
175
+ If the designer wants to see new entries appear without refreshing:
176
+ ```tsx
177
+ 'use client'
178
+
179
+ import { createClient } from '@/utils/supabase/client'
180
+ import { useEffect, useState } from 'react'
181
+
182
+ // Subscribe to new entries
183
+ useEffect(() => {
184
+ const supabase = createClient()
185
+ const channel = supabase.channel('entries')
186
+ .on('postgres_changes', {
187
+ event: 'INSERT',
188
+ schema: 'public',
189
+ table: 'table_name',
190
+ }, (payload) => {
191
+ setItems(prev => [payload.new, ...prev])
192
+ })
193
+ .subscribe()
194
+
195
+ return () => { supabase.removeChannel(channel) }
196
+ }, [])
197
+ ```
198
+
199
+ Only add if they ask for it. Don't over-engineer.
200
+
201
+ ## Common Issues
202
+
203
+ | Problem | Fix |
204
+ |---|---|
205
+ | Page shows empty even though data exists | Check RLS policy allows reads for this user |
206
+ | Data shows but unstyled | Make sure Tailwind classes are applied |
207
+ | Dates look ugly | Format with `toLocaleDateString()` |
208
+ | Too much data, page is slow | Add `.limit(50)` to query, add pagination later if needed |
209
+ | Data appears on refresh but not immediately | Page is server-side cached — add `export const revalidate = 0` for always-fresh data |
@@ -0,0 +1,105 @@
1
+ ---
2
+ name: unstuck
3
+ description: "Detects frustration and fixes problems fast. Triggers: 'stuck', 'this doesn't work', 'broken', 'help', 'ugh', 'what the hell', 'why', 'not working', 'it broke', 'error', 'can't figure out', 'I give up', 'frustrated', 'wtf', 'nothing happens', 'blank page', 'won't load', 'keeps crashing'."
4
+ ---
5
+
6
+ # Unstuck
7
+
8
+ The momentum-preservation skill. When a designer hits a wall, get them back to a working state as fast as possible. Explain after.
9
+
10
+ ## Detection Signals
11
+
12
+ Activate when you see:
13
+ - Short frustrated messages: "ugh", "help", "stuck", "wtf"
14
+ - Error descriptions: "this doesn't work", "it broke", "nothing happens"
15
+ - Repeated attempts at the same thing
16
+ - Same error appearing multiple times
17
+ - Designer pasting error messages
18
+ - Questions like "why doesn't this work?"
19
+
20
+ ## Response Protocol
21
+
22
+ ### Step 1: Acknowledge (1 sentence)
23
+ > "Got it, let me take a look."
24
+
25
+ Do NOT say: "What seems to be the problem?" or "Can you describe the error?" or "What were you trying to do?"
26
+
27
+ They already told you. Or the context tells you. Diagnose from what you can see.
28
+
29
+ ### Step 2: Diagnose Silently
30
+
31
+ Check in this order:
32
+ 1. **Terminal output** — any errors visible?
33
+ 2. **Browser console** — any errors in the page?
34
+ 3. **Recent file changes** — what did they (or you) change last?
35
+ 4. **Dev server** — is it running? Did it crash?
36
+ 5. **Dependencies** — any missing packages?
37
+ 6. **Environment** — any missing env vars?
38
+
39
+ ### Step 3: Fix
40
+
41
+ Fix the problem. Don't describe what you're about to do. Just do it.
42
+
43
+ ### Step 4: Show Working Result
44
+ > "That's working now. Check your browser."
45
+
46
+ ### Step 5: Brief Explanation (1-2 sentences, only if helpful)
47
+ > "The issue was [X]. This happens when [Y]. No worries."
48
+
49
+ Do NOT:
50
+ - Launch into a teaching moment
51
+ - Explain the underlying architecture
52
+ - Suggest they should have done it differently
53
+ - Recommend preventive measures
54
+
55
+ ### Step 6: Momentum Restore
56
+ > "Want to keep going?"
57
+
58
+ ## Common Problems & Fast Fixes
59
+
60
+ | Symptom | Likely cause | Fix |
61
+ |---|---|---|
62
+ | Blank page | Server component trying to use client hooks | Add `'use client'` directive |
63
+ | "Module not found" | Missing package | `npm install [package]` |
64
+ | Form submits but nothing happens | Server action not connected or missing `'use server'` | Check action binding |
65
+ | "hydration mismatch" | Server/client HTML differs | Move dynamic content to client component |
66
+ | Page shows raw code/JSON | Missing page component or wrong export | Check default export |
67
+ | Styles not applying | Tailwind class not compiling or wrong class name | Check tailwind config, restart dev server |
68
+ | "ECONNREFUSED" on database | Supabase not configured or env vars missing | Check `.env.local` |
69
+ | Login redirect loop | Middleware misconfigured | Check middleware matcher |
70
+ | Image not showing | Wrong path or missing from public folder | Fix path or move image |
71
+ | Dev server won't start | Port in use or syntax error | Kill port, check last edit |
72
+ | "Cannot read properties of undefined" | Accessing data before it loads | Add loading/null check |
73
+ | Build fails | TypeScript error or missing import | Check the specific error line |
74
+
75
+ ## Escalation
76
+
77
+ If you can't fix it in 2 attempts:
78
+
79
+ > "This one's tricky. I've tried two approaches and it's still not playing nice.
80
+ >
81
+ > Here's what I can do:
82
+ > 1. **Roll back** — go back to how it was 5 minutes ago before this broke
83
+ > 2. **Try a different approach** — do the same thing but built differently
84
+ >
85
+ > Which do you prefer?"
86
+
87
+ If they choose rollback, use git:
88
+ ```bash
89
+ git stash # saves their changes
90
+ git checkout -- . # restores last good state
91
+ ```
92
+
93
+ Then re-apply their intended change with a different approach.
94
+
95
+ ## Anti-Patterns
96
+
97
+ NEVER do these when a designer is frustrated:
98
+
99
+ - ❌ "What error are you seeing?" (you can see it)
100
+ - ❌ "Can you try clearing your cache?" (you fix it)
101
+ - ❌ "This is because of how React hydration works..." (they don't care right now)
102
+ - ❌ "You should have used X instead of Y" (not the time)
103
+ - ❌ "Let me explain what went wrong in detail" (later, if they ask)
104
+ - ❌ Ask multiple clarifying questions before acting
105
+ - ❌ Suggest they read documentation
@@ -0,0 +1,188 @@
1
+ ---
2
+ name: upload-file
3
+ description: "Handles file and image uploads. Triggers: 'upload', 'add a photo', 'add an image', 'file upload', 'image upload', 'let them upload', 'upload pictures', 'attach file', 'profile picture', 'photo gallery', 'add photos', 'drag and drop'."
4
+ ---
5
+
6
+ # Upload File
7
+
8
+ Lets users upload images or files. Stores them in the cloud, displays them on the site.
9
+
10
+ ## Default: Supabase Storage
11
+
12
+ Already using Supabase for data, so storage is built in.
13
+
14
+ ### Step 1: Create Storage Bucket
15
+
16
+ Via Supabase dashboard:
17
+ > "Go to Supabase dashboard → Storage → New Bucket.
18
+ > Name it something like 'images' or 'uploads'.
19
+ > Set it to Public if these images should be visible on your site."
20
+
21
+ Or via SQL:
22
+ ```sql
23
+ insert into storage.buckets (id, name, public)
24
+ values ('images', 'images', true);
25
+
26
+ -- Allow anyone to upload (for public forms)
27
+ create policy "Anyone can upload" on storage.objects
28
+ for insert with check (bucket_id = 'images');
29
+
30
+ -- Allow anyone to view (for public images)
31
+ create policy "Anyone can view" on storage.objects
32
+ for select using (bucket_id = 'images');
33
+ ```
34
+
35
+ ### Step 2: Create Upload Component
36
+
37
+ ```tsx
38
+ 'use client'
39
+
40
+ import { createClient } from '@/utils/supabase/client'
41
+ import { useState } from 'react'
42
+
43
+ export function ImageUpload({ onUpload }: { onUpload: (url: string) => void }) {
44
+ const [uploading, setUploading] = useState(false)
45
+
46
+ async function handleUpload(e: React.ChangeEvent<HTMLInputElement>) {
47
+ const file = e.target.files?.[0]
48
+ if (!file) return
49
+
50
+ setUploading(true)
51
+ const supabase = createClient()
52
+
53
+ // Generate unique filename
54
+ const fileExt = file.name.split('.').pop()
55
+ const fileName = `${Date.now()}-${Math.random().toString(36).slice(2)}.${fileExt}`
56
+
57
+ const { error } = await supabase.storage
58
+ .from('images')
59
+ .upload(fileName, file)
60
+
61
+ if (error) {
62
+ alert('Upload failed. Try again.')
63
+ setUploading(false)
64
+ return
65
+ }
66
+
67
+ // Get the public URL
68
+ const { data: { publicUrl } } = supabase.storage
69
+ .from('images')
70
+ .getPublicUrl(fileName)
71
+
72
+ onUpload(publicUrl)
73
+ setUploading(false)
74
+ }
75
+
76
+ return (
77
+ <label className="block cursor-pointer">
78
+ <div className="border-2 border-dashed border-gray-300 rounded-xl p-8 text-center hover:border-gray-400 transition-colors">
79
+ {uploading ? (
80
+ <p className="text-gray-500">Uploading...</p>
81
+ ) : (
82
+ <>
83
+ <p className="text-gray-500">Click to upload an image</p>
84
+ <p className="text-sm text-gray-400 mt-1">PNG, JPG, WebP up to 5MB</p>
85
+ </>
86
+ )}
87
+ </div>
88
+ <input
89
+ type="file"
90
+ accept="image/*"
91
+ onChange={handleUpload}
92
+ className="hidden"
93
+ disabled={uploading}
94
+ />
95
+ </label>
96
+ )
97
+ }
98
+ ```
99
+
100
+ ### Step 3: Use It
101
+
102
+ In any page or form:
103
+ ```tsx
104
+ import { ImageUpload } from '@/components/ImageUpload'
105
+
106
+ // In your component:
107
+ <ImageUpload onUpload={(url) => {
108
+ // Save the URL to your database, or display it
109
+ console.log('Uploaded:', url)
110
+ }} />
111
+ ```
112
+
113
+ ### Step 4: Display Uploaded Images
114
+
115
+ ```tsx
116
+ // Single image
117
+ <img src={imageUrl} alt="Uploaded image" className="rounded-lg w-full max-w-md" />
118
+
119
+ // Gallery grid
120
+ <div className="grid grid-cols-2 md:grid-cols-3 gap-4">
121
+ {images.map((url) => (
122
+ <img key={url} src={url} alt="" className="rounded-lg aspect-square object-cover" />
123
+ ))}
124
+ </div>
125
+ ```
126
+
127
+ ### Step 5: Test It
128
+
129
+ > "Try uploading an image. It should appear on the page immediately. You can also check your Supabase dashboard → Storage → images to see the file."
130
+
131
+ ## Variations
132
+
133
+ ### Profile Picture
134
+ Upload + save URL to user record:
135
+ ```typescript
136
+ // After upload, save to user profile
137
+ await supabase.from('profiles').update({
138
+ avatar_url: publicUrl
139
+ }).eq('id', userId)
140
+ ```
141
+
142
+ ### Multiple Images
143
+ Allow selecting multiple files:
144
+ ```tsx
145
+ <input type="file" accept="image/*" multiple onChange={handleMultiUpload} />
146
+ ```
147
+
148
+ ### Drag and Drop
149
+ Add drag-and-drop to the upload zone:
150
+ ```tsx
151
+ <div
152
+ onDragOver={(e) => { e.preventDefault(); setDragging(true) }}
153
+ onDragLeave={() => setDragging(false)}
154
+ onDrop={(e) => {
155
+ e.preventDefault()
156
+ setDragging(false)
157
+ const file = e.dataTransfer.files[0]
158
+ if (file) handleUploadFile(file)
159
+ }}
160
+ className={`border-2 border-dashed rounded-xl p-8 text-center transition-colors ${
161
+ dragging ? 'border-blue-400 bg-blue-50' : 'border-gray-300'
162
+ }`}
163
+ >
164
+ ```
165
+
166
+ ## File Size & Type Limits
167
+
168
+ Set reasonable defaults:
169
+ - Max file size: 5MB for images, 10MB for documents
170
+ - Accepted types: `image/*` for images, or specific extensions
171
+ - Validate before upload, show friendly error if too large
172
+
173
+ ```typescript
174
+ if (file.size > 5 * 1024 * 1024) {
175
+ alert('This image is too large. Please use one under 5MB.')
176
+ return
177
+ }
178
+ ```
179
+
180
+ ## Common Issues
181
+
182
+ | Problem | Fix |
183
+ |---|---|
184
+ | "Bucket not found" | Create the bucket in Supabase dashboard |
185
+ | Upload succeeds but image doesn't display | Check bucket is set to Public |
186
+ | "Permission denied" on upload | Check storage policies — insert policy needed |
187
+ | Image loads slowly | Supabase serves from CDN, but very large images will be slow. Consider resizing before upload |
188
+ | Wrong file type uploaded | Add `accept` attribute to input and validate in JS |
@@ -0,0 +1,129 @@
1
+ ---
2
+ name: what-am-i-building
3
+ description: "Figures out what you're building and sets up the project. Triggers: 'I want to build', 'I want to make', 'new project', 'start something', 'I have an idea', 'help me build', 'create a', 'build me a', 'I need a website', 'I need an app', 'make me a'."
4
+ ---
5
+
6
+ # What Am I Building
7
+
8
+ The entry point for every new project. Translates the designer's idea into a working scaffold as fast as possible.
9
+
10
+ ## Fast Mode (Default)
11
+
12
+ Ask ONE question, then scaffold. Do not front-load planning.
13
+
14
+ ### The Question
15
+
16
+ > "What are you making? Give me the quick version — what does someone DO when they visit?"
17
+
18
+ ### From Their Answer, Extract
19
+
20
+ 1. **Platform** — web, mobile, desktop, or other (see routing table below)
21
+ 2. **Core action** — the ONE thing a visitor does (book, buy, read, contact, upload)
22
+ 3. **First visible thing** — the landing page / first screen
23
+
24
+ ### Then Immediately
25
+
26
+ 1. Show a simple flow map:
27
+ ```
28
+ 📍 Here's how it'll work:
29
+ [Visitor arrives] → [Sees X] → [Does Y] → [Result Z]
30
+ ```
31
+ 2. Scaffold the project
32
+ 3. Start the dev server
33
+ 4. Show the first page in the browser
34
+
35
+ Total time from idea to first page in browser: **under 5 minutes.**
36
+
37
+ ## Platform Routing
38
+
39
+ | They say | Platform | Stack |
40
+ |---|---|---|
41
+ | "website", "landing page", "portfolio", "blog" | Web | Next.js + Tailwind + Supabase + Vercel |
42
+ | "web app", "dashboard", "tool", "SaaS" | Web | Next.js + Tailwind + Supabase + Vercel |
43
+ | "app", "iPhone", "Android", "mobile" | Mobile | React Native + Expo + Supabase + EAS |
44
+ | "store", "sell", "shop", "products", "e-commerce" | Shopify | Liquid + Shopify CLI |
45
+ | "blog", "CMS", "content site", "magazine" | WordPress | Block themes + WP REST API |
46
+ | "Figma plugin", "extend Figma" | Figma Plugin | TypeScript + Figma Plugin API |
47
+ | "email template", "newsletter" | Email | MJML + Resend |
48
+ | "desktop app", "Mac app", "Windows app" | Desktop | Electron + Vite |
49
+ | "art", "generative", "creative", "animation" | Creative | p5.js or Three.js |
50
+
51
+ If ambiguous: "Is this something people use on their phone, in a browser, or on their desktop?"
52
+
53
+ Only ask if truly unclear — most of the time, the context makes it obvious.
54
+
55
+ ## Scaffolding (Web — Default)
56
+
57
+ ```bash
58
+ npx create-next-app@latest . --typescript --tailwind --eslint --app --src-dir --import-alias "@/*" --use-npm
59
+ ```
60
+
61
+ After scaffold, immediately:
62
+ 1. Clean up starter boilerplate (remove default Next.js hero content)
63
+ 2. Add a minimal but attractive landing page with good typography
64
+ 3. `npm run dev` and tell the designer to check their browser
65
+
66
+ ## System Design (Invisible)
67
+
68
+ When the designer describes their idea, internally decompose into building blocks. NEVER show this as a technical diagram. Show it as the flow map above.
69
+
70
+ Internal mapping (you think this, they never see it):
71
+ ```
72
+ Story element → Building block → Skill to invoke later
73
+ "people can book" → Form + database → save-data
74
+ "only I can see bookings" → Auth + protected page → add-login
75
+ "get notified" → Email integration → send-email
76
+ "upload photos" → File storage → upload-file
77
+ "show all bookings" → Data display → show-data
78
+ ```
79
+
80
+ ## Scope Control
81
+
82
+ If they describe many features, prioritize without blocking:
83
+
84
+ ```
85
+ 📍 You've described a few features. Here's what I'd suggest:
86
+
87
+ 🟢 BUILD FIRST (gets you live fastest):
88
+ 1. [Core visible page]
89
+ 2. [Primary action / form]
90
+
91
+ 🟡 ADD NEXT (once the core works):
92
+ 3. [Secondary feature]
93
+ 4. [Another feature]
94
+
95
+ 🔵 LATER (nice to have):
96
+ 5. [Extra feature]
97
+
98
+ The first 2 could be working in 15 minutes. Start there?
99
+ ```
100
+
101
+ Never enforce this order. If they say "actually start with #4," start with #4.
102
+
103
+ ## Re-Activation
104
+
105
+ This skill re-activates when the designer says:
106
+ - "I also want to add..."
107
+ - "Can we add a new feature?"
108
+ - "What about adding..."
109
+
110
+ Re-evaluate the flow map, identify new building blocks, integrate without restructuring what exists.
111
+
112
+ ## Project Context File
113
+
114
+ After the first scaffold, auto-generate `.github/project-context.md` so the assistant remembers across sessions:
115
+
116
+ ```markdown
117
+ # Project Context
118
+ - **What:** [Description from designer]
119
+ - **Platform:** web
120
+ - **Stack:** Next.js + Tailwind + Supabase + Vercel
121
+ - **Core flow:** [Visitor arrives] → [Does X] → [Result Y]
122
+ - **Features present:** landing page
123
+ - **Features planned:** [from scope control]
124
+ - **Database tables:** (none yet)
125
+ - **Auth:** not set up
126
+ - **Deploy:** not deployed yet
127
+ ```
128
+
129
+ Update this file whenever a major feature is added.
@@ -0,0 +1,66 @@
1
+ # Platform Routing Reference
2
+
3
+ ## Decision Table
4
+
5
+ | Signal words | Platform | Default stack |
6
+ |---|---|---|
7
+ | website, landing page, portfolio, personal site | Web | Next.js + Tailwind + Supabase + Vercel |
8
+ | web app, tool, SaaS, dashboard, admin | Web | Next.js + Tailwind + Supabase + Vercel |
9
+ | booking, scheduling, appointments | Web | Next.js + Tailwind + Supabase + Vercel |
10
+ | app, iPhone, Android, mobile, phone | Mobile | Expo (React Native) + Supabase + EAS |
11
+ | store, shop, sell, products, e-commerce, marketplace | Shopify | Shopify CLI + Liquid |
12
+ | blog, CMS, content, magazine, news, articles | WordPress | Block themes + WP REST API |
13
+ | Figma plugin, extend Figma, Figma tool | Figma Plugin | TypeScript + Figma Plugin API |
14
+ | email, newsletter, email template | Email | MJML + Resend |
15
+ | desktop app, Mac app, Windows app | Desktop | Electron + Vite + React |
16
+ | art, generative, creative, animation, 3D | Creative | p5.js / Three.js / Canvas |
17
+ | game, interactive, playful | Creative | p5.js / Pixi.js |
18
+ | physical, hardware, Arduino, sensor | Hardware | Python / Arduino C++ |
19
+ | AI tool, automation, script | Utility | Python + API calls |
20
+
21
+ ## Disambiguation
22
+
23
+ If multiple signals conflict, ask ONE question:
24
+
25
+ > "Sounds cool! Quick question — will people use this on their phone, in a browser, or on their desktop?"
26
+
27
+ Do NOT ask about technology choices (React vs Vue, PostgreSQL vs MongoDB). The platform decision determines the stack automatically.
28
+
29
+ ## Per-Platform Scaffold Commands
30
+
31
+ ### Web (Next.js)
32
+ ```bash
33
+ npx create-next-app@latest . --typescript --tailwind --eslint --app --src-dir --import-alias "@/*" --use-npm
34
+ ```
35
+
36
+ ### Mobile (Expo)
37
+ ```bash
38
+ npx create-expo-app@latest . --template tabs
39
+ ```
40
+
41
+ ### Shopify
42
+ ```bash
43
+ npm init @shopify/theme@latest
44
+ ```
45
+
46
+ ### WordPress
47
+ ```bash
48
+ npx @wordpress/create-block@latest theme-starter
49
+ ```
50
+
51
+ ### Email (MJML)
52
+ ```bash
53
+ npm init -y && npm install mjml
54
+ ```
55
+
56
+ ### Desktop (Electron)
57
+ ```bash
58
+ npm create electron-vite@latest . -- --template react-ts
59
+ ```
60
+
61
+ ### Creative (p5.js)
62
+ ```bash
63
+ npm init -y && npm install p5
64
+ ```
65
+
66
+ For v1, only **Web (Next.js)** has full skill support. Other platforms can be scaffolded but won't have outcome skills (save-data, add-login, etc.) customized for them yet.