vibetachyon 1.9.0 → 2.1.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.
- package/dist/mcp-server.js +258 -15
- package/package.json +1 -1
package/dist/mcp-server.js
CHANGED
|
@@ -47,8 +47,148 @@ async function checkSanity() {
|
|
|
47
47
|
throw new Error(`[VIBETACHYON SANITY TRAP] Execution blocked. Agent exceeded ${CALL_LIMIT_PER_SESSION} tool calls in a single session. This prevents infinite loops or excessive API usage. Please restart the CLI if this was intentional.`);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
+
// --- Style Palettes — real CSS values per preset ─────────────────────────
|
|
51
|
+
const STYLE_PALETTES = {
|
|
52
|
+
linear: {
|
|
53
|
+
'--background': '#0a0a0f',
|
|
54
|
+
'--foreground': '#f4f4f5',
|
|
55
|
+
'--primary': '#6366f1',
|
|
56
|
+
'--primary-fg': '#ffffff',
|
|
57
|
+
'--muted': '#1c1c28',
|
|
58
|
+
'--muted-fg': '#8585a8',
|
|
59
|
+
'--border': 'rgba(255,255,255,0.08)',
|
|
60
|
+
'--card': '#111120',
|
|
61
|
+
'--radius': '8px',
|
|
62
|
+
'--font': "'Inter', system-ui, sans-serif",
|
|
63
|
+
'--gradient': 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)',
|
|
64
|
+
'--shadow': '0 1px 3px rgba(0,0,0,0.4)',
|
|
65
|
+
},
|
|
66
|
+
vercel: {
|
|
67
|
+
'--background': '#000000',
|
|
68
|
+
'--foreground': '#ffffff',
|
|
69
|
+
'--primary': '#ffffff',
|
|
70
|
+
'--primary-fg': '#000000',
|
|
71
|
+
'--muted': '#111111',
|
|
72
|
+
'--muted-fg': '#888888',
|
|
73
|
+
'--border': '#333333',
|
|
74
|
+
'--card': '#0a0a0a',
|
|
75
|
+
'--radius': '4px',
|
|
76
|
+
'--font': "'Geist', 'Inter', system-ui, sans-serif",
|
|
77
|
+
'--gradient': 'none',
|
|
78
|
+
'--shadow': '0 0 0 1px #333',
|
|
79
|
+
},
|
|
80
|
+
stripe: {
|
|
81
|
+
'--background': '#ffffff',
|
|
82
|
+
'--foreground': '#0a2540',
|
|
83
|
+
'--primary': '#635bff',
|
|
84
|
+
'--primary-fg': '#ffffff',
|
|
85
|
+
'--muted': '#f6f9fc',
|
|
86
|
+
'--muted-fg': '#425466',
|
|
87
|
+
'--border': '#e3e8ee',
|
|
88
|
+
'--card': '#ffffff',
|
|
89
|
+
'--radius': '6px',
|
|
90
|
+
'--font': "'Sohne', 'Inter', system-ui, sans-serif",
|
|
91
|
+
'--gradient': 'linear-gradient(135deg, #635bff 0%, #0a2540 100%)',
|
|
92
|
+
'--shadow': '0 2px 8px rgba(0,0,0,0.08)',
|
|
93
|
+
},
|
|
94
|
+
notion: {
|
|
95
|
+
'--background': '#ffffff',
|
|
96
|
+
'--foreground': '#37352f',
|
|
97
|
+
'--primary': '#2eaadc',
|
|
98
|
+
'--primary-fg': '#ffffff',
|
|
99
|
+
'--muted': '#f7f6f3',
|
|
100
|
+
'--muted-fg': '#9b9a97',
|
|
101
|
+
'--border': '#e9e9e7',
|
|
102
|
+
'--card': '#ffffff',
|
|
103
|
+
'--radius': '3px',
|
|
104
|
+
'--font': "'ui-sans-serif', 'Inter', system-ui, sans-serif",
|
|
105
|
+
'--gradient': 'none',
|
|
106
|
+
'--shadow': '0 1px 3px rgba(0,0,0,0.07)',
|
|
107
|
+
},
|
|
108
|
+
apple: {
|
|
109
|
+
'--background': '#f5f5f7',
|
|
110
|
+
'--foreground': '#1d1d1f',
|
|
111
|
+
'--primary': '#0066cc',
|
|
112
|
+
'--primary-fg': '#ffffff',
|
|
113
|
+
'--muted': '#e8e8ed',
|
|
114
|
+
'--muted-fg': '#6e6e73',
|
|
115
|
+
'--border': 'rgba(0,0,0,0.1)',
|
|
116
|
+
'--card': '#ffffff',
|
|
117
|
+
'--radius': '12px',
|
|
118
|
+
'--font': "'-apple-system', 'SF Pro Display', 'Inter', sans-serif",
|
|
119
|
+
'--gradient': 'linear-gradient(180deg, #f5f5f7 0%, #e8e8ed 100%)',
|
|
120
|
+
'--shadow': '0 4px 20px rgba(0,0,0,0.08)',
|
|
121
|
+
},
|
|
122
|
+
'bold-dark': {
|
|
123
|
+
'--background': '#060b18',
|
|
124
|
+
'--foreground': '#e2e8f0',
|
|
125
|
+
'--primary': '#06b6d4',
|
|
126
|
+
'--primary-fg': '#000000',
|
|
127
|
+
'--muted': '#0f1d2e',
|
|
128
|
+
'--muted-fg': '#94a3b8',
|
|
129
|
+
'--border': 'rgba(6,182,212,0.15)',
|
|
130
|
+
'--card': '#0d1a2e',
|
|
131
|
+
'--radius': '10px',
|
|
132
|
+
'--font': "'Inter', system-ui, sans-serif",
|
|
133
|
+
'--gradient': 'linear-gradient(135deg, #06b6d4 0%, #3b82f6 100%)',
|
|
134
|
+
'--shadow': '0 4px 24px rgba(6,182,212,0.15)',
|
|
135
|
+
},
|
|
136
|
+
agency: {
|
|
137
|
+
'--background': '#0f0f0f',
|
|
138
|
+
'--foreground': '#ffffff',
|
|
139
|
+
'--primary': '#ff6b35',
|
|
140
|
+
'--primary-fg': '#ffffff',
|
|
141
|
+
'--muted': '#1a1a1a',
|
|
142
|
+
'--muted-fg': '#999999',
|
|
143
|
+
'--border': 'rgba(255,107,53,0.2)',
|
|
144
|
+
'--card': '#1a1a1a',
|
|
145
|
+
'--radius': '2px',
|
|
146
|
+
'--font': "'Space Grotesk', 'Inter', system-ui, sans-serif",
|
|
147
|
+
'--gradient': 'linear-gradient(135deg, #ff6b35 0%, #f7c59f 100%)',
|
|
148
|
+
'--shadow': '0 4px 20px rgba(255,107,53,0.2)',
|
|
149
|
+
},
|
|
150
|
+
aceternity: {
|
|
151
|
+
'--background': '#000000',
|
|
152
|
+
'--foreground': '#ffffff',
|
|
153
|
+
'--primary': '#a855f7',
|
|
154
|
+
'--primary-fg': '#ffffff',
|
|
155
|
+
'--muted': '#0a0a0a',
|
|
156
|
+
'--muted-fg': '#71717a',
|
|
157
|
+
'--border': 'rgba(168,85,247,0.2)',
|
|
158
|
+
'--card': '#0a0a0a',
|
|
159
|
+
'--radius': '16px',
|
|
160
|
+
'--font': "'Inter', system-ui, sans-serif",
|
|
161
|
+
'--gradient': 'linear-gradient(135deg, #a855f7 0%, #6366f1 50%, #ec4899 100%)',
|
|
162
|
+
'--shadow': '0 0 40px rgba(168,85,247,0.25)',
|
|
163
|
+
},
|
|
164
|
+
custom: {
|
|
165
|
+
'--background': 'var(--background, #ffffff)',
|
|
166
|
+
'--foreground': 'var(--foreground, #000000)',
|
|
167
|
+
'--primary': 'var(--primary, #3b82f6)',
|
|
168
|
+
'--primary-fg': 'var(--primary-fg, #ffffff)',
|
|
169
|
+
'--muted': 'var(--muted, #f4f4f5)',
|
|
170
|
+
'--muted-fg': 'var(--muted-fg, #71717a)',
|
|
171
|
+
'--border': 'var(--border, #e4e4e7)',
|
|
172
|
+
'--card': 'var(--card, #ffffff)',
|
|
173
|
+
'--radius': 'var(--radius, 8px)',
|
|
174
|
+
'--font': "var(--font-sans, 'Inter', sans-serif)",
|
|
175
|
+
'--gradient': 'none',
|
|
176
|
+
'--shadow': '0 1px 3px rgba(0,0,0,0.1)',
|
|
177
|
+
},
|
|
178
|
+
};
|
|
50
179
|
// --- Changelog (per version) ---
|
|
51
180
|
const CHANGELOG = {
|
|
181
|
+
'2.1.0': [
|
|
182
|
+
'Fix: vibe_compose_landing_page detecta framework (Next.js/Vite) automaticamente',
|
|
183
|
+
'Fix: output sempre .tsx React, nunca index.html',
|
|
184
|
+
'Instruções explícitas de conversão HTML→JSX (class→className, useEffect)',
|
|
185
|
+
'Detecta src/app vs app para outputTarget correto',
|
|
186
|
+
],
|
|
187
|
+
'2.0.0': [
|
|
188
|
+
'8 presets visuais reais: linear, vercel, stripe, bold-dark, agency...',
|
|
189
|
+
'Paletas CSS aplicadas automaticamente — sem mais neon hardcoded',
|
|
190
|
+
'vibe_compose_landing_page lê o brief e injeta cores corretas',
|
|
191
|
+
],
|
|
52
192
|
'1.9.0': [
|
|
53
193
|
'vibe_clone_design — clone design system de qualquer URL',
|
|
54
194
|
'Detecta cores, tipografia, radius e sombras automaticamente',
|
|
@@ -203,7 +343,7 @@ async function validateTokenAtStartup() {
|
|
|
203
343
|
}
|
|
204
344
|
// --- Update Check ---
|
|
205
345
|
try {
|
|
206
|
-
const CURRENT_VERSION = '
|
|
346
|
+
const CURRENT_VERSION = '2.0.0'; // keep in sync with package.json
|
|
207
347
|
const npmRes = await fetch('https://registry.npmjs.org/vibetachyon/latest', {
|
|
208
348
|
signal: AbortSignal.timeout(4000)
|
|
209
349
|
});
|
|
@@ -232,7 +372,7 @@ async function startMcpServer() {
|
|
|
232
372
|
await validateTokenAtStartup();
|
|
233
373
|
const server = new mcp_js_1.McpServer({
|
|
234
374
|
name: "VibeTachyon MCP — Animmaster Engine",
|
|
235
|
-
version: "
|
|
375
|
+
version: "2.0.0"
|
|
236
376
|
});
|
|
237
377
|
/**
|
|
238
378
|
* VIBETACHYON FRONTEND PERSONA — Senior Frontend Designer (Animmaster Engine)
|
|
@@ -981,7 +1121,7 @@ COMPONENT SELECTION FILTER (apply mentally before using any component):
|
|
|
981
1121
|
niche: zod_1.z.string().describe("What is the product niche? e.g. 'B2B SaaS fintech', 'developer tool', 'e-commerce fashion'"),
|
|
982
1122
|
targetAudience: zod_1.z.string().describe("Who is the target user? e.g. 'CTO of early-stage startup', 'solo developer', 'non-technical founder'"),
|
|
983
1123
|
styleWords: zod_1.z.array(zod_1.z.string()).describe("3 adjectives that describe the desired visual style. e.g. ['clean', 'modern', 'trustworthy'] or ['bold', 'dark', 'animated']"),
|
|
984
|
-
referenceStyle: zod_1.z.enum(['linear', 'vercel', 'stripe', 'aceternity', 'apple', 'notion', 'custom']).describe("
|
|
1124
|
+
referenceStyle: zod_1.z.enum(['linear', 'vercel', 'stripe', 'aceternity', 'apple', 'notion', 'bold-dark', 'agency', 'custom']).describe("Visual preset: 'linear'=dark minimal indigo, 'vercel'=black/white terminal, 'stripe'=light professional, 'notion'=clean editorial, 'apple'=light cinematic, 'bold-dark'=dark navy cyan, 'agency'=dark orange dramatic, 'aceternity'=dark glowing purple, 'custom'=use project CSS vars"),
|
|
985
1125
|
sectionsNeeded: zod_1.z.array(zod_1.z.string()).describe("Which page sections are needed in order. e.g. ['hero', 'features', 'social-proof', 'pricing', 'faq', 'cta']")
|
|
986
1126
|
}, async ({ projectDir, pageGoal, niche, targetAudience, styleWords, referenceStyle, sectionsNeeded }) => {
|
|
987
1127
|
await checkSanity();
|
|
@@ -1064,6 +1204,10 @@ COMPONENT SELECTION FILTER (apply mentally before using any component):
|
|
|
1064
1204
|
if (sectionsNeeded.includes('pricing') && !sectionsNeeded.includes('social-proof') && !sectionsNeeded.includes('testimonials')) {
|
|
1065
1205
|
sectionWarnings.push('⚠️ Pricing without social proof reduces trust — consider adding testimonials before pricing.');
|
|
1066
1206
|
}
|
|
1207
|
+
const palette = STYLE_PALETTES[referenceStyle] || STYLE_PALETTES.custom;
|
|
1208
|
+
const paletteCSS = Object.entries(palette)
|
|
1209
|
+
.map(([k, v]) => ` ${k}: ${v};`)
|
|
1210
|
+
.join('\n');
|
|
1067
1211
|
const brief = {
|
|
1068
1212
|
createdAt: new Date().toISOString(),
|
|
1069
1213
|
pageGoal,
|
|
@@ -1072,6 +1216,8 @@ COMPONENT SELECTION FILTER (apply mentally before using any component):
|
|
|
1072
1216
|
styleWords,
|
|
1073
1217
|
referenceStyle,
|
|
1074
1218
|
sectionsNeeded,
|
|
1219
|
+
palette,
|
|
1220
|
+
paletteCSS: `:root {\n${paletteCSS}\n}`,
|
|
1075
1221
|
styleProfile: profile,
|
|
1076
1222
|
rules: {
|
|
1077
1223
|
maxAnimationTypes: profile.animationLevel === 'heavy' ? 3 : profile.animationLevel === 'subtle' ? 2 : 0,
|
|
@@ -1117,14 +1263,17 @@ COMPONENT SELECTION FILTER (apply mentally before using any component):
|
|
|
1117
1263
|
`DESIGN RULES:\n${rulesText}\n\n` +
|
|
1118
1264
|
`SECTION SEQUENCE:\n${sectionsText}` +
|
|
1119
1265
|
`${warningsText}\n\n` +
|
|
1266
|
+
`COLOR PALETTE (USE THESE EXACT VALUES — NO EXCEPTIONS):\n` +
|
|
1267
|
+
`\`\`\`css\n${brief.paletteCSS}\n\`\`\`\n\n` +
|
|
1120
1268
|
`INSTRUCTION FOR AI — CRITICAL RULES FOR THIS SESSION:\n` +
|
|
1121
|
-
`1.
|
|
1122
|
-
`2.
|
|
1123
|
-
`3.
|
|
1124
|
-
`4.
|
|
1125
|
-
`5.
|
|
1126
|
-
`6.
|
|
1127
|
-
`7.
|
|
1269
|
+
`1. ALWAYS inject the CSS palette above as the FIRST thing inside <style> when generating HTML\n` +
|
|
1270
|
+
`2. NEVER hardcode colors like #7c3aed, #a855f7, #ec4899 — use ONLY the CSS vars above\n` +
|
|
1271
|
+
`3. Every component you choose MUST match the "${referenceStyle}" reference style\n` +
|
|
1272
|
+
`4. Visual tone is "${profile.tone}" — ${profile.tone === 'dark' ? 'dark backgrounds, light text' : profile.tone === 'light' ? 'light backgrounds, dark text' : 'adapt to project'}\n` +
|
|
1273
|
+
`5. MAXIMUM ${brief.rules.maxAnimationTypes} different animation styles on the entire page\n` +
|
|
1274
|
+
`6. NEVER use these: ${profile.avoid.join(', ')}\n` +
|
|
1275
|
+
`7. Build sections in this EXACT order: ${sectionsNeeded.join(' → ')}\n` +
|
|
1276
|
+
`8. If a component does NOT match this brief, REJECT it and search again`
|
|
1128
1277
|
}]
|
|
1129
1278
|
};
|
|
1130
1279
|
});
|
|
@@ -1566,11 +1715,69 @@ COMPONENT SELECTION FILTER (apply mentally before using any component):
|
|
|
1566
1715
|
}
|
|
1567
1716
|
});
|
|
1568
1717
|
// Tool: Compose Landing Page
|
|
1569
|
-
server.tool("vibe_compose_landing_page", "Macro-composer that autonomously queries the VibeCodes RAG database for a full Landing Page structure (Navbar, Hero, Features, Pricing, Footer).", {
|
|
1570
|
-
themeOrIndustry: zod_1.z.string().describe("The theme, industry, or style of the page (e.g., 'SaaS Finance
|
|
1571
|
-
|
|
1718
|
+
server.tool("vibe_compose_landing_page", "Macro-composer that autonomously queries the VibeCodes RAG database for a full Landing Page structure (Navbar, Hero, Features, Pricing, Footer). ALWAYS call vibe_design_brief first — this tool reads the saved brief to apply the correct color palette. OUTPUT: Always generates Next.js TSX React components (never index.html). For Next.js projects, saves to src/app/page.tsx or app/page.tsx. Convert all HTML templates to JSX (class→className, style={{}} etc).", {
|
|
1719
|
+
themeOrIndustry: zod_1.z.string().describe("The theme, industry, or style of the page (e.g., 'SaaS Finance', 'Dental Clinic', 'Developer Tool')"),
|
|
1720
|
+
projectDir: zod_1.z.string().optional().describe("Absolute path to the project root. Used to read the design brief.")
|
|
1721
|
+
}, async ({ themeOrIndustry, projectDir }) => {
|
|
1572
1722
|
await checkSanity();
|
|
1573
1723
|
try {
|
|
1724
|
+
// Read design brief for palette injection
|
|
1725
|
+
let paletteCSS = '';
|
|
1726
|
+
let briefStyle = 'linear';
|
|
1727
|
+
let briefTone = 'dark';
|
|
1728
|
+
let briefAvoid = [];
|
|
1729
|
+
const cwd = projectDir || process.cwd();
|
|
1730
|
+
const root = await findProjectRoot(cwd);
|
|
1731
|
+
// Detect framework for output instructions
|
|
1732
|
+
let framework = 'unknown';
|
|
1733
|
+
let outputTarget = '';
|
|
1734
|
+
const pkgPath = path_1.default.join(root, 'package.json');
|
|
1735
|
+
if (await fs_extra_1.default.pathExists(pkgPath)) {
|
|
1736
|
+
try {
|
|
1737
|
+
const pkg = await fs_extra_1.default.readJson(pkgPath);
|
|
1738
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
1739
|
+
if (deps['next']) {
|
|
1740
|
+
framework = 'nextjs';
|
|
1741
|
+
const hasAppSrc = await fs_extra_1.default.pathExists(path_1.default.join(root, 'src', 'app'));
|
|
1742
|
+
const hasApp = await fs_extra_1.default.pathExists(path_1.default.join(root, 'app'));
|
|
1743
|
+
if (hasAppSrc)
|
|
1744
|
+
outputTarget = 'src/app/page.tsx';
|
|
1745
|
+
else if (hasApp)
|
|
1746
|
+
outputTarget = 'app/page.tsx';
|
|
1747
|
+
else
|
|
1748
|
+
outputTarget = 'src/app/page.tsx';
|
|
1749
|
+
}
|
|
1750
|
+
else if (deps['vite'] || deps['react']) {
|
|
1751
|
+
framework = 'vite';
|
|
1752
|
+
outputTarget = 'src/App.tsx';
|
|
1753
|
+
}
|
|
1754
|
+
else if (deps['nuxt']) {
|
|
1755
|
+
framework = 'nuxt';
|
|
1756
|
+
outputTarget = 'pages/index.vue';
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
catch { /* ignore */ }
|
|
1760
|
+
}
|
|
1761
|
+
const briefPath = path_1.default.join(root, '.vibetachyon', 'design-session.json');
|
|
1762
|
+
if (await fs_extra_1.default.pathExists(briefPath)) {
|
|
1763
|
+
try {
|
|
1764
|
+
const brief = await fs_extra_1.default.readJson(briefPath);
|
|
1765
|
+
if (brief.paletteCSS)
|
|
1766
|
+
paletteCSS = brief.paletteCSS;
|
|
1767
|
+
if (brief.referenceStyle)
|
|
1768
|
+
briefStyle = brief.referenceStyle;
|
|
1769
|
+
if (brief.styleProfile?.tone)
|
|
1770
|
+
briefTone = brief.styleProfile.tone;
|
|
1771
|
+
if (brief.rules?.mustAvoid)
|
|
1772
|
+
briefAvoid = brief.rules.mustAvoid;
|
|
1773
|
+
}
|
|
1774
|
+
catch { /* use defaults */ }
|
|
1775
|
+
}
|
|
1776
|
+
// Fallback: use linear palette if no brief
|
|
1777
|
+
if (!paletteCSS) {
|
|
1778
|
+
const fallbackPalette = STYLE_PALETTES[briefStyle] || STYLE_PALETTES.linear;
|
|
1779
|
+
paletteCSS = `:root {\n${Object.entries(fallbackPalette).map(([k, v]) => ` ${k}: ${v};`).join('\n')}\n}`;
|
|
1780
|
+
}
|
|
1574
1781
|
// Map sections to Animmaster use cases and search terms
|
|
1575
1782
|
const sectionMap = [
|
|
1576
1783
|
{ section: 'preloader', query: 'preloader', useCase: 'preloader' },
|
|
@@ -1580,7 +1787,37 @@ COMPONENT SELECTION FILTER (apply mentally before using any component):
|
|
|
1580
1787
|
{ section: 'features', query: 'features section', useCase: 'feature-section' },
|
|
1581
1788
|
{ section: 'footer', query: 'footer', useCase: 'footer' }
|
|
1582
1789
|
];
|
|
1583
|
-
let combinedPage = `[🎬 ANIMMASTER PAGE COMPOSER: ${themeOrIndustry}]\n
|
|
1790
|
+
let combinedPage = `[🎬 ANIMMASTER PAGE COMPOSER: ${themeOrIndustry}]\n`;
|
|
1791
|
+
combinedPage += `Style: ${briefStyle} | Tone: ${briefTone}\n\n`;
|
|
1792
|
+
// Framework-aware output instructions
|
|
1793
|
+
combinedPage += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`;
|
|
1794
|
+
combinedPage += `📁 OUTPUT TARGET: ${outputTarget || 'src/app/page.tsx'}\n`;
|
|
1795
|
+
combinedPage += `🚨 NEVER create index.html — this is a ${framework === 'nextjs' ? 'Next.js' : framework === 'vite' ? 'React/Vite' : 'React'} project\n`;
|
|
1796
|
+
combinedPage += `🚨 ALL output MUST be .tsx React components, NOT plain HTML files\n`;
|
|
1797
|
+
if (framework === 'nextjs') {
|
|
1798
|
+
combinedPage += `\n📋 NEXTJS TSX RULES:\n`;
|
|
1799
|
+
combinedPage += ` • Convert all HTML → JSX: class→className, for→htmlFor, style={{}}\n`;
|
|
1800
|
+
combinedPage += ` • Add "use client" directive at top if using animations/events\n`;
|
|
1801
|
+
combinedPage += ` • Inline scripts → useEffect(() => { /* JS here */ }, [])\n`;
|
|
1802
|
+
combinedPage += ` • External CDN scripts → use next/script: <Script src="..." strategy="afterInteractive" />\n`;
|
|
1803
|
+
combinedPage += ` • Self-closing tags: <img />, <br />, <input />\n`;
|
|
1804
|
+
combinedPage += ` • Create each section as a separate component in src/components/\n`;
|
|
1805
|
+
combinedPage += ` • Page file: export default function Page() { return (<main>...</main>) }\n`;
|
|
1806
|
+
}
|
|
1807
|
+
else if (framework === 'vite') {
|
|
1808
|
+
combinedPage += `\n📋 VITE/REACT TSX RULES:\n`;
|
|
1809
|
+
combinedPage += ` • Convert HTML → JSX: class→className, for→htmlFor\n`;
|
|
1810
|
+
combinedPage += ` • Inline scripts → useEffect with cleanup\n`;
|
|
1811
|
+
combinedPage += ` • Add React imports at top\n`;
|
|
1812
|
+
}
|
|
1813
|
+
combinedPage += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n`;
|
|
1814
|
+
combinedPage += `⚠️ MANDATORY COLOR RULES — INJECT THIS PALETTE IN globals.css:\n\`\`\`css\n${paletteCSS}\n\`\`\`\n\n`;
|
|
1815
|
+
combinedPage += `CRITICAL: Use ONLY var(--background), var(--primary), var(--foreground), var(--border), var(--card) etc.\n`;
|
|
1816
|
+
combinedPage += `NEVER hardcode hex colors. NEVER use purple/neon unless --primary IS purple in the palette above.\n`;
|
|
1817
|
+
if (briefAvoid.length > 0)
|
|
1818
|
+
combinedPage += `AVOID: ${briefAvoid.join(', ')}\n`;
|
|
1819
|
+
combinedPage += `\nINSTRUCTION FOR AI: Assemble a complete page using Animmaster components in init_order sequence.\n`;
|
|
1820
|
+
combinedPage += `Convert ALL HTML templates below to JSX. Initialize JS in useEffect hooks.\n\n`;
|
|
1584
1821
|
const allComponents = [];
|
|
1585
1822
|
for (const { section, query, useCase } of sectionMap) {
|
|
1586
1823
|
const { data } = await supabase
|
|
@@ -1615,7 +1852,13 @@ COMPONENT SELECTION FILTER (apply mentally before using any component):
|
|
|
1615
1852
|
}
|
|
1616
1853
|
const totalBudget = allComponents.reduce((sum, c) => sum + (c.animation_budget || 0), 0);
|
|
1617
1854
|
combinedPage += `\n---\nTotal animation budget: ${totalBudget}/30 | Components: ${allComponents.length}\n`;
|
|
1618
|
-
combinedPage += `\
|
|
1855
|
+
combinedPage += `\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`;
|
|
1856
|
+
combinedPage += `FINAL INSTRUCTION:\n`;
|
|
1857
|
+
combinedPage += `1. Initialize components in init_order sequence (preloader → cursor → header → effects)\n`;
|
|
1858
|
+
combinedPage += `2. Save the page to: ${outputTarget || 'src/app/page.tsx'}\n`;
|
|
1859
|
+
combinedPage += `3. ${framework === 'nextjs' ? 'Add "use client" at top, convert all HTML to JSX (class→className)' : 'Convert HTML to JSX React components'}\n`;
|
|
1860
|
+
combinedPage += `4. NEVER create index.html — always .tsx files only\n`;
|
|
1861
|
+
combinedPage += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`;
|
|
1619
1862
|
return { content: [{ type: "text", text: combinedPage }] };
|
|
1620
1863
|
}
|
|
1621
1864
|
catch (err) {
|