@triedotdev/mcp 1.0.32 → 1.0.34
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/README.md +230 -98
- package/dist/{chunk-3724RQC3.js → chunk-3NXWEJUV.js} +518 -14
- package/dist/chunk-3NXWEJUV.js.map +1 -0
- package/dist/{chunk-B6MTR6IG.js → chunk-FPISHSPT.js} +2 -2
- package/dist/cli/yolo-daemon.js +2 -2
- package/dist/index.js +145 -95
- package/dist/index.js.map +1 -1
- package/dist/workers/agent-worker.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-3724RQC3.js.map +0 -1
- /package/dist/{chunk-B6MTR6IG.js.map → chunk-FPISHSPT.js.map} +0 -0
|
@@ -1074,19 +1074,121 @@ Output STRICT JSON:
|
|
|
1074
1074
|
};
|
|
1075
1075
|
|
|
1076
1076
|
// src/agents/design-engineer.ts
|
|
1077
|
+
var AI_SLOP_COLORS = [
|
|
1078
|
+
// Neon/toxic greens (AI loves these for "success")
|
|
1079
|
+
{ pattern: /#[0-4][eEfF][0-5][0-4][0-2][0-4]/i, name: "toxic neon green", suggestion: "emerald-500 (#10b981) or green-600 (#16a34a)" },
|
|
1080
|
+
{ pattern: /#00[fF][fF]00/i, name: "pure lime green", suggestion: "emerald-400 (#34d399) for a modern SaaS look" },
|
|
1081
|
+
{ pattern: /#[0-3][fF][fF][0-3][fF][0-3]/i, name: "cyan-green neon", suggestion: "teal-500 (#14b8a6) for sophistication" },
|
|
1082
|
+
// Garish purples/magentas
|
|
1083
|
+
{ pattern: /#[fF][0-3][0-5][fF][0-3][fF]/i, name: "hot magenta", suggestion: "fuchsia-500 (#d946ef) or violet-500 (#8b5cf6)" },
|
|
1084
|
+
{ pattern: /#[8-9aA][0-3][0-3][fF][fF][fF]/i, name: "electric purple", suggestion: "indigo-500 (#6366f1) for a Stripe-like feel" },
|
|
1085
|
+
// Oversaturated blues
|
|
1086
|
+
{ pattern: /#00[0-5][0-5][fF][fF]/i, name: "electric blue", suggestion: "blue-600 (#2563eb) or sky-500 (#0ea5e9)" },
|
|
1087
|
+
{ pattern: /#0{4}[fF]{2}/i, name: "pure blue", suggestion: "blue-500 (#3b82f6) for modern SaaS" },
|
|
1088
|
+
// Harsh reds
|
|
1089
|
+
{ pattern: /#[fF][fF]0{4}/i, name: "pure red", suggestion: "rose-500 (#f43f5e) or red-500 (#ef4444)" },
|
|
1090
|
+
{ pattern: /#[fF][0-3][0-3][0-3][0-3][0-3]/i, name: "harsh red", suggestion: "rose-600 (#e11d48) for errors, or softer coral (#fb7185)" },
|
|
1091
|
+
// Dated yellows/oranges
|
|
1092
|
+
{ pattern: /#[fF][fF][fF][fF]00/i, name: "pure yellow", suggestion: "amber-400 (#fbbf24) or yellow-500 (#eab308)" },
|
|
1093
|
+
{ pattern: /#[fF][fF][aA-fF]000/i, name: "orange-yellow", suggestion: "amber-500 (#f59e0b) for warnings" },
|
|
1094
|
+
// Gray issues
|
|
1095
|
+
{ pattern: /#[8-9][8-9][8-9][8-9][8-9][8-9]/i, name: "flat mid-gray", suggestion: "slate-400 (#94a3b8) or zinc-500 (#71717a) for depth" },
|
|
1096
|
+
{ pattern: /#[cC][cC][cC][cC][cC][cC]/i, name: "washed-out gray", suggestion: "slate-300 (#cbd5e1) or neutral-300 (#d4d4d4)" }
|
|
1097
|
+
];
|
|
1098
|
+
var MODERN_PALETTES = {
|
|
1099
|
+
// Dark mode palettes (most popular on Awwwards)
|
|
1100
|
+
vercel: {
|
|
1101
|
+
name: "Vercel/Next.js",
|
|
1102
|
+
bg: "#000000",
|
|
1103
|
+
surface: "#111111",
|
|
1104
|
+
border: "#333333",
|
|
1105
|
+
text: "#ededed",
|
|
1106
|
+
muted: "#888888",
|
|
1107
|
+
accent: "#0070f3"
|
|
1108
|
+
},
|
|
1109
|
+
linear: {
|
|
1110
|
+
name: "Linear",
|
|
1111
|
+
bg: "#000212",
|
|
1112
|
+
surface: "#0a0a1a",
|
|
1113
|
+
border: "#1a1a2e",
|
|
1114
|
+
text: "#f7f8f8",
|
|
1115
|
+
muted: "#8f9ba8",
|
|
1116
|
+
accent: "#5e6ad2"
|
|
1117
|
+
},
|
|
1118
|
+
stripe: {
|
|
1119
|
+
name: "Stripe",
|
|
1120
|
+
bg: "#0a2540",
|
|
1121
|
+
surface: "#0d3358",
|
|
1122
|
+
border: "#1a4a70",
|
|
1123
|
+
text: "#ffffff",
|
|
1124
|
+
muted: "#adbdcc",
|
|
1125
|
+
accent: "#635bff"
|
|
1126
|
+
},
|
|
1127
|
+
// Light mode palettes
|
|
1128
|
+
notion: {
|
|
1129
|
+
name: "Notion",
|
|
1130
|
+
bg: "#ffffff",
|
|
1131
|
+
surface: "#f7f6f3",
|
|
1132
|
+
border: "#e3e2de",
|
|
1133
|
+
text: "#37352f",
|
|
1134
|
+
muted: "#9b9a97",
|
|
1135
|
+
accent: "#2eaadc"
|
|
1136
|
+
},
|
|
1137
|
+
figma: {
|
|
1138
|
+
name: "Figma",
|
|
1139
|
+
bg: "#ffffff",
|
|
1140
|
+
surface: "#f5f5f5",
|
|
1141
|
+
border: "#e5e5e5",
|
|
1142
|
+
text: "#1e1e1e",
|
|
1143
|
+
muted: "#8c8c8c",
|
|
1144
|
+
accent: "#0d99ff"
|
|
1145
|
+
},
|
|
1146
|
+
framer: {
|
|
1147
|
+
name: "Framer",
|
|
1148
|
+
bg: "#ffffff",
|
|
1149
|
+
surface: "#fafafa",
|
|
1150
|
+
border: "#ebebeb",
|
|
1151
|
+
text: "#171717",
|
|
1152
|
+
muted: "#666666",
|
|
1153
|
+
accent: "#0055ff"
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
var PROJECT_CONTEXTS = {
|
|
1157
|
+
marketing: {
|
|
1158
|
+
patterns: [/landing|hero|pricing|features|testimonial|cta|homepage/i, /marketing|campaign|launch/i],
|
|
1159
|
+
effects: ["3D product showcases", "scroll-triggered reveals", "parallax sections", "text animations", "gradient meshes"]
|
|
1160
|
+
},
|
|
1161
|
+
dashboard: {
|
|
1162
|
+
patterns: [/dashboard|admin|analytics|settings|sidebar|table|chart/i],
|
|
1163
|
+
effects: ["subtle micro-interactions", "skeleton loaders", "toast animations", "chart transitions"]
|
|
1164
|
+
},
|
|
1165
|
+
ecommerce: {
|
|
1166
|
+
patterns: [/product|cart|checkout|shop|store|catalog/i],
|
|
1167
|
+
effects: ["image zoom", "add-to-cart animations", "filter transitions", "product card hovers"]
|
|
1168
|
+
},
|
|
1169
|
+
portfolio: {
|
|
1170
|
+
patterns: [/portfolio|gallery|showcase|project|work|case-study/i],
|
|
1171
|
+
effects: ["image reveals", "cursor effects", "page transitions", "scroll-linked galleries"]
|
|
1172
|
+
}
|
|
1173
|
+
};
|
|
1077
1174
|
var DesignEngineerAgent = class extends BaseAgent {
|
|
1078
1175
|
name = "design-engineer";
|
|
1079
|
-
description = "Award-winning frontend craft: design systems, motion design, creative CSS, Awwwards-level polish";
|
|
1080
|
-
version = "
|
|
1176
|
+
description = "Award-winning frontend craft: design systems, motion design, creative CSS, modern color palettes, Awwwards-level polish";
|
|
1177
|
+
version = "2.0.0";
|
|
1081
1178
|
shouldActivate(context) {
|
|
1082
1179
|
return context.touchesUI;
|
|
1083
1180
|
}
|
|
1084
1181
|
async analyzeFiles(files, _context) {
|
|
1085
1182
|
const issues = [];
|
|
1183
|
+
const allContent = await this.getAllContent(files);
|
|
1184
|
+
const projectContext = this.detectProjectContext(allContent);
|
|
1185
|
+
const hasMotionLibrary = this.detectMotionLibraries(allContent);
|
|
1086
1186
|
for (const file of files) {
|
|
1087
1187
|
try {
|
|
1088
1188
|
const content = await this.readFile(file);
|
|
1089
1189
|
if (this.isFrontendFile(file)) {
|
|
1190
|
+
issues.push(...this.analyzeColorPalette(content, file));
|
|
1191
|
+
issues.push(...this.analyzeMotionLibraries(content, file, hasMotionLibrary, projectContext));
|
|
1090
1192
|
issues.push(...this.analyzeDesignSystem(content, file));
|
|
1091
1193
|
issues.push(...this.analyzeMotionDesign(content, file));
|
|
1092
1194
|
issues.push(...this.analyzeVisualCraft(content, file));
|
|
@@ -1099,9 +1201,340 @@ var DesignEngineerAgent = class extends BaseAgent {
|
|
|
1099
1201
|
}
|
|
1100
1202
|
return issues;
|
|
1101
1203
|
}
|
|
1204
|
+
/**
|
|
1205
|
+
* Get all content from files for context detection
|
|
1206
|
+
*/
|
|
1207
|
+
async getAllContent(files) {
|
|
1208
|
+
const contents = [];
|
|
1209
|
+
for (const file of files.slice(0, 20)) {
|
|
1210
|
+
try {
|
|
1211
|
+
const content = await this.readFile(file);
|
|
1212
|
+
contents.push(content);
|
|
1213
|
+
} catch {
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
return contents.join("\n");
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Detect project context (marketing, dashboard, ecommerce, portfolio)
|
|
1220
|
+
*/
|
|
1221
|
+
detectProjectContext(content) {
|
|
1222
|
+
for (const [context, config] of Object.entries(PROJECT_CONTEXTS)) {
|
|
1223
|
+
for (const pattern of config.patterns) {
|
|
1224
|
+
if (pattern.test(content)) {
|
|
1225
|
+
return context;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
return "general";
|
|
1230
|
+
}
|
|
1231
|
+
/**
|
|
1232
|
+
* Detect which motion libraries are already installed
|
|
1233
|
+
*/
|
|
1234
|
+
detectMotionLibraries(content) {
|
|
1235
|
+
const detected = /* @__PURE__ */ new Set();
|
|
1236
|
+
if (/framer-motion|from ['"]framer-motion['"]/.test(content)) detected.add("framer-motion");
|
|
1237
|
+
if (/gsap|from ['"]gsap['"]/.test(content)) detected.add("gsap");
|
|
1238
|
+
if (/@react-three\/fiber|from ['"]@react-three\/fiber['"]/.test(content)) detected.add("three");
|
|
1239
|
+
if (/lenis|locomotive-scroll/.test(content)) detected.add("scroll");
|
|
1240
|
+
if (/react-spring|@react-spring/.test(content)) detected.add("react-spring");
|
|
1241
|
+
if (/auto-animate|@formkit\/auto-animate/.test(content)) detected.add("auto-animate");
|
|
1242
|
+
return detected;
|
|
1243
|
+
}
|
|
1102
1244
|
isFrontendFile(file) {
|
|
1103
1245
|
return /\.(tsx|jsx|vue|svelte|astro|css|scss|sass|less|styled\.(ts|js))$/.test(file);
|
|
1104
1246
|
}
|
|
1247
|
+
/**
|
|
1248
|
+
* Analyze color palette for AI slop and suggest modern alternatives
|
|
1249
|
+
* Inspired by top SaaS sites: Linear, Vercel, Stripe, Notion, Figma, Framer
|
|
1250
|
+
*/
|
|
1251
|
+
analyzeColorPalette(content, file) {
|
|
1252
|
+
const issues = [];
|
|
1253
|
+
const lines = content.split("\n");
|
|
1254
|
+
const colorsFound = [];
|
|
1255
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1256
|
+
const line = lines[i];
|
|
1257
|
+
const lineNumber = i + 1;
|
|
1258
|
+
const hexMatches = line.matchAll(/#[0-9a-fA-F]{3,8}\b/g);
|
|
1259
|
+
for (const match of hexMatches) {
|
|
1260
|
+
const hex = match[0].toLowerCase();
|
|
1261
|
+
colorsFound.push({ hex, line: lineNumber });
|
|
1262
|
+
for (const slop of AI_SLOP_COLORS) {
|
|
1263
|
+
if (slop.pattern.test(hex)) {
|
|
1264
|
+
issues.push(this.createIssue(
|
|
1265
|
+
this.generateIssueId(),
|
|
1266
|
+
"moderate",
|
|
1267
|
+
`AI slop color detected: ${slop.name} (${hex})`,
|
|
1268
|
+
`Replace with modern SaaS palette: ${slop.suggestion}. See Linear, Vercel, Stripe for inspiration.`,
|
|
1269
|
+
file,
|
|
1270
|
+
lineNumber,
|
|
1271
|
+
0.85,
|
|
1272
|
+
void 0,
|
|
1273
|
+
true
|
|
1274
|
+
));
|
|
1275
|
+
break;
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
if (/^#(ff0000|00ff00|0000ff|ffff00|ff00ff|00ffff)$/i.test(hex)) {
|
|
1279
|
+
issues.push(this.createIssue(
|
|
1280
|
+
this.generateIssueId(),
|
|
1281
|
+
"serious",
|
|
1282
|
+
`Pure saturated color ${hex} \u2014 looks amateur, not SaaS-ready`,
|
|
1283
|
+
"Use desaturated alternatives. Modern SaaS uses muted, sophisticated colors. Try Tailwind's color palette or Linear's scheme.",
|
|
1284
|
+
file,
|
|
1285
|
+
lineNumber,
|
|
1286
|
+
0.95,
|
|
1287
|
+
void 0,
|
|
1288
|
+
true
|
|
1289
|
+
));
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
if (/linear-gradient|radial-gradient/i.test(line)) {
|
|
1293
|
+
const gradientColors = line.match(/#[0-9a-fA-F]{3,8}/g) || [];
|
|
1294
|
+
if (gradientColors.length >= 3) {
|
|
1295
|
+
const hasSaturated = gradientColors.some(
|
|
1296
|
+
(c) => /^#(ff|00)[0-9a-f]{4}$/i.test(c) || /^#[0-9a-f]{2}(ff|00)[0-9a-f]{2}$/i.test(c)
|
|
1297
|
+
);
|
|
1298
|
+
if (hasSaturated) {
|
|
1299
|
+
issues.push(this.createIssue(
|
|
1300
|
+
this.generateIssueId(),
|
|
1301
|
+
"moderate",
|
|
1302
|
+
"Multi-color gradient with saturated colors \u2014 can look dated or garish",
|
|
1303
|
+
"Modern SaaS uses subtle gradients: 2 colors max, low saturation, or monochromatic. See Stripe's gradient mesh.",
|
|
1304
|
+
file,
|
|
1305
|
+
lineNumber,
|
|
1306
|
+
0.75,
|
|
1307
|
+
void 0,
|
|
1308
|
+
false
|
|
1309
|
+
));
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
if (/#000000|#ffffff/i.test(line) && /color:|background:/i.test(line)) {
|
|
1314
|
+
issues.push(this.createIssue(
|
|
1315
|
+
this.generateIssueId(),
|
|
1316
|
+
"low",
|
|
1317
|
+
"Pure black/white detected \u2014 consider off-black/off-white for sophistication",
|
|
1318
|
+
"Modern SaaS uses near-black (#171717, #0a0a0a) and near-white (#fafafa, #f5f5f5). Pure #000/#fff can feel harsh.",
|
|
1319
|
+
file,
|
|
1320
|
+
lineNumber,
|
|
1321
|
+
0.65,
|
|
1322
|
+
void 0,
|
|
1323
|
+
false
|
|
1324
|
+
));
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
if (colorsFound.length > 5) {
|
|
1328
|
+
const uniqueColors = new Set(colorsFound.map((c) => c.hex));
|
|
1329
|
+
if (uniqueColors.size > 15) {
|
|
1330
|
+
issues.push(this.createIssue(
|
|
1331
|
+
this.generateIssueId(),
|
|
1332
|
+
"moderate",
|
|
1333
|
+
`${uniqueColors.size} unique colors detected \u2014 palette lacks cohesion`,
|
|
1334
|
+
`Modern SaaS uses 5-8 core colors max. Establish a design system with tokens: --color-primary, --color-surface, --color-text, --color-muted, --color-accent. Reference: ${this.getRandomPaletteRecommendation()}`,
|
|
1335
|
+
file,
|
|
1336
|
+
void 0,
|
|
1337
|
+
0.8,
|
|
1338
|
+
void 0,
|
|
1339
|
+
false
|
|
1340
|
+
));
|
|
1341
|
+
}
|
|
1342
|
+
let violetCount = 0;
|
|
1343
|
+
for (const { hex } of colorsFound) {
|
|
1344
|
+
const rgb = this.hexToRgb(hex);
|
|
1345
|
+
if (!rgb) continue;
|
|
1346
|
+
const hue = this.rgbToHue(rgb.r, rgb.g, rgb.b);
|
|
1347
|
+
if (hue >= 250 && hue <= 310) violetCount++;
|
|
1348
|
+
}
|
|
1349
|
+
if (violetCount >= 3 && violetCount / colorsFound.length > 0.35) {
|
|
1350
|
+
issues.push(this.createIssue(
|
|
1351
|
+
this.generateIssueId(),
|
|
1352
|
+
"moderate",
|
|
1353
|
+
"Palette leans heavily on violet/purple \u2014 looks templated/AI-generated",
|
|
1354
|
+
"Use Josef Albers \u201CInteraction of Color\u201D approach: constrain to 1-2 hue families, anchor with neutrals, and build contrast via value/temperature shifts rather than piling on violet gradients.",
|
|
1355
|
+
file,
|
|
1356
|
+
void 0,
|
|
1357
|
+
0.78,
|
|
1358
|
+
void 0,
|
|
1359
|
+
false
|
|
1360
|
+
));
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
return issues;
|
|
1364
|
+
}
|
|
1365
|
+
/**
|
|
1366
|
+
* Convert hex color to RGB
|
|
1367
|
+
*/
|
|
1368
|
+
hexToRgb(hex) {
|
|
1369
|
+
const normalized = hex.replace("#", "");
|
|
1370
|
+
if (normalized.length === 3) {
|
|
1371
|
+
const r = parseInt(normalized[0] + normalized[0], 16);
|
|
1372
|
+
const g = parseInt(normalized[1] + normalized[1], 16);
|
|
1373
|
+
const b = parseInt(normalized[2] + normalized[2], 16);
|
|
1374
|
+
return { r, g, b };
|
|
1375
|
+
}
|
|
1376
|
+
if (normalized.length === 6) {
|
|
1377
|
+
const r = parseInt(normalized.slice(0, 2), 16);
|
|
1378
|
+
const g = parseInt(normalized.slice(2, 4), 16);
|
|
1379
|
+
const b = parseInt(normalized.slice(4, 6), 16);
|
|
1380
|
+
return { r, g, b };
|
|
1381
|
+
}
|
|
1382
|
+
return null;
|
|
1383
|
+
}
|
|
1384
|
+
/**
|
|
1385
|
+
* Calculate hue in degrees from RGB
|
|
1386
|
+
*/
|
|
1387
|
+
rgbToHue(r, g, b) {
|
|
1388
|
+
const rNorm = r / 255;
|
|
1389
|
+
const gNorm = g / 255;
|
|
1390
|
+
const bNorm = b / 255;
|
|
1391
|
+
const max = Math.max(rNorm, gNorm, bNorm);
|
|
1392
|
+
const min = Math.min(rNorm, gNorm, bNorm);
|
|
1393
|
+
const delta = max - min;
|
|
1394
|
+
if (delta === 0) return 0;
|
|
1395
|
+
let hue;
|
|
1396
|
+
switch (max) {
|
|
1397
|
+
case rNorm:
|
|
1398
|
+
hue = (gNorm - bNorm) / delta % 6;
|
|
1399
|
+
break;
|
|
1400
|
+
case gNorm:
|
|
1401
|
+
hue = (bNorm - rNorm) / delta + 2;
|
|
1402
|
+
break;
|
|
1403
|
+
default:
|
|
1404
|
+
hue = (rNorm - gNorm) / delta + 4;
|
|
1405
|
+
break;
|
|
1406
|
+
}
|
|
1407
|
+
hue *= 60;
|
|
1408
|
+
if (hue < 0) hue += 360;
|
|
1409
|
+
return hue;
|
|
1410
|
+
}
|
|
1411
|
+
/**
|
|
1412
|
+
* Get a random modern palette recommendation
|
|
1413
|
+
*/
|
|
1414
|
+
getRandomPaletteRecommendation() {
|
|
1415
|
+
const palettes = Object.values(MODERN_PALETTES);
|
|
1416
|
+
const palette = palettes[Math.floor(Math.random() * palettes.length)];
|
|
1417
|
+
return `${palette.name} palette: bg ${palette.bg}, text ${palette.text}, accent ${palette.accent}`;
|
|
1418
|
+
}
|
|
1419
|
+
/**
|
|
1420
|
+
* Analyze motion library usage and suggest Awwwards-level effects
|
|
1421
|
+
*/
|
|
1422
|
+
analyzeMotionLibraries(content, file, hasLibraries, projectContext) {
|
|
1423
|
+
const issues = [];
|
|
1424
|
+
const isReact = /from ['"]react['"]|import React/.test(content);
|
|
1425
|
+
const hasAnimations = /animation|transition|@keyframes|animate/i.test(content);
|
|
1426
|
+
const purposefulMotionSignals = hasAnimations || /hero|landing|modal|dialog|drawer|toast|tooltip|hover|scroll|parallax|reveal|transition|carousel|slider|gallery/i.test(content);
|
|
1427
|
+
if (!purposefulMotionSignals) {
|
|
1428
|
+
return issues;
|
|
1429
|
+
}
|
|
1430
|
+
if (isReact && !hasLibraries.has("framer-motion") && !hasLibraries.has("react-spring")) {
|
|
1431
|
+
if (/useState.*animation|setAnimation|isAnimating|animationState/i.test(content)) {
|
|
1432
|
+
issues.push(this.createIssue(
|
|
1433
|
+
this.generateIssueId(),
|
|
1434
|
+
"moderate",
|
|
1435
|
+
"Manual animation state management \u2014 use Framer Motion instead",
|
|
1436
|
+
`Install framer-motion for declarative animations: \`npm i framer-motion\`. Replace useState + CSS with <motion.div animate={{ ... }} />. See: https://www.framer.com/motion/`,
|
|
1437
|
+
file,
|
|
1438
|
+
void 0,
|
|
1439
|
+
0.8,
|
|
1440
|
+
void 0,
|
|
1441
|
+
false
|
|
1442
|
+
));
|
|
1443
|
+
}
|
|
1444
|
+
if (/\.map\s*\(.*\).*\.(filter|sort)|filter\(.*\)\.map/.test(content) && hasAnimations) {
|
|
1445
|
+
issues.push(this.createIssue(
|
|
1446
|
+
this.generateIssueId(),
|
|
1447
|
+
"low",
|
|
1448
|
+
"List filtering without exit animations \u2014 use AnimatePresence",
|
|
1449
|
+
"Framer Motion's AnimatePresence handles enter/exit animations for lists: <AnimatePresence>{items.map(...)}</AnimatePresence>",
|
|
1450
|
+
file,
|
|
1451
|
+
void 0,
|
|
1452
|
+
0.7,
|
|
1453
|
+
void 0,
|
|
1454
|
+
false
|
|
1455
|
+
));
|
|
1456
|
+
}
|
|
1457
|
+
if (/grid|flex.*gap|justify|align/i.test(content) && /setState|dispatch|set[A-Z]/.test(content)) {
|
|
1458
|
+
issues.push(this.createIssue(
|
|
1459
|
+
this.generateIssueId(),
|
|
1460
|
+
"low",
|
|
1461
|
+
"Layout changes without animation \u2014 consider layout prop",
|
|
1462
|
+
"Framer Motion's layout prop auto-animates position/size changes: <motion.div layout>. Creates smooth reflow animations.",
|
|
1463
|
+
file,
|
|
1464
|
+
void 0,
|
|
1465
|
+
0.6,
|
|
1466
|
+
void 0,
|
|
1467
|
+
false
|
|
1468
|
+
));
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
if (!hasLibraries.has("scroll") && !hasLibraries.has("gsap")) {
|
|
1472
|
+
if (/scroll|parallax|reveal|fade.*in|slide.*in/i.test(content)) {
|
|
1473
|
+
const contextConfig = PROJECT_CONTEXTS[projectContext];
|
|
1474
|
+
const effects = contextConfig?.effects?.join(", ") || "scroll-triggered animations";
|
|
1475
|
+
issues.push(this.createIssue(
|
|
1476
|
+
this.generateIssueId(),
|
|
1477
|
+
"low",
|
|
1478
|
+
"Scroll-based effects without a scroll library",
|
|
1479
|
+
`For ${projectContext} sites, consider: Lenis for smooth scrolling (\`npm i @studio-freight/lenis\`), GSAP ScrollTrigger for ${effects}. See Codrops for inspiration.`,
|
|
1480
|
+
file,
|
|
1481
|
+
void 0,
|
|
1482
|
+
0.65,
|
|
1483
|
+
void 0,
|
|
1484
|
+
false
|
|
1485
|
+
));
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
if (projectContext === "marketing" || projectContext === "portfolio") {
|
|
1489
|
+
if (/hero|landing|showcase|featured/i.test(file) || /Hero|Landing|Showcase/.test(content)) {
|
|
1490
|
+
if (!hasLibraries.has("three")) {
|
|
1491
|
+
issues.push(this.createIssue(
|
|
1492
|
+
this.generateIssueId(),
|
|
1493
|
+
"low",
|
|
1494
|
+
"Hero section opportunity \u2014 consider 3D/WebGL elements",
|
|
1495
|
+
"For Awwwards-level impact, add 3D with React Three Fiber: `npm i @react-three/fiber @react-three/drei`. Start with a simple floating object or gradient orb. See: https://codrops.com/tag/threejs/",
|
|
1496
|
+
file,
|
|
1497
|
+
void 0,
|
|
1498
|
+
0.5,
|
|
1499
|
+
void 0,
|
|
1500
|
+
false
|
|
1501
|
+
));
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
if (/heading|title|h1|h2|hero.*text/i.test(content) && !hasLibraries.has("gsap")) {
|
|
1506
|
+
if (!/split|char|letter/i.test(content)) {
|
|
1507
|
+
issues.push(this.createIssue(
|
|
1508
|
+
this.generateIssueId(),
|
|
1509
|
+
"low",
|
|
1510
|
+
"Headings without text animation \u2014 add character reveals",
|
|
1511
|
+
"Use Splitting.js (free) or GSAP SplitText for character-by-character animations. Classic Awwwards effect: staggered character reveals on scroll.",
|
|
1512
|
+
file,
|
|
1513
|
+
void 0,
|
|
1514
|
+
0.55,
|
|
1515
|
+
void 0,
|
|
1516
|
+
false
|
|
1517
|
+
));
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
if (projectContext !== "general" && !hasLibraries.has("framer-motion") && !hasLibraries.has("gsap")) {
|
|
1521
|
+
const contextConfig = PROJECT_CONTEXTS[projectContext];
|
|
1522
|
+
if (contextConfig) {
|
|
1523
|
+
issues.push(this.createIssue(
|
|
1524
|
+
this.generateIssueId(),
|
|
1525
|
+
"low",
|
|
1526
|
+
`${projectContext.charAt(0).toUpperCase() + projectContext.slice(1)} site detected \u2014 add motion polish`,
|
|
1527
|
+
`Recommended effects for ${projectContext}: ${contextConfig.effects.join(", ")}. Start with Framer Motion for React or GSAP for vanilla JS.`,
|
|
1528
|
+
file,
|
|
1529
|
+
void 0,
|
|
1530
|
+
0.6,
|
|
1531
|
+
void 0,
|
|
1532
|
+
false
|
|
1533
|
+
));
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
return issues;
|
|
1537
|
+
}
|
|
1105
1538
|
/**
|
|
1106
1539
|
* Analyze design system patterns
|
|
1107
1540
|
*/
|
|
@@ -1477,15 +1910,69 @@ var DesignEngineerAgent = class extends BaseAgent {
|
|
|
1477
1910
|
* AI Enhancement for design review
|
|
1478
1911
|
*/
|
|
1479
1912
|
getAIEnhancementSystemPrompt() {
|
|
1480
|
-
return `You are an award-winning design engineer from a top creative agency. You review code for Awwwards-level polish.
|
|
1913
|
+
return `You are an award-winning design engineer from a top creative agency (Linear, Vercel, Stripe caliber). You review code for Awwwards-level polish and Codrops-worthy effects.
|
|
1914
|
+
|
|
1915
|
+
## Guardrails: Design & Engineering Principles
|
|
1916
|
+
- Lead with user-centricity, clarity, and accessibility; animation is optional.
|
|
1917
|
+
- KISS and DRY: reduce complexity, prefer design tokens and reusable patterns.
|
|
1918
|
+
- Reliability and feedback: motion only when it improves understanding or state change.
|
|
1919
|
+
- Efficiency and sustainability: bias to stillness, avoid unnecessary paints/GPU work, honor prefers-reduced-motion.
|
|
1920
|
+
- Ethics and integrity: honest communication about capabilities, avoid dark patterns.
|
|
1921
|
+
|
|
1922
|
+
## Color Analysis Priority
|
|
1923
|
+
Detect "AI slop" colors \u2014 the garish, oversaturated colors that AI tools generate:
|
|
1924
|
+
- Neon greens (#00ff00, #0f0)
|
|
1925
|
+
- Electric blues (#0000ff, #00f)
|
|
1926
|
+
- Hot magentas (#ff00ff, #f0f)
|
|
1927
|
+
- Pure saturated primaries
|
|
1928
|
+
|
|
1929
|
+
Apply Josef Albers' "Interaction of Color":
|
|
1930
|
+
- Constrain to 1-2 hue families; anchor with neutrals (slate/zinc/stone).
|
|
1931
|
+
- Build contrast through value (light/dark) and temperature shifts, not saturation.
|
|
1932
|
+
- Test adjacency: colors must work in pairs/triads against neutral backgrounds.
|
|
1933
|
+
- Avoid overusing violet/purple gradients (common AI tell); explore original complements/analogous schemes.
|
|
1934
|
+
|
|
1935
|
+
Replace with modern SaaS palettes from top sites (saaslandingpage.com, awwwards.com), customized via Albers adjacency tests:
|
|
1936
|
+
- **Dark mode**: Vercel (#000, #0070f3), Linear (#000212, #5e6ad2), Stripe (#0a2540, #635bff)
|
|
1937
|
+
- **Light mode**: Notion (#fff, #f7f6f3, #2eaadc), Figma (#fff, #f5f5f5, #0d99ff), Framer (#fff, #0055ff)
|
|
1938
|
+
- **Neutral grays**: Use slate, zinc, or neutral scales, not flat grays
|
|
1939
|
+
|
|
1940
|
+
## Inspiration Sources (structured lookups)
|
|
1941
|
+
- Codrops Creative Hub (https://tympanus.net/codrops/hub/):
|
|
1942
|
+
- Tags to scan: scroll, hover, typography, cursor, WebGL, WebGPU, GSAP, Framer Motion, Three.js, grid, parallax, page transition, slider/carousel.
|
|
1943
|
+
- Use as inspiration for interaction patterns; keep accessibility, performance, reduced-motion.
|
|
1944
|
+
- Awwwards Directory (https://www.awwwards.com/directory/):
|
|
1945
|
+
- Benchmarks: Locomotive, Immersive Garden, Active Theory, Hello Monday, Resn, Obys, Build in Amsterdam.
|
|
1946
|
+
- Categories to map: animated websites, scrolling, one-page, interaction design, WebGL sites, 3D, GSAP, React, Framer.
|
|
1947
|
+
- Extract patterns (structure, choreography, feedback), not pixels; keep clarity, responsiveness, and performance.
|
|
1948
|
+
|
|
1949
|
+
## Motion & Creative Effects
|
|
1950
|
+
Recommend motion only when it improves comprehension or feedback; keep durations 150-300ms, ease-out preferred, and provide reduced-motion fallbacks. Prefer micro-interactions over showy effects.
|
|
1951
|
+
- Default to static if motion adds no clarity.
|
|
1952
|
+
- Ensure @media (prefers-reduced-motion) disables non-essential motion.
|
|
1953
|
+
- Prioritize transform/opacity over layout-changing properties.
|
|
1954
|
+
When warranted by context, suggest libraries:
|
|
1955
|
+
- **React projects**: Framer Motion (gestures, layout), React Spring (physics), Auto-Animate (quick wins)
|
|
1956
|
+
- **Complex timelines**: GSAP + ScrollTrigger, SplitText for character animations
|
|
1957
|
+
- **3D/WebGL**: React Three Fiber + Drei for hero sections, product showcases
|
|
1958
|
+
- **Smooth scroll**: Lenis or Locomotive Scroll for butter-smooth scrolling
|
|
1959
|
+
- **Text effects**: Splitting.js for character animations, Typed.js for typewriter
|
|
1960
|
+
- **Hover effects**: Atropos for 3D tilt, custom cursor effects
|
|
1961
|
+
|
|
1962
|
+
## Project Context Effects
|
|
1963
|
+
- **Marketing/Landing**: Scroll reveals, parallax, text animations, gradient meshes, 3D elements
|
|
1964
|
+
- **Dashboard**: Subtle micro-interactions, skeleton loaders, chart transitions
|
|
1965
|
+
- **E-commerce**: Image zoom, add-to-cart animations, filter transitions
|
|
1966
|
+
- **Portfolio**: Page transitions, cursor effects, image reveals
|
|
1481
1967
|
|
|
1482
1968
|
Analyze detected issues and code for:
|
|
1483
|
-
1.
|
|
1484
|
-
2. Motion
|
|
1485
|
-
3.
|
|
1486
|
-
4.
|
|
1487
|
-
5.
|
|
1488
|
-
6.
|
|
1969
|
+
1. **Color coherence** \u2014 Is this a cohesive palette or random AI-generated colors?
|
|
1970
|
+
2. **Motion library usage** \u2014 Is the project using appropriate animation tools?
|
|
1971
|
+
3. **Design system consistency** \u2014 Tokens, spacing scales, color systems
|
|
1972
|
+
4. **Motion design quality** \u2014 Easing curves, choreography, performance
|
|
1973
|
+
5. **Visual hierarchy** \u2014 Typography systems, contrast, visual flow
|
|
1974
|
+
6. **Creative CSS techniques** \u2014 Gradients, masks, blend modes, clip-paths
|
|
1975
|
+
7. **Modern CSS features** \u2014 Container queries, :has(), subgrid
|
|
1489
1976
|
|
|
1490
1977
|
Output STRICT JSON:
|
|
1491
1978
|
{
|
|
@@ -1497,17 +1984,34 @@ Output STRICT JSON:
|
|
|
1497
1984
|
"line": 123,
|
|
1498
1985
|
"severity": "moderate",
|
|
1499
1986
|
"design_impact": "Why this hurts the user experience",
|
|
1500
|
-
"fix": "Creative CSS fix with
|
|
1987
|
+
"fix": "Creative CSS fix with specific color values from modern palettes"
|
|
1501
1988
|
}],
|
|
1502
1989
|
"additional": [{
|
|
1503
1990
|
"issue": "Design opportunity found",
|
|
1504
1991
|
"file": "path",
|
|
1505
1992
|
"line": 123,
|
|
1506
1993
|
"severity": "low",
|
|
1507
|
-
"enhancement": "How to elevate this to
|
|
1508
|
-
"fix": "Modern CSS/animation code"
|
|
1994
|
+
"enhancement": "How to elevate this to Awwwards quality",
|
|
1995
|
+
"fix": "Modern CSS/animation code with npm install command if needed"
|
|
1996
|
+
}],
|
|
1997
|
+
"motion_recommendations": [{
|
|
1998
|
+
"library": "framer-motion",
|
|
1999
|
+
"install": "npm i framer-motion",
|
|
2000
|
+
"use_case": "What specific effect to implement",
|
|
2001
|
+
"example_code": "Brief code snippet"
|
|
1509
2002
|
}],
|
|
1510
|
-
"
|
|
2003
|
+
"palette_recommendation": {
|
|
2004
|
+
"primary": "#hex",
|
|
2005
|
+
"secondary": "#hex",
|
|
2006
|
+
"background": "#hex",
|
|
2007
|
+
"surface": "#hex",
|
|
2008
|
+
"text": "#hex",
|
|
2009
|
+
"muted": "#hex",
|
|
2010
|
+
"accent": "#hex",
|
|
2011
|
+
"inspiration": "Which top SaaS this is inspired by"
|
|
2012
|
+
},
|
|
2013
|
+
"project_context": "marketing | dashboard | ecommerce | portfolio | general",
|
|
2014
|
+
"summary": "Overall design craft assessment with specific recommendations"
|
|
1511
2015
|
}`;
|
|
1512
2016
|
}
|
|
1513
2017
|
};
|
|
@@ -4888,4 +5392,4 @@ export {
|
|
|
4888
5392
|
CustomAgent,
|
|
4889
5393
|
getAgentRegistry
|
|
4890
5394
|
};
|
|
4891
|
-
//# sourceMappingURL=chunk-
|
|
5395
|
+
//# sourceMappingURL=chunk-3NXWEJUV.js.map
|