@elsahafy/ux-mcp-server 2.0.0 → 4.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.
package/dist/index.js CHANGED
@@ -109,6 +109,150 @@ server.setRequestHandler(ListResourcesRequestSchema, async () => {
109
109
  description: "Advanced React patterns for composition, state management, and performance",
110
110
  mimeType: "application/json",
111
111
  },
112
+ {
113
+ uri: "ux://forms/patterns",
114
+ name: "Form Design Patterns",
115
+ description: "Comprehensive guide to designing accessible, user-friendly forms",
116
+ mimeType: "application/json",
117
+ },
118
+ {
119
+ uri: "ux://content/microcopy",
120
+ name: "Microcopy & UX Writing",
121
+ description: "Guide to writing clear, user-friendly interface copy and microcopy",
122
+ mimeType: "application/json",
123
+ },
124
+ {
125
+ uri: "ux://design/typography",
126
+ name: "Typography System",
127
+ description: "Type scales, font pairing, hierarchy, and responsive typography",
128
+ mimeType: "application/json",
129
+ },
130
+ {
131
+ uri: "ux://design/color-theory",
132
+ name: "Color Theory & Palettes",
133
+ description: "Color theory, palette generation, accessibility, and color usage",
134
+ mimeType: "application/json",
135
+ },
136
+ {
137
+ uri: "ux://mobile/patterns",
138
+ name: "Mobile-Specific UX Patterns",
139
+ description: "Mobile-first design, touch interactions, and mobile navigation patterns",
140
+ mimeType: "application/json",
141
+ },
142
+ {
143
+ uri: "ux://vue/patterns",
144
+ name: "Vue.js Patterns & Best Practices",
145
+ description: "Vue.js component patterns, Composition API, and state management",
146
+ mimeType: "application/json",
147
+ },
148
+ {
149
+ uri: "ux://angular/patterns",
150
+ name: "Angular Patterns & Best Practices",
151
+ description: "Angular component patterns, services, RxJS, and performance optimization",
152
+ mimeType: "application/json",
153
+ },
154
+ {
155
+ uri: "ux://data-viz/patterns",
156
+ name: "Data Visualization Patterns",
157
+ description: "Choosing, designing, and implementing accessible data visualizations",
158
+ mimeType: "application/json",
159
+ },
160
+ {
161
+ uri: "ux://ecommerce/patterns",
162
+ name: "E-commerce UX Patterns",
163
+ description: "E-commerce user experience patterns, conversion optimization, and best practices",
164
+ mimeType: "application/json",
165
+ },
166
+ {
167
+ uri: "ux://ia/information-architecture",
168
+ name: "Information Architecture",
169
+ description: "Organizing and structuring information for optimal findability and usability",
170
+ mimeType: "application/json",
171
+ },
172
+ {
173
+ uri: "ux://testing/validation",
174
+ name: "UX Testing & Validation",
175
+ description: "User experience testing methodologies, validation techniques, and research methods",
176
+ mimeType: "application/json",
177
+ },
178
+ {
179
+ uri: "ux://pwa/patterns",
180
+ name: "Progressive Web App Patterns",
181
+ description: "Building progressive web apps with optimal UX patterns and best practices",
182
+ mimeType: "application/json",
183
+ },
184
+ {
185
+ uri: "ux://ethics/dark-patterns",
186
+ name: "Ethical Design & Dark Patterns",
187
+ description: "Ethical design principles and avoiding dark patterns that manipulate users",
188
+ mimeType: "application/json",
189
+ },
190
+ {
191
+ uri: "ux://design-systems/advanced",
192
+ name: "Advanced Design System Patterns",
193
+ description: "Advanced concepts for building, scaling, and maintaining enterprise design systems",
194
+ mimeType: "application/json",
195
+ },
196
+ {
197
+ uri: "ux://saas/patterns",
198
+ name: "SaaS Product UX Patterns",
199
+ description: "UX patterns for SaaS products including onboarding, pricing, and retention",
200
+ mimeType: "application/json",
201
+ },
202
+ {
203
+ uri: "ux://analytics/metrics",
204
+ name: "UX Analytics & Metrics",
205
+ description: "Measuring user experience through analytics, metrics, and data-driven decision making",
206
+ mimeType: "application/json",
207
+ },
208
+ {
209
+ uri: "ux://voice/interface",
210
+ name: "Voice User Interface (VUI) Design",
211
+ description: "Designing voice interfaces for assistants, smart speakers, and voice-enabled apps",
212
+ mimeType: "application/json",
213
+ },
214
+ {
215
+ uri: "ux://ar-vr/interfaces",
216
+ name: "AR/VR Interface Design",
217
+ description: "Design principles and patterns for Augmented and Virtual Reality interfaces",
218
+ mimeType: "application/json",
219
+ },
220
+ {
221
+ uri: "ux://ai-ml/patterns",
222
+ name: "AI/ML UX Patterns",
223
+ description: "User experience patterns for AI and machine learning powered features",
224
+ mimeType: "application/json",
225
+ },
226
+ {
227
+ uri: "ux://haptic/feedback",
228
+ name: "Haptic Feedback Design",
229
+ description: "Design guide for tactile feedback in user interfaces across devices",
230
+ mimeType: "application/json",
231
+ },
232
+ {
233
+ uri: "ux://healthcare/patterns",
234
+ name: "Healthcare UX Patterns",
235
+ description: "UX design for healthcare applications prioritizing safety, privacy, and usability",
236
+ mimeType: "application/json",
237
+ },
238
+ {
239
+ uri: "ux://finance/patterns",
240
+ name: "Financial Services UX Patterns",
241
+ description: "UX design for banking, fintech, and financial applications",
242
+ mimeType: "application/json",
243
+ },
244
+ {
245
+ uri: "ux://neurodiversity/design",
246
+ name: "Neurodiversity-Inclusive Design",
247
+ description: "Designing for neurodivergent users including ADHD, autism, and dyslexia",
248
+ mimeType: "application/json",
249
+ },
250
+ {
251
+ uri: "ux://web-components/patterns",
252
+ name: "Web Components",
253
+ description: "Building framework-agnostic, reusable UI components with Web Components",
254
+ mimeType: "application/json",
255
+ },
112
256
  ],
113
257
  };
114
258
  });
@@ -165,6 +309,102 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
165
309
  content = await loadKnowledge("react-patterns.json");
166
310
  description = "Advanced React component patterns and best practices";
167
311
  break;
312
+ case "ux://forms/patterns":
313
+ content = await loadKnowledge("forms.json");
314
+ description = "Comprehensive form design patterns and validation";
315
+ break;
316
+ case "ux://content/microcopy":
317
+ content = await loadKnowledge("microcopy.json");
318
+ description = "UX writing and microcopy best practices";
319
+ break;
320
+ case "ux://design/typography":
321
+ content = await loadKnowledge("typography.json");
322
+ description = "Typography system and font pairing guide";
323
+ break;
324
+ case "ux://design/color-theory":
325
+ content = await loadKnowledge("color-theory.json");
326
+ description = "Color theory, palettes, and accessibility";
327
+ break;
328
+ case "ux://mobile/patterns":
329
+ content = await loadKnowledge("mobile-patterns.json");
330
+ description = "Mobile-specific UX patterns and touch interactions";
331
+ break;
332
+ case "ux://vue/patterns":
333
+ content = await loadKnowledge("vue-patterns.json");
334
+ description = "Vue.js patterns and Composition API";
335
+ break;
336
+ case "ux://angular/patterns":
337
+ content = await loadKnowledge("angular-patterns.json");
338
+ description = "Angular patterns, services, and RxJS";
339
+ break;
340
+ case "ux://data-viz/patterns":
341
+ content = await loadKnowledge("data-viz.json");
342
+ description = "Data visualization best practices";
343
+ break;
344
+ case "ux://ecommerce/patterns":
345
+ content = await loadKnowledge("ecommerce-patterns.json");
346
+ description = "E-commerce UX patterns and conversion optimization";
347
+ break;
348
+ case "ux://ia/information-architecture":
349
+ content = await loadKnowledge("information-architecture.json");
350
+ description = "Information architecture and content organization";
351
+ break;
352
+ case "ux://testing/validation":
353
+ content = await loadKnowledge("testing-validation.json");
354
+ description = "UX testing methodologies and validation techniques";
355
+ break;
356
+ case "ux://pwa/patterns":
357
+ content = await loadKnowledge("pwa-patterns.json");
358
+ description = "Progressive Web App patterns and best practices";
359
+ break;
360
+ case "ux://ethics/dark-patterns":
361
+ content = await loadKnowledge("ethical-design.json");
362
+ description = "Ethical design and dark pattern prevention";
363
+ break;
364
+ case "ux://design-systems/advanced":
365
+ content = await loadKnowledge("design-system-advanced.json");
366
+ description = "Advanced design system patterns and scaling";
367
+ break;
368
+ case "ux://saas/patterns":
369
+ content = await loadKnowledge("saas-patterns.json");
370
+ description = "SaaS product UX patterns and strategies";
371
+ break;
372
+ case "ux://analytics/metrics":
373
+ content = await loadKnowledge("analytics-metrics.json");
374
+ description = "UX analytics, metrics, and measurement";
375
+ break;
376
+ case "ux://voice/interface":
377
+ content = await loadKnowledge("voice-ui.json");
378
+ description = "Voice user interface design and conversation patterns";
379
+ break;
380
+ case "ux://ar-vr/interfaces":
381
+ content = await loadKnowledge("ar-vr-interfaces.json");
382
+ description = "AR and VR interface design principles";
383
+ break;
384
+ case "ux://ai-ml/patterns":
385
+ content = await loadKnowledge("ai-ml-patterns.json");
386
+ description = "AI and ML UX patterns and ethical considerations";
387
+ break;
388
+ case "ux://haptic/feedback":
389
+ content = await loadKnowledge("haptic-feedback.json");
390
+ description = "Haptic feedback design for tactile interfaces";
391
+ break;
392
+ case "ux://healthcare/patterns":
393
+ content = await loadKnowledge("healthcare-ux.json");
394
+ description = "Healthcare UX design patterns and regulations";
395
+ break;
396
+ case "ux://finance/patterns":
397
+ content = await loadKnowledge("finance-ux.json");
398
+ description = "Financial services UX patterns and security";
399
+ break;
400
+ case "ux://neurodiversity/design":
401
+ content = await loadKnowledge("neurodiversity.json");
402
+ description = "Neurodiversity-inclusive design principles";
403
+ break;
404
+ case "ux://web-components/patterns":
405
+ content = await loadKnowledge("web-components.json");
406
+ description = "Web Components standards and patterns";
407
+ break;
168
408
  default:
169
409
  throw new Error(`Unknown resource: ${uri}`);
170
410
  }
@@ -415,6 +655,275 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
415
655
  required: ["interaction"],
416
656
  },
417
657
  },
658
+ {
659
+ name: "generate_color_palette",
660
+ description: "Generate accessible color palette from a base color. Returns primary, secondary, neutral, and semantic colors with WCAG-compliant variations.",
661
+ inputSchema: {
662
+ type: "object",
663
+ properties: {
664
+ base_color: {
665
+ type: "string",
666
+ description: "Base color (hex, rgb, or color name)",
667
+ },
668
+ harmony_type: {
669
+ type: "string",
670
+ enum: ["monochromatic", "analogous", "complementary", "triadic", "split-complementary"],
671
+ description: "Color harmony type to generate",
672
+ default: "analogous",
673
+ },
674
+ include_neutrals: {
675
+ type: "boolean",
676
+ description: "Include grayscale neutrals",
677
+ default: true,
678
+ },
679
+ },
680
+ required: ["base_color"],
681
+ },
682
+ },
683
+ {
684
+ name: "generate_typography_scale",
685
+ description: "Calculate modular typography scale with recommended sizes for headings and body text. Returns complete type scale with line heights.",
686
+ inputSchema: {
687
+ type: "object",
688
+ properties: {
689
+ base_size: {
690
+ type: "number",
691
+ description: "Base font size in pixels (typically 16)",
692
+ default: 16,
693
+ },
694
+ scale_ratio: {
695
+ type: "number",
696
+ description: "Scale ratio (e.g., 1.2 for minor third, 1.5 for perfect fifth)",
697
+ default: 1.2,
698
+ },
699
+ steps: {
700
+ type: "number",
701
+ description: "Number of steps to generate (up and down from base)",
702
+ default: 5,
703
+ },
704
+ },
705
+ },
706
+ },
707
+ {
708
+ name: "suggest_microcopy",
709
+ description: "Suggest user-friendly microcopy for UI elements. Returns context-aware suggestions for buttons, labels, messages, and help text.",
710
+ inputSchema: {
711
+ type: "object",
712
+ properties: {
713
+ element_type: {
714
+ type: "string",
715
+ enum: ["button", "label", "placeholder", "error", "success", "empty-state", "tooltip", "cta"],
716
+ description: "Type of UI element needing copy",
717
+ },
718
+ context: {
719
+ type: "string",
720
+ description: "Context of the element (e.g., 'login button', 'email field', 'payment success')",
721
+ },
722
+ tone: {
723
+ type: "string",
724
+ enum: ["professional", "friendly", "casual", "formal"],
725
+ description: "Desired tone of voice",
726
+ default: "friendly",
727
+ },
728
+ },
729
+ required: ["element_type", "context"],
730
+ },
731
+ },
732
+ {
733
+ name: "suggest_form_pattern",
734
+ description: "Recommend optimal form layout and validation pattern. Returns layout recommendations, field types, and validation strategies.",
735
+ inputSchema: {
736
+ type: "object",
737
+ properties: {
738
+ form_type: {
739
+ type: "string",
740
+ description: "Type of form (e.g., 'login', 'registration', 'checkout', 'contact', 'search')",
741
+ },
742
+ field_count: {
743
+ type: "number",
744
+ description: "Approximate number of fields",
745
+ },
746
+ platform: {
747
+ type: "string",
748
+ enum: ["web", "mobile", "both"],
749
+ description: "Target platform",
750
+ default: "both",
751
+ },
752
+ },
753
+ required: ["form_type"],
754
+ },
755
+ },
756
+ {
757
+ name: "analyze_data_viz",
758
+ description: "Review data visualization for accessibility and clarity. Checks chart type appropriateness, color usage, labels, and accessibility.",
759
+ inputSchema: {
760
+ type: "object",
761
+ properties: {
762
+ chart_type: {
763
+ type: "string",
764
+ description: "Type of chart/visualization (e.g., 'bar chart', 'line chart', 'pie chart', 'scatter plot')",
765
+ },
766
+ data_description: {
767
+ type: "string",
768
+ description: "Description of the data being visualized",
769
+ },
770
+ purpose: {
771
+ type: "string",
772
+ description: "Purpose of the visualization (e.g., 'comparison', 'trend', 'composition', 'distribution')",
773
+ },
774
+ },
775
+ required: ["chart_type", "data_description"],
776
+ },
777
+ },
778
+ {
779
+ name: "generate_accessibility_report",
780
+ description: "Generate comprehensive accessibility audit report. Checks WCAG compliance, keyboard navigation, screen reader compatibility, and semantic HTML.",
781
+ inputSchema: {
782
+ type: "object",
783
+ properties: {
784
+ url: {
785
+ type: "string",
786
+ description: "URL or page identifier to audit",
787
+ },
788
+ wcag_level: {
789
+ type: "string",
790
+ enum: ["A", "AA", "AAA"],
791
+ description: "WCAG compliance level to check against",
792
+ default: "AA",
793
+ },
794
+ },
795
+ required: ["url"],
796
+ },
797
+ },
798
+ {
799
+ name: "suggest_ab_variant",
800
+ description: "Suggest A/B test variants for optimization. Provides hypothesis, variant designs, and metrics to track.",
801
+ inputSchema: {
802
+ type: "object",
803
+ properties: {
804
+ element: {
805
+ type: "string",
806
+ description: "Element to test (e.g., 'CTA button', 'headline', 'pricing page', 'checkout flow')",
807
+ },
808
+ goal: {
809
+ type: "string",
810
+ description: "Desired outcome (e.g., 'increase conversions', 'reduce bounce', 'improve engagement')",
811
+ },
812
+ current_performance: {
813
+ type: "string",
814
+ description: "Current metric (e.g., '2% conversion rate', '60% bounce rate')",
815
+ },
816
+ },
817
+ required: ["element", "goal"],
818
+ },
819
+ },
820
+ {
821
+ name: "analyze_information_architecture",
822
+ description: "Analyze and suggest improvements to information architecture. Reviews navigation, labeling, hierarchy, and content organization.",
823
+ inputSchema: {
824
+ type: "object",
825
+ properties: {
826
+ site_structure: {
827
+ type: "string",
828
+ description: "Description or sitemap of current structure",
829
+ },
830
+ user_goals: {
831
+ type: "string",
832
+ description: "Primary user goals and tasks",
833
+ },
834
+ issues: {
835
+ type: "string",
836
+ description: "Known issues or pain points (optional)",
837
+ },
838
+ },
839
+ required: ["site_structure", "user_goals"],
840
+ },
841
+ },
842
+ {
843
+ name: "detect_dark_patterns",
844
+ description: "Detect dark patterns and ethical design violations. Identifies manipulative UI practices and suggests ethical alternatives.",
845
+ inputSchema: {
846
+ type: "object",
847
+ properties: {
848
+ flow_description: {
849
+ type: "string",
850
+ description: "Description of user flow or interface (e.g., 'subscription cancellation', 'cookie consent', 'checkout')",
851
+ },
852
+ screenshot_url: {
853
+ type: "string",
854
+ description: "URL to screenshot (optional)",
855
+ },
856
+ },
857
+ required: ["flow_description"],
858
+ },
859
+ },
860
+ {
861
+ name: "calculate_ux_metrics",
862
+ description: "Calculate key UX metrics and benchmarks. Computes SUS score, NPS, task success rate, and provides interpretation.",
863
+ inputSchema: {
864
+ type: "object",
865
+ properties: {
866
+ metric_type: {
867
+ type: "string",
868
+ enum: ["SUS", "NPS", "CSAT", "CES", "task-success", "retention"],
869
+ description: "Type of UX metric to calculate",
870
+ },
871
+ data: {
872
+ type: "string",
873
+ description: "Raw data (e.g., 'SUS responses: 4,2,5,4,3,2,5,4,4,3' or 'NPS scores: 9,8,10,7,6,9,10')",
874
+ },
875
+ },
876
+ required: ["metric_type", "data"],
877
+ },
878
+ },
879
+ {
880
+ name: "generate_wireframe",
881
+ description: "Generate ASCII wireframe mockup for a page or component. Creates low-fidelity layout sketch using text characters.",
882
+ inputSchema: {
883
+ type: "object",
884
+ properties: {
885
+ page_type: {
886
+ type: "string",
887
+ description: "Type of page/component (e.g., 'login page', 'dashboard', 'product card', 'navigation header')",
888
+ },
889
+ elements: {
890
+ type: "string",
891
+ description: "Key elements to include (e.g., 'logo, search bar, user menu, main content area')",
892
+ },
893
+ layout: {
894
+ type: "string",
895
+ enum: ["single-column", "two-column", "three-column", "grid", "sidebar"],
896
+ description: "Overall layout structure",
897
+ default: "single-column",
898
+ },
899
+ },
900
+ required: ["page_type"],
901
+ },
902
+ },
903
+ {
904
+ name: "suggest_microinteraction",
905
+ description: "Suggest microinteractions for UI elements. Provides animation, feedback, and transition recommendations.",
906
+ inputSchema: {
907
+ type: "object",
908
+ properties: {
909
+ element: {
910
+ type: "string",
911
+ description: "UI element (e.g., 'button', 'toggle switch', 'like button', 'form submission', 'loading')",
912
+ },
913
+ context: {
914
+ type: "string",
915
+ description: "Context of interaction (e.g., 'delete action', 'successful save', 'error state')",
916
+ },
917
+ platform: {
918
+ type: "string",
919
+ enum: ["web", "mobile", "both"],
920
+ description: "Target platform",
921
+ default: "web",
922
+ },
923
+ },
924
+ required: ["element"],
925
+ },
926
+ },
418
927
  ],
419
928
  };
420
929
  });
@@ -444,6 +953,30 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
444
953
  return await checkSEO(args);
445
954
  case "suggest_animation":
446
955
  return await suggestAnimation(args);
956
+ case "generate_color_palette":
957
+ return await generateColorPalette(args);
958
+ case "generate_typography_scale":
959
+ return await generateTypographyScale(args);
960
+ case "suggest_microcopy":
961
+ return await suggestMicrocopy(args);
962
+ case "suggest_form_pattern":
963
+ return await suggestFormPattern(args);
964
+ case "analyze_data_viz":
965
+ return await analyzeDataViz(args);
966
+ case "generate_accessibility_report":
967
+ return await generateAccessibilityReport(args);
968
+ case "suggest_ab_variant":
969
+ return await suggestABVariant(args);
970
+ case "analyze_information_architecture":
971
+ return await analyzeInformationArchitecture(args);
972
+ case "detect_dark_patterns":
973
+ return await detectDarkPatterns(args);
974
+ case "calculate_ux_metrics":
975
+ return await calculateUXMetrics(args);
976
+ case "generate_wireframe":
977
+ return await generateWireframe(args);
978
+ case "suggest_microinteraction":
979
+ return await suggestMicrointeraction(args);
447
980
  default:
448
981
  throw new Error(`Unknown tool: ${name}`);
449
982
  }
@@ -1598,14 +2131,1483 @@ async function suggestAnimation(args) {
1598
2131
  ],
1599
2132
  };
1600
2133
  }
1601
- // ========================================
1602
- // PROMPTS - Pre-configured UX Reviews
1603
- // ========================================
1604
- server.setRequestHandler(ListPromptsRequestSchema, async () => {
1605
- return {
1606
- prompts: [
1607
- {
1608
- name: "accessibility_review",
2134
+ async function generateColorPalette(args) {
2135
+ const baseColor = args.base_color;
2136
+ const harmonyType = args.harmony_type || "analogous";
2137
+ const includeNeutrals = args.include_neutrals !== false;
2138
+ // Parse base color (simplified - would use proper color library in production)
2139
+ const colorName = baseColor.toLowerCase();
2140
+ let palette = {
2141
+ base_color: baseColor,
2142
+ harmony_type: harmonyType,
2143
+ colors: {
2144
+ primary: {
2145
+ 50: "#f0f9ff",
2146
+ 100: "#e0f2fe",
2147
+ 200: "#bae6fd",
2148
+ 300: "#7dd3fc",
2149
+ 400: "#38bdf8",
2150
+ 500: baseColor,
2151
+ 600: "#0284c7",
2152
+ 700: "#0369a1",
2153
+ 800: "#075985",
2154
+ 900: "#0c4a6e",
2155
+ 950: "#082f49"
2156
+ }
2157
+ },
2158
+ usage_guide: {
2159
+ 50: "Lightest backgrounds",
2160
+ 100_200_300: "Light backgrounds, hover states",
2161
+ 400: "Borders, disabled states",
2162
+ 500: "Primary brand color",
2163
+ 600_700: "Interactive elements, buttons",
2164
+ 800_900: "Text on light backgrounds",
2165
+ 950: "Darkest text"
2166
+ },
2167
+ accessibility: {
2168
+ text_on_50: "Use 700+ for AA contrast",
2169
+ text_on_500: "Use white or 50 for AA contrast",
2170
+ text_on_900: "Use 50-200 for AA contrast"
2171
+ }
2172
+ };
2173
+ if (harmonyType === "complementary") {
2174
+ palette.colors.secondary = {
2175
+ 500: "#ff6b35",
2176
+ description: "Complementary (opposite on color wheel)"
2177
+ };
2178
+ palette.usage = "Use primary (60%), secondary (30%), accent (10%)";
2179
+ }
2180
+ else if (harmonyType === "analogous") {
2181
+ palette.colors.secondary = {
2182
+ 500: "#8b5cf6",
2183
+ description: "Analogous (adjacent on color wheel)"
2184
+ };
2185
+ palette.colors.tertiary = {
2186
+ 500: "#10b981",
2187
+ description: "Analogous variation"
2188
+ };
2189
+ }
2190
+ else if (harmonyType === "triadic") {
2191
+ palette.colors.secondary = {
2192
+ 500: "#f59e0b",
2193
+ description: "Triadic (120° apart)"
2194
+ };
2195
+ palette.colors.tertiary = {
2196
+ 500: "#10b981",
2197
+ description: "Triadic (240° apart)"
2198
+ };
2199
+ }
2200
+ if (includeNeutrals) {
2201
+ palette.colors.neutral = {
2202
+ 50: "#f9fafb",
2203
+ 100: "#f3f4f6",
2204
+ 200: "#e5e7eb",
2205
+ 300: "#d1d5db",
2206
+ 400: "#9ca3af",
2207
+ 500: "#6b7280",
2208
+ 600: "#4b5563",
2209
+ 700: "#374151",
2210
+ 800: "#1f2937",
2211
+ 900: "#111827",
2212
+ 950: "#030712",
2213
+ usage: "Backgrounds, text, borders, shadows"
2214
+ };
2215
+ }
2216
+ palette.semantic_colors = {
2217
+ success: { color: "#10b981", use: "Success messages, confirmations" },
2218
+ error: { color: "#ef4444", use: "Errors, destructive actions" },
2219
+ warning: { color: "#f59e0b", use: "Warnings, caution states" },
2220
+ info: { color: "#3b82f6", use: "Informational messages" }
2221
+ };
2222
+ palette.best_practices = [
2223
+ "Use primary color for brand identity and main CTAs",
2224
+ "Limit to 1-2 primary colors maximum",
2225
+ "Create 9-11 shades of each color for flexibility",
2226
+ "Maintain 4.5:1 contrast ratio for text",
2227
+ "Test with colorblind simulators",
2228
+ "Use semantic colors consistently"
2229
+ ];
2230
+ palette.tools = [
2231
+ "Coolors.co - Generate more variations",
2232
+ "Colorbox.io - Accessible color systems",
2233
+ "Stark - Test accessibility"
2234
+ ];
2235
+ return {
2236
+ content: [
2237
+ {
2238
+ type: "text",
2239
+ text: JSON.stringify(palette, null, 2),
2240
+ },
2241
+ ],
2242
+ };
2243
+ }
2244
+ async function generateTypographyScale(args) {
2245
+ const baseSize = args.base_size || 16;
2246
+ const ratio = args.scale_ratio || 1.2;
2247
+ const steps = args.steps || 5;
2248
+ const scale = {
2249
+ base_size: `${baseSize}px (1rem)`,
2250
+ ratio,
2251
+ ratio_name: getRatioName(ratio),
2252
+ sizes: {}
2253
+ };
2254
+ // Generate sizes
2255
+ for (let i = -steps; i <= steps; i++) {
2256
+ const size = baseSize * Math.pow(ratio, i);
2257
+ const rem = size / 16;
2258
+ const lineHeight = size < 20 ? 1.6 : size < 32 ? 1.4 : size < 48 ? 1.2 : 1.1;
2259
+ let name;
2260
+ if (i === 0)
2261
+ name = "base";
2262
+ else if (i < 0)
2263
+ name = `sm${Math.abs(i) > 1 ? Math.abs(i) : ""}`;
2264
+ else
2265
+ name = `${i > 1 ? i : ""}xl`;
2266
+ scale.sizes[name] = {
2267
+ px: `${size.toFixed(1)}px`,
2268
+ rem: `${rem.toFixed(3)}rem`,
2269
+ line_height: lineHeight.toFixed(2)
2270
+ };
2271
+ }
2272
+ scale.usage_guide = {
2273
+ "sm2-sm": "Fine print, captions, footnotes (12-14px)",
2274
+ "base": "Body text (16px) - never go smaller",
2275
+ "lg-xl": "Subheadings, large body text (18-20px)",
2276
+ "2xl-3xl": "Section headings, h3-h4 (24-32px)",
2277
+ "4xl-5xl": "Page titles, h1-h2 (40-56px)"
2278
+ };
2279
+ scale.recommendations = {
2280
+ headings: {
2281
+ h1: scale.sizes["5xl"] || scale.sizes["4xl"],
2282
+ h2: scale.sizes["4xl"] || scale.sizes["3xl"],
2283
+ h3: scale.sizes["3xl"] || scale.sizes["2xl"],
2284
+ h4: scale.sizes["2xl"] || scale.sizes["xl"],
2285
+ h5: scale.sizes["xl"],
2286
+ h6: scale.sizes["lg"]
2287
+ },
2288
+ body: scale.sizes["base"],
2289
+ small: scale.sizes["sm"],
2290
+ tiny: scale.sizes["sm2"] || scale.sizes["sm"]
2291
+ };
2292
+ scale.css_example = `:root {\n --font-size-base: ${baseSize}px;\n --font-size-sm: ${scale.sizes.sm.px};\n --font-size-lg: ${scale.sizes.lg.px};\n --font-size-xl: ${scale.sizes.xl.px};\n --font-size-2xl: ${scale.sizes["2xl"].px};\n \n --line-height-tight: 1.2;\n --line-height-normal: 1.5;\n --line-height-relaxed: 1.75;\n}`;
2293
+ scale.best_practices = [
2294
+ "Base size should be 16px minimum for body text",
2295
+ "Use rem units for accessibility (respects user preferences)",
2296
+ "Maintain consistent ratio throughout design",
2297
+ "Larger text needs tighter line-height",
2298
+ "Test on actual devices, not just browser resize"
2299
+ ];
2300
+ scale.tools = [
2301
+ "https://typescale.com - Visualize type scales",
2302
+ "https://www.modularscale.com - Generate scales"
2303
+ ];
2304
+ return {
2305
+ content: [
2306
+ {
2307
+ type: "text",
2308
+ text: JSON.stringify(scale, null, 2),
2309
+ },
2310
+ ],
2311
+ };
2312
+ }
2313
+ function getRatioName(ratio) {
2314
+ const ratios = {
2315
+ 1.067: "Minor Second",
2316
+ 1.125: "Major Second",
2317
+ 1.2: "Minor Third",
2318
+ 1.25: "Major Third",
2319
+ 1.333: "Perfect Fourth",
2320
+ 1.414: "Augmented Fourth",
2321
+ 1.5: "Perfect Fifth",
2322
+ 1.618: "Golden Ratio"
2323
+ };
2324
+ return ratios[ratio] || "Custom";
2325
+ }
2326
+ async function suggestMicrocopy(args) {
2327
+ const elementType = args.element_type;
2328
+ const context = args.context.toLowerCase();
2329
+ const tone = args.tone || "friendly";
2330
+ let suggestions = {
2331
+ element_type: elementType,
2332
+ context,
2333
+ tone,
2334
+ suggestions: []
2335
+ };
2336
+ if (elementType === "button") {
2337
+ if (context.includes("login") || context.includes("sign in")) {
2338
+ suggestions.suggestions = [
2339
+ { text: "Sign in", note: "Clear and standard" },
2340
+ { text: "Log in", note: "Alternative, equally clear" },
2341
+ { text: "Continue", note: "If part of multi-step flow" }
2342
+ ];
2343
+ suggestions.avoid = ["Submit", "Enter", "OK"];
2344
+ }
2345
+ else if (context.includes("register") || context.includes("sign up")) {
2346
+ suggestions.suggestions = [
2347
+ { text: "Create account", note: "Specific and action-oriented" },
2348
+ { text: "Sign up", note: "Common and clear" },
2349
+ { text: "Get started", note: "Friendly, inviting" }
2350
+ ];
2351
+ }
2352
+ else if (context.includes("delete") || context.includes("remove")) {
2353
+ suggestions.suggestions = [
2354
+ { text: "Delete permanently", note: "Clear about consequences" },
2355
+ { text: "Remove [item]", note: "Specific about what's being removed" },
2356
+ { text: "Yes, delete", note: "For confirmation dialogs" }
2357
+ ];
2358
+ suggestions.warning = "Require confirmation for destructive actions";
2359
+ }
2360
+ else if (context.includes("save")) {
2361
+ suggestions.suggestions = [
2362
+ { text: "Save changes", note: "Clear about action" },
2363
+ { text: "Save", note: "Simple, works for most cases" },
2364
+ { text: "Save and continue", note: "For multi-step flows" }
2365
+ ];
2366
+ }
2367
+ else if (context.includes("cancel")) {
2368
+ suggestions.suggestions = [
2369
+ { text: "Cancel", note: "Standard and clear" },
2370
+ { text: "Go back", note: "If returning to previous step" },
2371
+ { text: "Discard changes", note: "If changes will be lost" }
2372
+ ];
2373
+ }
2374
+ }
2375
+ else if (elementType === "error") {
2376
+ if (context.includes("email")) {
2377
+ suggestions.suggestions = [
2378
+ { text: "Please enter a valid email address (e.g., name@example.com)", note: "Specific, with example" },
2379
+ { text: "This doesn't look like a valid email address", note: "Friendly tone" }
2380
+ ];
2381
+ suggestions.avoid = ["Invalid email", "Error"];
2382
+ }
2383
+ else if (context.includes("password")) {
2384
+ suggestions.suggestions = [
2385
+ { text: "Password must be at least 8 characters with one number", note: "Specific requirements" },
2386
+ { text: "This password is too weak. Try adding numbers or symbols.", note: "Helpful guidance" }
2387
+ ];
2388
+ }
2389
+ else if (context.includes("required")) {
2390
+ suggestions.suggestions = [
2391
+ { text: "[Field name] is required", note: "Clear and specific" },
2392
+ { text: "Please fill out this field", note: "Polite" }
2393
+ ];
2394
+ suggestions.avoid = ["This field is required", "Required"];
2395
+ }
2396
+ }
2397
+ else if (elementType === "success") {
2398
+ if (context.includes("save") || context.includes("update")) {
2399
+ suggestions.suggestions = [
2400
+ { text: "✓ Changes saved", note: "Short and confirmatory" },
2401
+ { text: "Your settings have been updated", note: "Specific" }
2402
+ ];
2403
+ }
2404
+ else if (context.includes("send") || context.includes("submit")) {
2405
+ suggestions.suggestions = [
2406
+ { text: "Message sent successfully!", note: "Celebratory" },
2407
+ { text: "✓ Submitted. We'll get back to you soon.", note: "Sets expectation" }
2408
+ ];
2409
+ }
2410
+ }
2411
+ else if (elementType === "empty-state") {
2412
+ suggestions.suggestions = [
2413
+ { text: "No [items] yet. [Action] to get started!", note: "Encouraging with CTA" },
2414
+ { text: "You're all caught up!", note: "Positive framing" },
2415
+ { text: "Nothing to show here. [Action] to add [item].", note: "Clear next step" }
2416
+ ];
2417
+ suggestions.structure = "Headline + Optional explanation + Call-to-action";
2418
+ }
2419
+ else if (elementType === "placeholder") {
2420
+ suggestions.suggestions = [
2421
+ { text: "name@example.com", note: "Show format example" },
2422
+ { text: "Search...", note: "Describe action" },
2423
+ { text: "MM/DD/YYYY", note: "Format hint" }
2424
+ ];
2425
+ suggestions.warning = "Never replace labels with placeholders - use both";
2426
+ }
2427
+ suggestions.general_guidelines = {
2428
+ clarity: "Be specific, not vague",
2429
+ conciseness: "Remove unnecessary words",
2430
+ user_centered: "Use 'you' and 'your'",
2431
+ actionable: "Start buttons with verbs",
2432
+ tone: `Maintain ${tone} tone throughout`,
2433
+ dont_blame: "Never blame the user for errors",
2434
+ be_helpful: "Provide guidance on how to fix issues"
2435
+ };
2436
+ suggestions.reference = "See ux://content/microcopy for complete UX writing guide";
2437
+ return {
2438
+ content: [
2439
+ {
2440
+ type: "text",
2441
+ text: JSON.stringify(suggestions, null, 2),
2442
+ },
2443
+ ],
2444
+ };
2445
+ }
2446
+ async function suggestFormPattern(args) {
2447
+ const formType = args.form_type.toLowerCase();
2448
+ const fieldCount = args.field_count;
2449
+ const platform = args.platform || "both";
2450
+ let pattern = {
2451
+ form_type: formType,
2452
+ field_count: fieldCount || "Not specified",
2453
+ platform
2454
+ };
2455
+ if (formType.includes("login") || formType.includes("sign in")) {
2456
+ pattern.layout = "Single column, simple and focused";
2457
+ pattern.fields = [
2458
+ { name: "Email/Username", type: "email or text", required: true },
2459
+ { name: "Password", type: "password", required: true, features: ["Show/hide toggle"] },
2460
+ { name: "Remember me", type: "checkbox", required: false }
2461
+ ];
2462
+ pattern.additional_elements = [
2463
+ "Forgot password link (prominent)",
2464
+ "Social login options (optional)",
2465
+ "Sign up link"
2466
+ ];
2467
+ pattern.validation = "On submit (least intrusive)";
2468
+ pattern.submit_button = "Sign in";
2469
+ }
2470
+ else if (formType.includes("registration") || formType.includes("signup")) {
2471
+ pattern.layout = "Single column, progressively disclose optional fields";
2472
+ pattern.fields = [
2473
+ { name: "Email", type: "email", required: true },
2474
+ { name: "Password", type: "password", required: true, features: ["Strength indicator", "Requirements shown upfront"] },
2475
+ { name: "Confirm password", type: "password", required: true },
2476
+ { name: "Name", type: "text", required: true }
2477
+ ];
2478
+ pattern.recommendations = [
2479
+ "Keep minimal - only essential fields",
2480
+ "Consider social signup to reduce friction",
2481
+ "Show password requirements before user types",
2482
+ "Validate username availability inline (debounced)",
2483
+ "Terms acceptance checkbox"
2484
+ ];
2485
+ pattern.validation = "Inline on blur + submit validation";
2486
+ }
2487
+ else if (formType.includes("checkout") || formType.includes("payment")) {
2488
+ if (fieldCount && fieldCount > 10) {
2489
+ pattern.layout = "Multi-step wizard with progress indicator";
2490
+ pattern.steps = [
2491
+ { step: 1, name: "Contact info", fields: ["Email", "Phone"] },
2492
+ { step: 2, name: "Shipping address", fields: ["Address fields"] },
2493
+ { step: 3, name: "Payment method", fields: ["Card details"] },
2494
+ { step: 4, name: "Review & confirm", fields: ["Order summary"] }
2495
+ ];
2496
+ }
2497
+ else {
2498
+ pattern.layout = "Single page with clear sections";
2499
+ pattern.sections = ["Contact", "Shipping", "Payment", "Order summary"];
2500
+ }
2501
+ pattern.features = [
2502
+ "Address autocomplete",
2503
+ "Save info for future",
2504
+ "Guest checkout option",
2505
+ "Order summary always visible",
2506
+ "Progress saving (don't lose data)",
2507
+ "Clear error recovery"
2508
+ ];
2509
+ pattern.mobile_considerations = [
2510
+ "Use appropriate input types (tel, email)",
2511
+ "Autocomplete attributes for autofill",
2512
+ "Large touch targets",
2513
+ "Single column layout"
2514
+ ];
2515
+ }
2516
+ else if (formType.includes("search")) {
2517
+ pattern.layout = "Horizontal search bar";
2518
+ pattern.components = [
2519
+ { element: "Input", type: "search", attributes: ["autocomplete", "placeholder"] },
2520
+ { element: "Search button", optional: "Often submit on Enter" },
2521
+ { element: "Clear button", show: "When input has value" }
2522
+ ];
2523
+ pattern.features = [
2524
+ "Autocomplete suggestions (after 2-3 characters)",
2525
+ "Recent searches",
2526
+ "Debounce requests (300ms)",
2527
+ "Keyboard navigation (arrow keys)",
2528
+ "Escape to clear"
2529
+ ];
2530
+ }
2531
+ else if (formType.includes("contact")) {
2532
+ pattern.layout = "Single column, simple";
2533
+ pattern.fields = [
2534
+ { name: "Name", type: "text", required: true },
2535
+ { name: "Email", type: "email", required: true },
2536
+ { name: "Subject", type: "text", required: false },
2537
+ { name: "Message", type: "textarea", required: true, rows: 4 }
2538
+ ];
2539
+ pattern.optional_features = [
2540
+ "File attachment",
2541
+ "CAPTCHA (only after suspicious activity)",
2542
+ "Character count for message"
2543
+ ];
2544
+ pattern.submit_button = "Send message";
2545
+ pattern.success = "Show confirmation message with next steps";
2546
+ }
2547
+ pattern.universal_best_practices = [
2548
+ "Single column layout (especially mobile)",
2549
+ "Mark required fields with * or (required)",
2550
+ "Use appropriate input types for mobile keyboards",
2551
+ "Enable autocomplete where appropriate",
2552
+ "Provide inline validation (on blur)",
2553
+ "Show specific, helpful error messages",
2554
+ "Disable submit during processing",
2555
+ "Show success confirmation",
2556
+ "Never lose user data on errors",
2557
+ "Support keyboard navigation"
2558
+ ];
2559
+ pattern.mobile_optimization = [
2560
+ "Touch targets minimum 44x44px",
2561
+ "Use inputmode for number/decimal inputs",
2562
+ "Handle virtual keyboard appropriately",
2563
+ "Full-width inputs with padding",
2564
+ "Ample spacing between fields (8-16px)"
2565
+ ];
2566
+ pattern.accessibility = [
2567
+ "All inputs have labels (visible preferred)",
2568
+ "Use fieldset and legend for groups",
2569
+ "aria-invalid and aria-describedby for errors",
2570
+ "Focus management",
2571
+ "Keyboard accessible"
2572
+ ];
2573
+ pattern.reference = "See ux://forms/patterns for complete form design patterns";
2574
+ return {
2575
+ content: [
2576
+ {
2577
+ type: "text",
2578
+ text: JSON.stringify(pattern, null, 2),
2579
+ },
2580
+ ],
2581
+ };
2582
+ }
2583
+ async function analyzeDataViz(args) {
2584
+ const chartType = args.chart_type.toLowerCase();
2585
+ const dataDescription = args.data_description;
2586
+ const purpose = args.purpose?.toLowerCase();
2587
+ let analysis = {
2588
+ chart_type: chartType,
2589
+ data_description: dataDescription,
2590
+ purpose: purpose || "Not specified",
2591
+ assessment: {}
2592
+ };
2593
+ // Assess chart type appropriateness
2594
+ if (chartType.includes("pie") || chartType.includes("donut")) {
2595
+ analysis.appropriateness = {
2596
+ rating: "Caution",
2597
+ notes: "Pie charts often not the best choice",
2598
+ better_alternative: "Bar chart (easier to compare values)",
2599
+ ok_when: "< 6 segments, showing parts of whole",
2600
+ avoid_when: "> 6 segments, comparing values, need precision"
2601
+ };
2602
+ }
2603
+ else if (chartType.includes("bar") || chartType.includes("column")) {
2604
+ analysis.appropriateness = {
2605
+ rating: "Good",
2606
+ notes: "Bar charts are versatile and clear",
2607
+ best_for: "Comparing categories, ranking data",
2608
+ orientation: "Horizontal for many categories or long labels"
2609
+ };
2610
+ }
2611
+ else if (chartType.includes("line")) {
2612
+ analysis.appropriateness = {
2613
+ rating: "Excellent for trends",
2614
+ best_for: "Time series, continuous data, trends",
2615
+ limit: "5-7 lines maximum for readability",
2616
+ alternatives: "Small multiples for many series"
2617
+ };
2618
+ }
2619
+ // Check purpose alignment
2620
+ if (purpose === "comparison" && chartType.includes("pie")) {
2621
+ analysis.purpose_alignment = {
2622
+ rating: "Poor",
2623
+ issue: "Pie charts are hard to compare accurately",
2624
+ recommendation: "Use bar chart instead"
2625
+ };
2626
+ }
2627
+ else if (purpose === "trend" && !chartType.includes("line") && !chartType.includes("area")) {
2628
+ analysis.purpose_alignment = {
2629
+ rating: "Fair",
2630
+ recommendation: "Line chart usually better for showing trends over time"
2631
+ };
2632
+ }
2633
+ // Accessibility checklist
2634
+ analysis.accessibility = {
2635
+ color: {
2636
+ requirement: "Don't rely on color alone to convey information",
2637
+ checks: [
2638
+ "Use patterns/shapes in addition to color",
2639
+ "Maintain 3:1 contrast ratio for chart elements",
2640
+ "Use colorblind-safe palette",
2641
+ "Test with colorblind simulator"
2642
+ ]
2643
+ },
2644
+ alt_text: {
2645
+ requirement: "Provide descriptive alt text",
2646
+ example: `alt='${chartType} showing ${dataDescription} - [describe key insight]'`
2647
+ },
2648
+ data_table: {
2649
+ requirement: "Provide data table alternative",
2650
+ implementation: "Accessible HTML table with proper headers"
2651
+ },
2652
+ keyboard: {
2653
+ requirement: "All interactive elements keyboard accessible",
2654
+ checks: ["Tooltips show on focus", "Logical tab order", "Escape closes tooltips"]
2655
+ }
2656
+ };
2657
+ // Design recommendations
2658
+ analysis.design_recommendations = {
2659
+ title: "Clear, descriptive title",
2660
+ axes: "Label axes with units",
2661
+ legend: "Include legend if multiple series",
2662
+ tooltips: "Show data values on hover/tap",
2663
+ gridlines: "Light, subtle gridlines",
2664
+ whitespace: "Don't cram - leave breathing room",
2665
+ data_labels: "Consider direct labels instead of just legend"
2666
+ };
2667
+ // Specific chart guidance
2668
+ if (chartType.includes("bar") || chartType.includes("column")) {
2669
+ analysis.specific_guidance = {
2670
+ y_axis: "Start at zero (don't truncate)",
2671
+ sorting: "Sort by value unless natural order exists",
2672
+ colors: "Consistent color unless highlighting specific bar",
2673
+ width: "Keep bars same width",
2674
+ avoid: "3D effects, unnecessary decoration"
2675
+ };
2676
+ }
2677
+ else if (chartType.includes("line")) {
2678
+ analysis.specific_guidance = {
2679
+ points: "Show data point markers",
2680
+ lines: "Use distinct colors and patterns",
2681
+ limit: "Maximum 5-7 lines",
2682
+ direct_labels: "Label lines directly, not just in legend",
2683
+ y_axis: "Can start above zero if trend matters more than magnitude (make obvious)"
2684
+ };
2685
+ }
2686
+ else if (chartType.includes("pie") || chartType.includes("donut")) {
2687
+ analysis.specific_guidance = {
2688
+ segments: "Limit to 5-6 maximum",
2689
+ start: "Start at 12 o'clock",
2690
+ order: "Sort by size (largest first)",
2691
+ labels: "Label directly with percentages",
2692
+ avoid: "3D effects, exploding multiple segments"
2693
+ };
2694
+ }
2695
+ // Performance considerations
2696
+ if (dataDescription.toLowerCase().includes("large") || dataDescription.toLowerCase().includes("many")) {
2697
+ analysis.performance = {
2698
+ concern: "Large dataset may impact performance",
2699
+ strategies: [
2700
+ "Aggregate data (e.g., daily to weekly)",
2701
+ "Sample representative subset",
2702
+ "Use Canvas instead of SVG for > 1000 points",
2703
+ "Implement virtualization for scrolling charts",
2704
+ "Progressive loading"
2705
+ ]
2706
+ };
2707
+ }
2708
+ analysis.reference = "See ux://data-viz/patterns for complete data visualization guide";
2709
+ analysis.recommended_tools = [
2710
+ "D3.js (maximum flexibility)",
2711
+ "Chart.js (simple, clean charts)",
2712
+ "Recharts (React components)",
2713
+ "Plotly (interactive, scientific)"
2714
+ ];
2715
+ return {
2716
+ content: [
2717
+ {
2718
+ type: "text",
2719
+ text: JSON.stringify(analysis, null, 2),
2720
+ },
2721
+ ],
2722
+ };
2723
+ }
2724
+ async function generateAccessibilityReport(args) {
2725
+ const url = args.url;
2726
+ const wcagLevel = args.wcag_level || "AA";
2727
+ const report = {
2728
+ url,
2729
+ wcag_level: wcagLevel,
2730
+ timestamp: new Date().toISOString(),
2731
+ summary: {},
2732
+ findings: [],
2733
+ recommendations: [],
2734
+ };
2735
+ // Automated checks (simulated comprehensive audit)
2736
+ report.automated_checks = {
2737
+ semantic_html: {
2738
+ status: "review_needed",
2739
+ checks: ["Proper heading hierarchy (H1 → H2 → H3)", "Semantic elements (<main>, <nav>, <article>)", "Form structure"]
2740
+ },
2741
+ keyboard_navigation: {
2742
+ status: "review_needed",
2743
+ checks: ["All interactive elements focusable", "Logical tab order", "Visible focus indicators", "No keyboard traps", "Skip links present"]
2744
+ },
2745
+ screen_reader: {
2746
+ status: "review_needed",
2747
+ checks: ["Alt text on images", "ARIA labels on icon buttons", "Form labels", "Live regions for dynamic content", "Heading structure"]
2748
+ },
2749
+ color_contrast: {
2750
+ status: "review_needed",
2751
+ minimum: wcagLevel === "AAA" ? "7:1 (normal text), 4.5:1 (large text)" : "4.5:1 (normal text), 3:1 (large text)"
2752
+ }
2753
+ };
2754
+ // Common issues to check
2755
+ report.findings = [
2756
+ { severity: "critical", category: "Images", issue: "Check for images without alt text", wcag: "1.1.1" },
2757
+ { severity: "critical", category: "Forms", issue: "Verify all inputs have associated labels", wcag: "3.3.2" },
2758
+ { severity: "major", category: "Color", issue: "Ensure sufficient color contrast for all text", wcag: "1.4.3" },
2759
+ { severity: "major", category: "Keyboard", issue: "Test all functionality is keyboard accessible", wcag: "2.1.1" },
2760
+ { severity: "major", category: "Focus", issue: "Verify visible focus indicators on all interactive elements", wcag: "2.4.7" },
2761
+ { severity: "moderate", category: "Headings", issue: "Check heading hierarchy is logical (no skipped levels)", wcag: "2.4.6" },
2762
+ { severity: "moderate", category: "Links", issue: "Ensure link text is descriptive (avoid 'click here')", wcag: "2.4.4" },
2763
+ { severity: "minor", category: "Language", issue: "Verify lang attribute on <html> tag", wcag: "3.1.1" }
2764
+ ];
2765
+ // Recommendations
2766
+ report.recommendations = [
2767
+ { priority: "high", action: "Run automated audit with axe DevTools or Lighthouse" },
2768
+ { priority: "high", action: "Test keyboard navigation (Tab, Shift+Tab, Enter, Escape)" },
2769
+ { priority: "high", action: "Test with screen reader (NVDA on Windows, VoiceOver on Mac)" },
2770
+ { priority: "medium", action: "Check color contrast with Contrast Checker tool" },
2771
+ { priority: "medium", action: "Test at 200% zoom (WCAG 1.4.4)" },
2772
+ { priority: "medium", action: "Review with accessibility checklist" },
2773
+ { priority: "low", action: "Test with real users who use assistive technology" }
2774
+ ];
2775
+ // Testing workflow
2776
+ report.testing_workflow = {
2777
+ step_1: "Automated testing (axe DevTools, Lighthouse) - catches ~40% of issues",
2778
+ step_2: "Keyboard testing - Tab through all interactive elements",
2779
+ step_3: "Screen reader testing - Navigate with NVDA/VoiceOver",
2780
+ step_4: "Manual checklist - WCAG quick reference",
2781
+ step_5: "User testing - Test with real users with disabilities (critical for high-stakes sites)"
2782
+ };
2783
+ report.tools = {
2784
+ browser_extensions: ["axe DevTools", "WAVE", "Lighthouse (Chrome DevTools)"],
2785
+ screen_readers: ["NVDA (free, Windows)", "JAWS (paid, Windows)", "VoiceOver (built-in, macOS/iOS)", "TalkBack (built-in, Android)"],
2786
+ contrast_checkers: ["WebAIM Contrast Checker", "Color Oracle (colorblindness simulator)"],
2787
+ testing_platforms: ["Fable (test with real users)", "AccessibilityOz"]
2788
+ };
2789
+ report.reference = "See ux://accessibility/wcag for complete WCAG guidelines";
2790
+ return {
2791
+ content: [{ type: "text", text: JSON.stringify(report, null, 2) }]
2792
+ };
2793
+ }
2794
+ async function suggestABVariant(args) {
2795
+ const element = args.element.toLowerCase();
2796
+ const goal = args.goal.toLowerCase();
2797
+ const currentPerformance = args.current_performance;
2798
+ const suggestion = {
2799
+ element,
2800
+ goal,
2801
+ current_performance: currentPerformance,
2802
+ hypothesis: "",
2803
+ variants: [],
2804
+ metrics_to_track: [],
2805
+ sample_size: {},
2806
+ duration: "1-2 weeks minimum (account for weekly cycles)",
2807
+ };
2808
+ // Generate hypothesis
2809
+ suggestion.hypothesis = `If we modify the ${element}, then ${goal} will improve because [reason based on best practices]`;
2810
+ // Generate variants based on element type
2811
+ if (element.includes("button") || element.includes("cta")) {
2812
+ suggestion.variants = [
2813
+ {
2814
+ variant: "A (Control)",
2815
+ description: "Current version",
2816
+ changes: "No changes (baseline)"
2817
+ },
2818
+ {
2819
+ variant: "B",
2820
+ description: "Action-oriented copy",
2821
+ changes: "Change button text to specific action verb (e.g., 'Get Started' vs 'Submit', 'Start Free Trial' vs 'Sign Up')",
2822
+ rationale: "Specific, action-oriented CTAs convert better"
2823
+ },
2824
+ {
2825
+ variant: "C",
2826
+ description: "Contrasting color",
2827
+ changes: "Use high-contrast color for button (test complementary color to background)",
2828
+ rationale: "Higher visual prominence improves click-through"
2829
+ },
2830
+ {
2831
+ variant: "D (optional)",
2832
+ description: "Size + placement",
2833
+ changes: "Larger button + above the fold placement",
2834
+ rationale: "Visibility and accessibility"
2835
+ }
2836
+ ];
2837
+ suggestion.metrics_to_track = ["Click-through rate (CTR)", "Conversion rate", "Bounce rate", "Time to click"];
2838
+ }
2839
+ else if (element.includes("headline") || element.includes("title")) {
2840
+ suggestion.variants = [
2841
+ {
2842
+ variant: "A (Control)",
2843
+ description: "Current headline",
2844
+ changes: "No changes"
2845
+ },
2846
+ {
2847
+ variant: "B",
2848
+ description: "Benefit-focused",
2849
+ changes: "Lead with benefit, not feature (e.g., 'Save 10 hours per week' vs 'Task automation software')",
2850
+ rationale: "Users care about outcomes, not features"
2851
+ },
2852
+ {
2853
+ variant: "C",
2854
+ description: "Question format",
2855
+ changes: "Pose question that addresses pain point (e.g., 'Tired of manual data entry?')",
2856
+ rationale: "Questions engage and create relatability"
2857
+ }
2858
+ ];
2859
+ suggestion.metrics_to_track = ["Scroll depth", "Time on page", "Conversion rate", "Bounce rate"];
2860
+ }
2861
+ else if (element.includes("pricing")) {
2862
+ suggestion.variants = [
2863
+ {
2864
+ variant: "A (Control)",
2865
+ description: "Current pricing display",
2866
+ changes: "No changes"
2867
+ },
2868
+ {
2869
+ variant: "B",
2870
+ description: "Annual vs monthly",
2871
+ changes: "Default to annual pricing with monthly breakdown ($49/mo billed annually)",
2872
+ rationale: "Higher perceived value, longer commitments"
2873
+ },
2874
+ {
2875
+ variant: "C",
2876
+ description: "Highlighted tier",
2877
+ changes: "Visually emphasize 'most popular' tier (border, badge, larger)",
2878
+ rationale: "Social proof + visual hierarchy guides decisions"
2879
+ }
2880
+ ];
2881
+ suggestion.metrics_to_track = ["Conversion rate", "Average order value", "Plan selection distribution"];
2882
+ }
2883
+ else {
2884
+ // Generic variants
2885
+ suggestion.variants = [
2886
+ {
2887
+ variant: "A (Control)",
2888
+ description: "Current version",
2889
+ changes: "No changes"
2890
+ },
2891
+ {
2892
+ variant: "B",
2893
+ description: "Simplified version",
2894
+ changes: "Remove unnecessary elements, reduce visual complexity",
2895
+ rationale: "Less cognitive load improves completion"
2896
+ },
2897
+ {
2898
+ variant: "C",
2899
+ description: "Enhanced clarity",
2900
+ changes: "Clearer labels, better visual hierarchy, stronger contrast",
2901
+ rationale: "Clarity reduces confusion and abandonment"
2902
+ }
2903
+ ];
2904
+ suggestion.metrics_to_track = ["Conversion rate", "Bounce rate", "Time on task", "Error rate"];
2905
+ }
2906
+ // Sample size calculation
2907
+ suggestion.sample_size = {
2908
+ note: "Use A/B test sample size calculator",
2909
+ factors: ["Current conversion rate", "Minimum detectable effect (e.g., 10% improvement)", "Statistical significance (95%)", "Statistical power (80%)"],
2910
+ rule_of_thumb: "Minimum 100 conversions per variant for reliable results",
2911
+ calculator: "https://www.optimizely.com/sample-size-calculator/"
2912
+ };
2913
+ // Best practices
2914
+ suggestion.best_practices = [
2915
+ "Test one variable at a time (isolate cause)",
2916
+ "Run test for full 1-2 weeks (account for weekly patterns)",
2917
+ "Ensure statistical significance (p < 0.05)",
2918
+ "Segment results (mobile vs desktop, traffic source)",
2919
+ "Don't stop test early (even if winning)",
2920
+ "Account for external factors (holidays, marketing campaigns)",
2921
+ "Document results and learnings"
2922
+ ];
2923
+ suggestion.reference = "See ux://testing/validation for complete A/B testing guide";
2924
+ return {
2925
+ content: [{ type: "text", text: JSON.stringify(suggestion, null, 2) }]
2926
+ };
2927
+ }
2928
+ async function analyzeInformationArchitecture(args) {
2929
+ const siteStructure = args.site_structure;
2930
+ const userGoals = args.user_goals;
2931
+ const issues = args.issues;
2932
+ const analysis = {
2933
+ site_structure: siteStructure,
2934
+ user_goals: userGoals,
2935
+ issues: issues || "Not specified",
2936
+ assessment: {},
2937
+ recommendations: [],
2938
+ };
2939
+ // Analyze structure depth
2940
+ const structureLower = siteStructure.toLowerCase();
2941
+ if (structureLower.includes("level") || structureLower.includes("tier") || structureLower.includes(">")) {
2942
+ const depth = (siteStructure.match(/>/g) || []).length + 1;
2943
+ analysis.assessment.hierarchy_depth = {
2944
+ current: `~${depth} levels`,
2945
+ recommendation: depth > 4 ? "Too deep - aim for 3-4 levels max" : "Good depth",
2946
+ issue: depth > 4 ? "Users get lost in deep hierarchies" : null
2947
+ };
2948
+ }
2949
+ // Check for issues keywords
2950
+ analysis.assessment.common_issues = [];
2951
+ if (structureLower.includes("confus") || issues?.toLowerCase().includes("confus")) {
2952
+ analysis.assessment.common_issues.push({
2953
+ issue: "Confusing labels",
2954
+ recommendation: "Use card sorting to understand user mental models",
2955
+ action: "Conduct open card sorting with 15-30 users"
2956
+ });
2957
+ }
2958
+ if (structureLower.includes("too many") || issues?.toLowerCase().includes("too many")) {
2959
+ analysis.assessment.common_issues.push({
2960
+ issue: "Too many navigation items",
2961
+ recommendation: "Limit top-level navigation to 5-7 items (Miller's Law: 7±2)",
2962
+ action: "Group related items, use mega menu for subcategories"
2963
+ });
2964
+ }
2965
+ if (structureLower.includes("search") || issues?.toLowerCase().includes("find")) {
2966
+ analysis.assessment.common_issues.push({
2967
+ issue: "Findability problems",
2968
+ recommendation: "Improve search and navigation",
2969
+ action: "Add autocomplete search, breadcrumbs, related links"
2970
+ });
2971
+ }
2972
+ // Recommendations based on user goals
2973
+ analysis.recommendations = [
2974
+ {
2975
+ priority: "high",
2976
+ recommendation: "Conduct card sorting to validate IA",
2977
+ method: "Open card sorting (users create categories), then closed card sorting (validate proposed IA)",
2978
+ tool: "OptimalSort, UserZoom, or Miro"
2979
+ },
2980
+ {
2981
+ priority: "high",
2982
+ recommendation: "Run tree testing to validate findability",
2983
+ method: "Give users tasks ('Find your order history'), measure success rate and path",
2984
+ tool: "Treejack (Optimal Workshop), UserZoom",
2985
+ target: "> 80% success rate"
2986
+ },
2987
+ {
2988
+ priority: "medium",
2989
+ recommendation: "Review navigation labels",
2990
+ check: ["Use user language (not jargon)", "Be specific (avoid 'More', 'Other', 'Resources')", "Keep short (1-2 words)", "Consistent capitalization"]
2991
+ },
2992
+ {
2993
+ priority: "medium",
2994
+ recommendation: "Ensure multiple paths to content",
2995
+ methods: ["Global navigation", "Search (with autocomplete)", "Related links", "Breadcrumbs", "Footer sitemap"]
2996
+ },
2997
+ {
2998
+ priority: "low",
2999
+ recommendation: "Create sitemap",
3000
+ purpose: "Visual representation for stakeholders, SEO, user reference"
3001
+ }
3002
+ ];
3003
+ // Best practices
3004
+ analysis.best_practices = {
3005
+ hierarchy: "Keep shallow (3-4 levels max)",
3006
+ navigation: "5-7 top-level items",
3007
+ labels: "Clear, user-centered, avoid jargon",
3008
+ findability: "Multiple access paths (nav, search, links)",
3009
+ breadcrumbs: "Use for deep sites",
3010
+ mobile: "Consider mobile navigation (hamburger + search)",
3011
+ testing: "Validate with tree testing before design"
3012
+ };
3013
+ analysis.research_methods = {
3014
+ card_sorting: "Understand how users categorize content",
3015
+ tree_testing: "Validate findability in structure (no design)",
3016
+ user_interviews: "Understand mental models and tasks",
3017
+ analytics: "See how users actually navigate (top pages, search queries, exit pages)",
3018
+ first_click_testing: "Where users click first for a task"
3019
+ };
3020
+ analysis.reference = "See ux://ia/information-architecture for complete IA guide";
3021
+ return {
3022
+ content: [{ type: "text", text: JSON.stringify(analysis, null, 2) }]
3023
+ };
3024
+ }
3025
+ async function detectDarkPatterns(args) {
3026
+ const flowDescription = args.flow_description.toLowerCase();
3027
+ const screenshotUrl = args.screenshot_url;
3028
+ const detection = {
3029
+ flow: args.flow_description,
3030
+ screenshot: screenshotUrl || "Not provided",
3031
+ detected_patterns: [],
3032
+ severity_score: 0,
3033
+ ethical_alternatives: [],
3034
+ };
3035
+ // Detect dark patterns based on keywords
3036
+ if (flowDescription.includes("cancel") || flowDescription.includes("unsubscribe")) {
3037
+ detection.detected_patterns.push({
3038
+ type: "Forced Continuity / Roach Motel",
3039
+ description: "Making it hard to cancel subscription",
3040
+ examples: ["Must call to cancel (can't do online)", "Buried in settings", "Multiple confirmations", "Retention dark patterns"],
3041
+ severity: "critical",
3042
+ ethical_alternative: "Cancel button in account settings, one confirmation, done. Same ease as sign-up."
3043
+ });
3044
+ }
3045
+ if (flowDescription.includes("cookie") || flowDescription.includes("consent")) {
3046
+ detection.detected_patterns.push({
3047
+ type: "Misdirection / Visual Prominence",
3048
+ description: "Giant 'Accept All' button, tiny 'Reject' link",
3049
+ severity: "major",
3050
+ example: "Large green 'Accept All Cookies' button, small gray 'Reject' text link",
3051
+ ethical_alternative: "Equal visual weight for Accept and Reject options. Clear 'Necessary Only' option."
3052
+ });
3053
+ detection.detected_patterns.push({
3054
+ type: "Obstruction / Hidden Options",
3055
+ description: "Hiding 'Reject All' behind multiple clicks",
3056
+ severity: "major",
3057
+ example: "Must click 'Manage Preferences' → scroll → find 'Reject All'",
3058
+ ethical_alternative: "Reject All button on first screen, same prominence as Accept All",
3059
+ legal: "GDPR requires equal ease for accept/reject"
3060
+ });
3061
+ }
3062
+ if (flowDescription.includes("checkout") || flowDescription.includes("cart")) {
3063
+ detection.detected_patterns.push({
3064
+ type: "Sneaking / Hidden Costs",
3065
+ description: "Revealing costs late in checkout",
3066
+ severity: "critical",
3067
+ example: "$50 product, but $80 at checkout (shipping, fees revealed late)",
3068
+ ethical_alternative: "Show total cost upfront, or clearly separate fees early in process"
3069
+ });
3070
+ detection.detected_patterns.push({
3071
+ type: "Sneak into Basket",
3072
+ description: "Adding items without user knowledge",
3073
+ severity: "major",
3074
+ example: "Insurance or warranty auto-added to cart",
3075
+ ethical_alternative: "Offer as optional add-on with clear, unchecked checkbox"
3076
+ });
3077
+ }
3078
+ if (flowDescription.includes("notification") || flowDescription.includes("permission")) {
3079
+ detection.detected_patterns.push({
3080
+ type: "Nagging",
3081
+ description: "Repeatedly asking after user declined",
3082
+ severity: "moderate",
3083
+ example: "Pop-up asking for notifications every visit after decline",
3084
+ ethical_alternative: "Ask once, or after delivering significant value. Respect 'no'."
3085
+ });
3086
+ }
3087
+ if (flowDescription.includes("sign up") || flowDescription.includes("account")) {
3088
+ detection.detected_patterns.push({
3089
+ type: "Privacy Zuckering",
3090
+ description: "Tricking users into sharing more data than intended",
3091
+ severity: "major",
3092
+ example: "Pre-checked boxes to share data with partners",
3093
+ ethical_alternative: "Unchecked by default, clear opt-in, explain why"
3094
+ });
3095
+ detection.detected_patterns.push({
3096
+ type: "Forced Enrollment",
3097
+ description: "Requiring account for basic functionality",
3098
+ severity: "moderate",
3099
+ example: "Can't view content without creating account",
3100
+ ethical_alternative: "Guest checkout, browse without account, optional sign-up"
3101
+ });
3102
+ }
3103
+ // Generic patterns to check for
3104
+ if (flowDescription.includes("no thanks") || flowDescription.includes("decline")) {
3105
+ detection.detected_patterns.push({
3106
+ type: "Confirmshaming",
3107
+ description: "Guilt-tripping decline option",
3108
+ severity: "moderate",
3109
+ example: "'No thanks, I don't want to save money' as decline button",
3110
+ ethical_alternative: "Neutral wording: 'No thanks' or 'Maybe later'"
3111
+ });
3112
+ }
3113
+ if (flowDescription.includes("only") || flowDescription.includes("left") || flowDescription.includes("viewing")) {
3114
+ detection.detected_patterns.push({
3115
+ type: "Fake Urgency / Scarcity",
3116
+ description: "False claims of limited availability",
3117
+ severity: "moderate",
3118
+ example: "'Only 2 left in stock!' but always 2 left, or '500 people viewing!' (not true)",
3119
+ ethical_alternative: "Real scarcity only, or don't use scarcity tactics"
3120
+ });
3121
+ }
3122
+ // Calculate severity score
3123
+ const severityMap = { critical: 3, major: 2, moderate: 1, minor: 0.5 };
3124
+ detection.severity_score = detection.detected_patterns.reduce((sum, p) => sum + (severityMap[p.severity] || 0), 0);
3125
+ // Overall assessment
3126
+ if (detection.severity_score >= 6) {
3127
+ detection.overall_assessment = "SEVERE: Multiple critical dark patterns detected. This violates user trust and may violate GDPR/CCPA.";
3128
+ }
3129
+ else if (detection.severity_score >= 3) {
3130
+ detection.overall_assessment = "MODERATE: Several dark patterns detected. Consider ethical alternatives.";
3131
+ }
3132
+ else if (detection.detected_patterns.length > 0) {
3133
+ detection.overall_assessment = "MINOR: Some questionable patterns detected. Review for ethical design.";
3134
+ }
3135
+ else {
3136
+ detection.overall_assessment = "No obvious dark patterns detected from description. Manual review recommended.";
3137
+ }
3138
+ // Ethical design principles
3139
+ detection.ethical_design_principles = [
3140
+ "Transparency: Be honest about costs, terms, data usage",
3141
+ "User control: Make opting out as easy as opting in",
3142
+ "Respect decisions: Don't nag after user declines",
3143
+ "Honest social proof: Use verified reviews, real stats only",
3144
+ "Equal visual weight: Accept and reject options should be equally prominent",
3145
+ "GDPR/CCPA compliance: Required for legal reasons, good for ethics too"
3146
+ ];
3147
+ detection.legal_risks = {
3148
+ gdpr: "Many dark patterns violate GDPR (non-consensual data collection, hard to withdraw consent)",
3149
+ ftc: "FTC has issued warnings and fines for deceptive practices",
3150
+ california_ab_2571: "California explicitly bans dark patterns in subscriptions"
3151
+ };
3152
+ detection.reference = "See ux://ethics/dark-patterns for complete dark pattern guide";
3153
+ return {
3154
+ content: [{ type: "text", text: JSON.stringify(detection, null, 2) }]
3155
+ };
3156
+ }
3157
+ async function calculateUXMetrics(args) {
3158
+ const metricType = args.metric_type;
3159
+ const rawData = args.data;
3160
+ const result = {
3161
+ metric_type: metricType,
3162
+ raw_data: rawData,
3163
+ calculation: {},
3164
+ interpretation: "",
3165
+ benchmark: "",
3166
+ };
3167
+ if (metricType === "SUS") {
3168
+ // System Usability Scale (10 questions, 1-5 scale)
3169
+ // Extract numbers from data string
3170
+ const responses = rawData.match(/\d+/g)?.map(Number) || [];
3171
+ if (responses.length !== 10) {
3172
+ result.error = "SUS requires exactly 10 responses (one per question)";
3173
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
3174
+ }
3175
+ // SUS calculation: Sum((odd - 1) + (5 - even)) * 2.5
3176
+ let score = 0;
3177
+ for (let i = 0; i < 10; i++) {
3178
+ if (i % 2 === 0) {
3179
+ // Odd questions (1,3,5,7,9): subtract 1
3180
+ score += responses[i] - 1;
3181
+ }
3182
+ else {
3183
+ // Even questions (2,4,6,8,10): subtract from 5
3184
+ score += 5 - responses[i];
3185
+ }
3186
+ }
3187
+ score = score * 2.5;
3188
+ result.calculation = {
3189
+ responses,
3190
+ sus_score: score.toFixed(1),
3191
+ formula: "Sum of [(odd questions - 1) + (5 - even questions)] × 2.5"
3192
+ };
3193
+ result.interpretation =
3194
+ score >= 80 ? "Excellent (A+): Users love this product" :
3195
+ score >= 68 ? "Good (B): Above average usability" :
3196
+ score >= 50 ? "OK (C): Average usability, room for improvement" :
3197
+ "Poor (D/F): Significant usability issues";
3198
+ result.benchmark = {
3199
+ excellent: "> 80",
3200
+ above_average: "68-80",
3201
+ average: "50-68",
3202
+ below_average: "< 50",
3203
+ note: "68 is the average SUS score across all products"
3204
+ };
3205
+ }
3206
+ else if (metricType === "NPS") {
3207
+ // Net Promoter Score (0-10 scale)
3208
+ const scores = rawData.match(/\d+/g)?.map(Number) || [];
3209
+ const promoters = scores.filter(s => s >= 9).length;
3210
+ const detractors = scores.filter(s => s <= 6).length;
3211
+ const total = scores.length;
3212
+ const nps = ((promoters / total) - (detractors / total)) * 100;
3213
+ result.calculation = {
3214
+ total_responses: total,
3215
+ promoters: `${promoters} (scores 9-10)`,
3216
+ passives: `${scores.filter(s => s === 7 || s === 8).length} (scores 7-8)`,
3217
+ detractors: `${detractors} (scores 0-6)`,
3218
+ nps_score: nps.toFixed(1),
3219
+ formula: "(% Promoters - % Detractors)"
3220
+ };
3221
+ result.interpretation =
3222
+ nps >= 50 ? "Excellent: Strong customer loyalty" :
3223
+ nps >= 30 ? "Great: Good growth potential" :
3224
+ nps >= 0 ? "Good: More promoters than detractors" :
3225
+ "Poor: More detractors than promoters, address issues";
3226
+ result.benchmark = {
3227
+ excellent: "> 50",
3228
+ great: "30-50",
3229
+ good: "0-30",
3230
+ poor: "< 0",
3231
+ note: "NPS varies widely by industry. SaaS average is ~30-40."
3232
+ };
3233
+ }
3234
+ else if (metricType === "CSAT") {
3235
+ // Customer Satisfaction (typically 1-5 scale)
3236
+ const scores = rawData.match(/\d+/g)?.map(Number) || [];
3237
+ const satisfied = scores.filter(s => s >= 4).length;
3238
+ const total = scores.length;
3239
+ const csat = (satisfied / total) * 100;
3240
+ result.calculation = {
3241
+ total_responses: total,
3242
+ satisfied: `${satisfied} (scores 4-5)`,
3243
+ csat_score: `${csat.toFixed(1)}%`,
3244
+ formula: "(Responses 4 or 5 / Total responses) × 100"
3245
+ };
3246
+ result.interpretation =
3247
+ csat >= 80 ? "Excellent: High customer satisfaction" :
3248
+ csat >= 70 ? "Good: Above average satisfaction" :
3249
+ csat >= 60 ? "Fair: Room for improvement" :
3250
+ "Poor: Significant dissatisfaction";
3251
+ result.benchmark = {
3252
+ excellent: "> 80%",
3253
+ good: "70-80%",
3254
+ fair: "60-70%",
3255
+ poor: "< 60%"
3256
+ };
3257
+ }
3258
+ else if (metricType === "task-success") {
3259
+ // Task success rate
3260
+ const numbers = rawData.match(/\d+/g)?.map(Number) || [];
3261
+ let successful, total;
3262
+ if (numbers.length === 2) {
3263
+ successful = numbers[0];
3264
+ total = numbers[1];
3265
+ }
3266
+ else {
3267
+ successful = numbers.filter(n => n === 1).length; // Assuming 1 = success, 0 = fail
3268
+ total = numbers.length;
3269
+ }
3270
+ const successRate = (successful / total) * 100;
3271
+ result.calculation = {
3272
+ successful_completions: successful,
3273
+ total_attempts: total,
3274
+ success_rate: `${successRate.toFixed(1)}%`,
3275
+ formula: "(Successful completions / Total attempts) × 100"
3276
+ };
3277
+ result.interpretation =
3278
+ successRate >= 78 ? "Good: Above Nielsen's 78% benchmark" :
3279
+ successRate >= 60 ? "Fair: Usable but room for improvement" :
3280
+ "Poor: Significant usability issues";
3281
+ result.benchmark = {
3282
+ good: "> 78%",
3283
+ fair: "60-78%",
3284
+ poor: "< 60%",
3285
+ note: "Nielsen Norman Group benchmark: 78% average task success rate"
3286
+ };
3287
+ }
3288
+ else {
3289
+ result.error = `Unsupported metric type: ${metricType}. Supported: SUS, NPS, CSAT, CES, task-success, retention`;
3290
+ }
3291
+ result.reference = "See ux://analytics/metrics for complete UX metrics guide";
3292
+ return {
3293
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
3294
+ };
3295
+ }
3296
+ async function generateWireframe(args) {
3297
+ const pageType = args.page_type.toLowerCase();
3298
+ const elements = args.elements;
3299
+ const layout = args.layout || "single-column";
3300
+ const wireframe = {
3301
+ page_type: args.page_type,
3302
+ layout,
3303
+ elements: elements || "Not specified",
3304
+ ascii_wireframe: "",
3305
+ };
3306
+ // Generate ASCII wireframe based on page type and layout
3307
+ if (pageType.includes("login")) {
3308
+ wireframe.ascii_wireframe = `
3309
+ ┌────────────────────────────────────────────┐
3310
+ │ │
3311
+ │ [ LOGO ] │
3312
+ │ │
3313
+ │ Login to Your Account │
3314
+ │ │
3315
+ │ ┌────────────────────────────┐ │
3316
+ │ │ Email │ │
3317
+ │ └────────────────────────────┘ │
3318
+ │ │
3319
+ │ ┌────────────────────────────┐ │
3320
+ │ │ Password [👁] │ │
3321
+ │ └────────────────────────────┘ │
3322
+ │ │
3323
+ │ [ ] Remember me Forgot password? │
3324
+ │ │
3325
+ │ ┌────────────────────────────┐ │
3326
+ │ │ LOG IN BUTTON │ │
3327
+ │ └────────────────────────────┘ │
3328
+ │ │
3329
+ │ Don't have an account? Sign up │
3330
+ │ │
3331
+ └────────────────────────────────────────────┘
3332
+ `;
3333
+ }
3334
+ else if (pageType.includes("dashboard")) {
3335
+ wireframe.ascii_wireframe = `
3336
+ ┌─────────────────────────────────────────────────────────────┐
3337
+ │ [Logo] Dashboard [Search...] [Notifications] [Profile] │
3338
+ ├─────────────────────────────────────────────────────────────┤
3339
+ │ │
3340
+ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
3341
+ │ │ Card 1 │ │ Card 2 │ │ Card 3 │ │ Card 4 │ │
3342
+ │ │ Value │ │ Value │ │ Value │ │ Value │ │
3343
+ │ │ +12% │ │ +8% │ │ -3% │ │ +15% │ │
3344
+ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
3345
+ │ │
3346
+ │ ┌────────────────────────────────────────────────────┐ │
3347
+ │ │ Chart/Visualization │ │
3348
+ │ │ │ │
3349
+ │ │ ██ │ │
3350
+ │ │ ████ ██ │ │
3351
+ │ │ ██████ ██ ████ │ │
3352
+ │ │ ████████████████████ │ │
3353
+ │ └────────────────────────────────────────────────────┘ │
3354
+ │ │
3355
+ │ ┌────────────────────────────────────────────────────┐ │
3356
+ │ │ Recent Activity │ │
3357
+ │ │ • Item 1 - Description │ │
3358
+ │ │ • Item 2 - Description │ │
3359
+ │ │ • Item 3 - Description │ │
3360
+ │ └────────────────────────────────────────────────────┘ │
3361
+ │ │
3362
+ └─────────────────────────────────────────────────────────────┘
3363
+ `;
3364
+ }
3365
+ else if (pageType.includes("card") || pageType.includes("product")) {
3366
+ wireframe.ascii_wireframe = `
3367
+ ┌─────────────────────────┐
3368
+ │ │
3369
+ │ ┌─────────────────┐ │
3370
+ │ │ │ │
3371
+ │ │ Product Image │ │
3372
+ │ │ │ │
3373
+ │ └─────────────────┘ │
3374
+ │ │
3375
+ │ Product Name │
3376
+ │ Short description │
3377
+ │ │
3378
+ │ $99.99 │
3379
+ │ ★★★★☆ (24 reviews) │
3380
+ │ │
3381
+ │ ┌─────────────────┐ │
3382
+ │ │ ADD TO CART │ │
3383
+ │ └─────────────────┘ │
3384
+ │ │
3385
+ └─────────────────────────┘
3386
+ `;
3387
+ }
3388
+ else {
3389
+ // Generic wireframe
3390
+ wireframe.ascii_wireframe = `
3391
+ ┌────────────────────────────────────────────┐
3392
+ │ [Logo] Navigation Menu [☰] │
3393
+ ├────────────────────────────────────────────┤
3394
+ │ │
3395
+ │ ┌──────────────────────────────────────┐ │
3396
+ │ │ Header / Hero Section │ │
3397
+ │ │ [Image] + Headline + Description │ │
3398
+ │ └──────────────────────────────────────┘ │
3399
+ │ │
3400
+ │ ┌──────────────────────────────────────┐ │
3401
+ │ │ │ │
3402
+ │ │ Main Content Area │ │
3403
+ │ │ │ │
3404
+ │ └──────────────────────────────────────┘ │
3405
+ │ │
3406
+ │ ┌────────┐ ┌────────┐ ┌────────┐ │
3407
+ │ │ Item 1 │ │ Item 2 │ │ Item 3 │ │
3408
+ │ └────────┘ └────────┘ └────────┘ │
3409
+ │ │
3410
+ ├────────────────────────────────────────────┤
3411
+ │ Footer: Links | Contact | Social Media │
3412
+ └────────────────────────────────────────────┘
3413
+ `;
3414
+ }
3415
+ wireframe.notes = [
3416
+ "This is a low-fidelity wireframe for layout planning",
3417
+ "Use as starting point for design discussions",
3418
+ "Focus on structure and hierarchy, not visual design",
3419
+ "Iterate based on user needs and feedback"
3420
+ ];
3421
+ wireframe.next_steps = [
3422
+ "Add detailed content and copy",
3423
+ "Define interactions and micro-interactions",
3424
+ "Create high-fidelity mockup in Figma/Sketch",
3425
+ "Conduct usability testing",
3426
+ "Develop responsive versions (mobile, tablet)"
3427
+ ];
3428
+ return {
3429
+ content: [{ type: "text", text: JSON.stringify(wireframe, null, 2) }]
3430
+ };
3431
+ }
3432
+ async function suggestMicrointeraction(args) {
3433
+ const element = args.element.toLowerCase();
3434
+ const context = args.context?.toLowerCase() || "";
3435
+ const platform = args.platform || "web";
3436
+ const suggestion = {
3437
+ element: args.element,
3438
+ context: context || "General interaction",
3439
+ platform,
3440
+ microinteractions: [],
3441
+ };
3442
+ // Suggest microinteractions based on element type
3443
+ if (element.includes("button")) {
3444
+ suggestion.microinteractions = [
3445
+ {
3446
+ trigger: "Hover",
3447
+ feedback: "Background color change + slight scale up (1.05x)",
3448
+ duration: "200ms",
3449
+ easing: "ease-out"
3450
+ },
3451
+ {
3452
+ trigger: "Active/Press",
3453
+ feedback: "Scale down (0.95x) + darker background",
3454
+ duration: "100ms",
3455
+ easing: "ease-in",
3456
+ haptic: platform === "mobile" ? "Light tap (10ms)" : "N/A"
3457
+ },
3458
+ {
3459
+ trigger: "Focus",
3460
+ feedback: "Outline ring (accessibility)",
3461
+ style: "2px solid blue, 4px offset"
3462
+ }
3463
+ ];
3464
+ if (context.includes("delete") || context.includes("destructive")) {
3465
+ suggestion.microinteractions.push({
3466
+ trigger: "Click",
3467
+ feedback: "Confirmation modal with shake animation",
3468
+ duration: "300ms",
3469
+ pattern: "Shake left-right to indicate danger"
3470
+ });
3471
+ }
3472
+ else if (context.includes("success") || context.includes("save")) {
3473
+ suggestion.microinteractions.push({
3474
+ trigger: "Click success",
3475
+ feedback: "Checkmark animation + color change green",
3476
+ duration: "400ms",
3477
+ pattern: "Button → Checkmark → 'Saved!'"
3478
+ });
3479
+ }
3480
+ }
3481
+ else if (element.includes("toggle") || element.includes("switch")) {
3482
+ suggestion.microinteractions = [
3483
+ {
3484
+ trigger: "Toggle on",
3485
+ feedback: "Slide animation + color change (gray → green)",
3486
+ duration: "250ms",
3487
+ easing: "ease-in-out",
3488
+ haptic: platform === "mobile" ? "Medium tap (20ms)" : "N/A"
3489
+ },
3490
+ {
3491
+ trigger: "Toggle off",
3492
+ feedback: "Slide animation + color change (green → gray)",
3493
+ duration: "250ms",
3494
+ easing: "ease-in-out"
3495
+ }
3496
+ ];
3497
+ }
3498
+ else if (element.includes("like") || element.includes("favorite") || element.includes("heart")) {
3499
+ suggestion.microinteractions = [
3500
+ {
3501
+ trigger: "Click/Tap",
3502
+ feedback: "Heart fills with color + bounces (scale 1 → 1.2 → 1)",
3503
+ duration: "400ms",
3504
+ easing: "elastic",
3505
+ haptic: platform === "mobile" ? "Light tap" : "N/A"
3506
+ },
3507
+ {
3508
+ trigger: "Unlike",
3509
+ feedback: "Heart empties + subtle shrink",
3510
+ duration: "200ms"
3511
+ }
3512
+ ];
3513
+ }
3514
+ else if (element.includes("loading") || element.includes("spinner")) {
3515
+ suggestion.microinteractions = [
3516
+ {
3517
+ trigger: "Loading state",
3518
+ feedback: "Spinner animation OR skeleton screen OR progress bar",
3519
+ duration: "Continuous",
3520
+ pattern: "Rotating spinner or pulsing skeleton",
3521
+ note: "Show progress if duration is known"
3522
+ }
3523
+ ];
3524
+ }
3525
+ else if (element.includes("form") || element.includes("input")) {
3526
+ suggestion.microinteractions = [
3527
+ {
3528
+ trigger: "Focus",
3529
+ feedback: "Border color change + label move (floating label)",
3530
+ duration: "200ms"
3531
+ },
3532
+ {
3533
+ trigger: "Valid input",
3534
+ feedback: "Green checkmark appears",
3535
+ duration: "200ms"
3536
+ },
3537
+ {
3538
+ trigger: "Invalid input",
3539
+ feedback: "Red border + shake animation + error message",
3540
+ duration: "300ms",
3541
+ pattern: "Shake to indicate error"
3542
+ },
3543
+ {
3544
+ trigger: "Form submission success",
3545
+ feedback: "Success message + confetti animation (optional)",
3546
+ duration: "500ms"
3547
+ }
3548
+ ];
3549
+ }
3550
+ else if (element.includes("dropdown") || element.includes("menu")) {
3551
+ suggestion.microinteractions = [
3552
+ {
3553
+ trigger: "Open",
3554
+ feedback: "Fade in + slide down",
3555
+ duration: "200ms",
3556
+ easing: "ease-out"
3557
+ },
3558
+ {
3559
+ trigger: "Close",
3560
+ feedback: "Fade out + slide up",
3561
+ duration: "150ms",
3562
+ easing: "ease-in"
3563
+ },
3564
+ {
3565
+ trigger: "Hover item",
3566
+ feedback: "Background color change",
3567
+ duration: "100ms"
3568
+ }
3569
+ ];
3570
+ }
3571
+ else {
3572
+ // Generic suggestions
3573
+ suggestion.microinteractions = [
3574
+ {
3575
+ trigger: "Interaction start",
3576
+ feedback: "Visual feedback (color, scale, or position change)",
3577
+ duration: "200-300ms"
3578
+ },
3579
+ {
3580
+ trigger: "Interaction complete",
3581
+ feedback: "Confirmation (checkmark, success message, or state change)",
3582
+ duration: "300-400ms"
3583
+ }
3584
+ ];
3585
+ }
3586
+ // General principles
3587
+ suggestion.principles = [
3588
+ "Keep animations subtle (< 400ms)",
3589
+ "Use easing for natural motion (ease-out for enter, ease-in for exit)",
3590
+ "Provide immediate feedback (< 100ms)",
3591
+ "Respect prefers-reduced-motion (disable animations)",
3592
+ "Use haptic feedback on mobile (10-50ms)",
3593
+ "Ensure accessibility (feedback not only visual)",
3594
+ "Match brand personality (playful vs professional)"
3595
+ ];
3596
+ suggestion.css_example = element.includes("button") ?
3597
+ "button {\n transition: all 200ms ease-out;\n}\nbutton:hover {\n transform: scale(1.05);\n background: #0056b3;\n}\nbutton:active {\n transform: scale(0.95);\n}" : null;
3598
+ suggestion.reference = "See ux://animation/principles for complete animation guide";
3599
+ return {
3600
+ content: [{ type: "text", text: JSON.stringify(suggestion, null, 2) }]
3601
+ };
3602
+ }
3603
+ // ========================================
3604
+ // PROMPTS - Pre-configured UX Reviews
3605
+ // ========================================
3606
+ server.setRequestHandler(ListPromptsRequestSchema, async () => {
3607
+ return {
3608
+ prompts: [
3609
+ {
3610
+ name: "accessibility_review",
1609
3611
  description: "Comprehensive accessibility review following WCAG 2.1 AA guidelines",
1610
3612
  arguments: [
1611
3613
  {
@@ -1642,6 +3644,22 @@ server.setRequestHandler(ListPromptsRequestSchema, async () => {
1642
3644
  },
1643
3645
  ],
1644
3646
  },
3647
+ {
3648
+ name: "complete_ux_audit",
3649
+ description: "Comprehensive UX audit combining accessibility, usability, performance, SEO, and responsive design checks",
3650
+ arguments: [
3651
+ {
3652
+ name: "interface",
3653
+ description: "Interface or page to audit",
3654
+ required: true,
3655
+ },
3656
+ {
3657
+ name: "code",
3658
+ description: "Code to analyze (optional)",
3659
+ required: false,
3660
+ },
3661
+ ],
3662
+ },
1645
3663
  ],
1646
3664
  };
1647
3665
  });
@@ -1748,6 +3766,110 @@ Provide code examples for token definition and a starter component.`,
1748
3766
  },
1749
3767
  ],
1750
3768
  };
3769
+ case "complete_ux_audit":
3770
+ return {
3771
+ messages: [
3772
+ {
3773
+ role: "user",
3774
+ content: {
3775
+ type: "text",
3776
+ text: `Please conduct a comprehensive UX audit for: ${args?.interface}
3777
+
3778
+ ${args?.code ? `Code to analyze:\n\`\`\`\n${args.code}\n\`\`\`\n` : ""}
3779
+
3780
+ This is a complete audit covering all critical UX dimensions. Perform the following:
3781
+
3782
+ ## 1. Accessibility Audit (WCAG 2.1 AA)
3783
+ - Use analyze_accessibility tool to identify violations
3784
+ - Check keyboard navigation and focus management
3785
+ - Verify screen reader compatibility (ARIA labels, roles)
3786
+ - Test color contrast with check_contrast tool
3787
+ - Review semantic HTML and heading hierarchy
3788
+ - Check form labels and error handling
3789
+
3790
+ ## 2. Usability Heuristics (Nielsen's 10)
3791
+ - Use review_usability tool for detailed analysis
3792
+ - Rate each heuristic (0-4 severity scale)
3793
+ - Identify specific violations per heuristic
3794
+ - Provide actionable recommendations
3795
+
3796
+ ## 3. Responsive Design
3797
+ - Use check_responsive tool to analyze breakpoints
3798
+ - Verify mobile-first approach
3799
+ - Check touch target sizes (44x44px minimum)
3800
+ - Test layout across viewports
3801
+ - Review mobile navigation patterns
3802
+ - Reference: ux://mobile/patterns
3803
+
3804
+ ## 4. Typography & Readability
3805
+ - Use generate_typography_scale to verify type system
3806
+ - Check line length (45-75 characters)
3807
+ - Verify line height (1.5-1.7 for body text)
3808
+ - Review font pairing and hierarchy
3809
+ - Reference: ux://visual/typography
3810
+
3811
+ ## 5. Color System
3812
+ - Use generate_color_palette to analyze harmony
3813
+ - Verify semantic color usage
3814
+ - Check 60-30-10 rule adherence
3815
+ - Ensure sufficient contrast ratios
3816
+ - Reference: ux://visual/color-theory
3817
+
3818
+ ## 6. Form Patterns (if applicable)
3819
+ - Use suggest_form_pattern tool
3820
+ - Verify single-column layout
3821
+ - Check validation timing (hybrid approach)
3822
+ - Review field types and autocomplete
3823
+ - Test error messages (clear, specific, actionable)
3824
+ - Reference: ux://forms/patterns
3825
+
3826
+ ## 7. Microcopy & Content
3827
+ - Use suggest_microcopy tool for key elements
3828
+ - Review button labels (specific, action-oriented)
3829
+ - Check error messages (explain + instruct)
3830
+ - Verify empty states and success messages
3831
+ - Reference: ux://content/microcopy
3832
+
3833
+ ## 8. Data Visualization (if applicable)
3834
+ - Use analyze_data_viz tool
3835
+ - Verify appropriate chart types
3836
+ - Check accessibility (color independence, alt text)
3837
+ - Review data-ink ratio
3838
+ - Reference: ux://data/visualization
3839
+
3840
+ ## 9. Performance Indicators
3841
+ - Check for performance best practices
3842
+ - Review lazy loading and code splitting
3843
+ - Verify optimization techniques
3844
+ - Reference: ux://performance/optimization
3845
+
3846
+ ## 10. SEO & Metadata
3847
+ - Review meta tags and Open Graph
3848
+ - Check semantic structure
3849
+ - Verify heading hierarchy
3850
+ - Reference: ux://seo/best-practices
3851
+
3852
+ ## Output Format
3853
+
3854
+ For each dimension, provide:
3855
+ 1. **Status**: ✅ Pass | ⚠️ Needs Improvement | ❌ Critical Issues
3856
+ 2. **Severity Score**: 0-4 (0=none, 1=minor, 2=moderate, 3=major, 4=critical)
3857
+ 3. **Findings**: Specific issues discovered
3858
+ 4. **Recommendations**: Prioritized, actionable fixes
3859
+ 5. **References**: Relevant knowledge resources
3860
+
3861
+ ## Summary
3862
+ - Overall UX Health Score: X/100
3863
+ - Critical Issues (must fix): List
3864
+ - High Priority (should fix): List
3865
+ - Medium Priority (nice to have): List
3866
+ - Positive Highlights: What's working well
3867
+
3868
+ Provide a comprehensive, actionable audit report.`,
3869
+ },
3870
+ },
3871
+ ],
3872
+ };
1751
3873
  default:
1752
3874
  throw new Error(`Unknown prompt: ${name}`);
1753
3875
  }