@layoutdesign/context 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +424 -0
  3. package/dist/bin/cli.d.ts +3 -0
  4. package/dist/bin/cli.d.ts.map +1 -0
  5. package/dist/bin/cli.js +57 -0
  6. package/dist/bin/cli.js.map +1 -0
  7. package/dist/src/cli/import-zip.d.ts +2 -0
  8. package/dist/src/cli/import-zip.d.ts.map +1 -0
  9. package/dist/src/cli/import-zip.js +156 -0
  10. package/dist/src/cli/import-zip.js.map +1 -0
  11. package/dist/src/cli/init.d.ts +4 -0
  12. package/dist/src/cli/init.d.ts.map +1 -0
  13. package/dist/src/cli/init.js +104 -0
  14. package/dist/src/cli/init.js.map +1 -0
  15. package/dist/src/cli/install.d.ts +5 -0
  16. package/dist/src/cli/install.d.ts.map +1 -0
  17. package/dist/src/cli/install.js +192 -0
  18. package/dist/src/cli/install.js.map +1 -0
  19. package/dist/src/cli/list.d.ts +2 -0
  20. package/dist/src/cli/list.d.ts.map +1 -0
  21. package/dist/src/cli/list.js +36 -0
  22. package/dist/src/cli/list.js.map +1 -0
  23. package/dist/src/cli/serve.d.ts +2 -0
  24. package/dist/src/cli/serve.d.ts.map +1 -0
  25. package/dist/src/cli/serve.js +9 -0
  26. package/dist/src/cli/serve.js.map +1 -0
  27. package/dist/src/cli/use.d.ts +2 -0
  28. package/dist/src/cli/use.d.ts.map +1 -0
  29. package/dist/src/cli/use.js +54 -0
  30. package/dist/src/cli/use.js.map +1 -0
  31. package/dist/src/compliance/checker.d.ts +23 -0
  32. package/dist/src/compliance/checker.d.ts.map +1 -0
  33. package/dist/src/compliance/checker.js +31 -0
  34. package/dist/src/compliance/checker.js.map +1 -0
  35. package/dist/src/compliance/rules.d.ts +11 -0
  36. package/dist/src/compliance/rules.d.ts.map +1 -0
  37. package/dist/src/compliance/rules.js +147 -0
  38. package/dist/src/compliance/rules.js.map +1 -0
  39. package/dist/src/index.d.ts +9 -0
  40. package/dist/src/index.d.ts.map +1 -0
  41. package/dist/src/index.js +6 -0
  42. package/dist/src/index.js.map +1 -0
  43. package/dist/src/kit/loader.d.ts +16 -0
  44. package/dist/src/kit/loader.d.ts.map +1 -0
  45. package/dist/src/kit/loader.js +98 -0
  46. package/dist/src/kit/loader.js.map +1 -0
  47. package/dist/src/kit/parser.d.ts +21 -0
  48. package/dist/src/kit/parser.d.ts.map +1 -0
  49. package/dist/src/kit/parser.js +98 -0
  50. package/dist/src/kit/parser.js.map +1 -0
  51. package/dist/src/kit/registry.d.ts +4 -0
  52. package/dist/src/kit/registry.d.ts.map +1 -0
  53. package/dist/src/kit/registry.js +91 -0
  54. package/dist/src/kit/registry.js.map +1 -0
  55. package/dist/src/kit/types.d.ts +51 -0
  56. package/dist/src/kit/types.d.ts.map +1 -0
  57. package/dist/src/kit/types.js +11 -0
  58. package/dist/src/kit/types.js.map +1 -0
  59. package/dist/src/mcp/server.d.ts +6 -0
  60. package/dist/src/mcp/server.d.ts.map +1 -0
  61. package/dist/src/mcp/server.js +56 -0
  62. package/dist/src/mcp/server.js.map +1 -0
  63. package/dist/src/mcp/tools/check-compliance.d.ts +16 -0
  64. package/dist/src/mcp/tools/check-compliance.d.ts.map +1 -0
  65. package/dist/src/mcp/tools/check-compliance.js +44 -0
  66. package/dist/src/mcp/tools/check-compliance.js.map +1 -0
  67. package/dist/src/mcp/tools/design-in-figma.d.ts +24 -0
  68. package/dist/src/mcp/tools/design-in-figma.d.ts.map +1 -0
  69. package/dist/src/mcp/tools/design-in-figma.js +202 -0
  70. package/dist/src/mcp/tools/design-in-figma.js.map +1 -0
  71. package/dist/src/mcp/tools/get-component.d.ts +16 -0
  72. package/dist/src/mcp/tools/get-component.d.ts.map +1 -0
  73. package/dist/src/mcp/tools/get-component.js +52 -0
  74. package/dist/src/mcp/tools/get-component.js.map +1 -0
  75. package/dist/src/mcp/tools/get-design-system.d.ts +16 -0
  76. package/dist/src/mcp/tools/get-design-system.d.ts.map +1 -0
  77. package/dist/src/mcp/tools/get-design-system.js +51 -0
  78. package/dist/src/mcp/tools/get-design-system.js.map +1 -0
  79. package/dist/src/mcp/tools/get-screenshots.d.ts +23 -0
  80. package/dist/src/mcp/tools/get-screenshots.d.ts.map +1 -0
  81. package/dist/src/mcp/tools/get-screenshots.js +78 -0
  82. package/dist/src/mcp/tools/get-screenshots.js.map +1 -0
  83. package/dist/src/mcp/tools/get-tokens.d.ts +20 -0
  84. package/dist/src/mcp/tools/get-tokens.d.ts.map +1 -0
  85. package/dist/src/mcp/tools/get-tokens.js +50 -0
  86. package/dist/src/mcp/tools/get-tokens.js.map +1 -0
  87. package/dist/src/mcp/tools/list-components.d.ts +11 -0
  88. package/dist/src/mcp/tools/list-components.d.ts.map +1 -0
  89. package/dist/src/mcp/tools/list-components.js +38 -0
  90. package/dist/src/mcp/tools/list-components.js.map +1 -0
  91. package/dist/src/mcp/tools/preview.d.ts +21 -0
  92. package/dist/src/mcp/tools/preview.d.ts.map +1 -0
  93. package/dist/src/mcp/tools/preview.js +63 -0
  94. package/dist/src/mcp/tools/preview.js.map +1 -0
  95. package/dist/src/mcp/tools/push-to-figma.d.ts +24 -0
  96. package/dist/src/mcp/tools/push-to-figma.d.ts.map +1 -0
  97. package/dist/src/mcp/tools/push-to-figma.js +101 -0
  98. package/dist/src/mcp/tools/push-to-figma.js.map +1 -0
  99. package/dist/src/mcp/tools/update-tokens.d.ts +21 -0
  100. package/dist/src/mcp/tools/update-tokens.d.ts.map +1 -0
  101. package/dist/src/mcp/tools/update-tokens.js +187 -0
  102. package/dist/src/mcp/tools/update-tokens.js.map +1 -0
  103. package/dist/src/mcp/tools/url-to-figma.d.ts +29 -0
  104. package/dist/src/mcp/tools/url-to-figma.d.ts.map +1 -0
  105. package/dist/src/mcp/tools/url-to-figma.js +103 -0
  106. package/dist/src/mcp/tools/url-to-figma.js.map +1 -0
  107. package/dist/src/preview/server.d.ts +15 -0
  108. package/dist/src/preview/server.d.ts.map +1 -0
  109. package/dist/src/preview/server.js +146 -0
  110. package/dist/src/preview/server.js.map +1 -0
  111. package/dist/src/preview/static/index.html +493 -0
  112. package/dist/src/preview/transpile.d.ts +10 -0
  113. package/dist/src/preview/transpile.d.ts.map +1 -0
  114. package/dist/src/preview/transpile.js +40 -0
  115. package/dist/src/preview/transpile.js.map +1 -0
  116. package/dist/src/preview/ws.d.ts +17 -0
  117. package/dist/src/preview/ws.d.ts.map +1 -0
  118. package/dist/src/preview/ws.js +66 -0
  119. package/dist/src/preview/ws.js.map +1 -0
  120. package/kits/linear-lite/DESIGN.md +421 -0
  121. package/kits/linear-lite/kit.json +12 -0
  122. package/kits/linear-lite/tokens.css +46 -0
  123. package/kits/linear-lite/tokens.json +47 -0
  124. package/kits/notion-lite/DESIGN.md +528 -0
  125. package/kits/notion-lite/kit.json +12 -0
  126. package/kits/notion-lite/tokens.css +50 -0
  127. package/kits/notion-lite/tokens.json +51 -0
  128. package/kits/stripe-lite/DESIGN.md +539 -0
  129. package/kits/stripe-lite/kit.json +12 -0
  130. package/kits/stripe-lite/tokens.css +57 -0
  131. package/kits/stripe-lite/tokens.json +58 -0
  132. package/package.json +63 -0
@@ -0,0 +1,103 @@
1
+ import { z } from "zod";
2
+ export const name = "url-to-figma";
3
+ export const description = "Captures a public URL as editable Figma frames with auto-layout. " +
4
+ "Returns step-by-step instructions for the agent to execute using Figma MCP " +
5
+ "and Playwright MCP. Supports multi-viewport capture (desktop, tablet, mobile).";
6
+ export const inputSchema = {
7
+ url: z.string().url().describe("The public URL to capture into Figma"),
8
+ viewports: z
9
+ .array(z.enum(["desktop", "tablet", "mobile"]))
10
+ .optional()
11
+ .describe("Viewports to capture (default: ['desktop']). Each gets a separate Figma frame."),
12
+ outputMode: z
13
+ .enum(["newFile", "existingFile", "clipboard"])
14
+ .optional()
15
+ .describe("How to output the captured design (default: newFile)"),
16
+ fileKey: z
17
+ .string()
18
+ .optional()
19
+ .describe("Figma file key (required if outputMode is existingFile)"),
20
+ };
21
+ const VIEWPORT_WIDTHS = {
22
+ desktop: { width: 1280, height: 900 },
23
+ tablet: { width: 768, height: 1024 },
24
+ mobile: { width: 375, height: 812 },
25
+ };
26
+ export function handler() {
27
+ return async ({ url, viewports, outputMode, fileKey, }) => {
28
+ const resolvedViewports = viewports ?? ["desktop"];
29
+ const resolvedMode = outputMode ?? "newFile";
30
+ const captureSteps = resolvedViewports
31
+ .map((vp, i) => {
32
+ const dims = VIEWPORT_WIDTHS[vp] ?? { width: 1280, height: 900 };
33
+ const stepBase = i * 6;
34
+ return [
35
+ `### Viewport: ${vp} (${dims.width}x${dims.height})`,
36
+ "",
37
+ `**Step ${stepBase + 1}.** Call \`generate_figma_design\` with:`,
38
+ resolvedMode === "existingFile" && fileKey
39
+ ? ` - \`outputMode: "existingFile"\`, \`fileKey: "${fileKey}"\``
40
+ : ` - \`outputMode: "${resolvedMode}"\``,
41
+ ` → Save the returned \`captureId\``,
42
+ "",
43
+ `**Step ${stepBase + 2}.** Call \`browser_resize\` with:`,
44
+ ` - \`width: ${dims.width}\`, \`height: ${dims.height}\``,
45
+ "",
46
+ `**Step ${stepBase + 3}.** Call \`browser_navigate\` with:`,
47
+ ` - \`url: "${url}"\``,
48
+ "",
49
+ `**Step ${stepBase + 4}.** Call \`browser_evaluate\` with this code:`,
50
+ "```javascript",
51
+ "(async () => {",
52
+ " const script = document.createElement('script');",
53
+ " script.src = 'https://mcp.figma.com/mcp/html-to-design/capture.js';",
54
+ " document.head.appendChild(script);",
55
+ " await new Promise(r => setTimeout(r, 1500));",
56
+ " location.hash = 'figmacapture=<CAPTURE_ID>&figmaendpoint=https%3A%2F%2Fmcp.figma.com%2Fmcp%2Fcapture%2F<CAPTURE_ID>%2Fsubmit&figmadelay=3000';",
57
+ "})()",
58
+ "```",
59
+ " Replace `<CAPTURE_ID>` with the captureId from step " +
60
+ (stepBase + 1) +
61
+ ".",
62
+ "",
63
+ `**Step ${stepBase + 5}.** Wait 10 seconds.`,
64
+ "",
65
+ `**Step ${stepBase + 6}.** Poll \`generate_figma_design\` with \`captureId\` every 5 seconds until status is \`completed\`.`,
66
+ "",
67
+ ].join("\n");
68
+ })
69
+ .join("\n");
70
+ const response = [
71
+ "# URL to Figma",
72
+ "",
73
+ `Capture **${url}** as editable Figma frames.`,
74
+ "",
75
+ "## Prerequisites",
76
+ "",
77
+ "Both MCP servers must be connected:",
78
+ "- **Figma MCP**: `claude mcp add --transport http figma https://mcp.figma.com/mcp`",
79
+ "- **Playwright MCP**: Must be available for `browser_navigate`, `browser_resize`, `browser_evaluate`",
80
+ "",
81
+ "## Auto-Layout",
82
+ "",
83
+ "The Figma capture script automatically converts CSS flexbox/grid to Figma auto-layout.",
84
+ "No extra configuration needed — frames will be editable with proper auto-layout constraints.",
85
+ "",
86
+ "## Capture Instructions",
87
+ "",
88
+ `Capturing ${resolvedViewports.length} viewport(s): ${resolvedViewports.join(", ")}`,
89
+ "",
90
+ captureSteps,
91
+ "## Notes",
92
+ "",
93
+ "- Each viewport gets its own captureId — do not reuse captureIds",
94
+ "- The capture script reads the live DOM and computed styles, preserving layout fidelity",
95
+ "- For best results, wait for the page to fully load before injecting the capture script",
96
+ "- If the page has a cookie banner or modal, dismiss it before capturing",
97
+ ].join("\n");
98
+ return {
99
+ content: [{ type: "text", text: response }],
100
+ };
101
+ };
102
+ }
103
+ //# sourceMappingURL=url-to-figma.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-to-figma.js","sourceRoot":"","sources":["../../../../src/mcp/tools/url-to-figma.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export interface PreviewServer {
2
+ url: string;
3
+ broadcast: (code: string, compiledJs: string) => void;
4
+ close: () => void;
5
+ }
6
+ /**
7
+ * Start the preview HTTP + WebSocket server.
8
+ *
9
+ * Serves the static preview page at GET / and attaches a WebSocket server
10
+ * for pushing live component updates.
11
+ */
12
+ export declare function startPreviewServer(port?: number, options?: {
13
+ openBrowser?: boolean;
14
+ }): Promise<PreviewServer>;
15
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/preview/server.ts"],"names":[],"mappings":"AA8BA,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AA2DD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,GAAE,MAAqB,EAC3B,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,GACtC,OAAO,CAAC,aAAa,CAAC,CA2ExB"}
@@ -0,0 +1,146 @@
1
+ import http from "node:http";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import open from "open";
6
+ import { createWsServer } from "./ws.js";
7
+ import { PREVIEW_PORT } from "../kit/types.js";
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+ /** Resolve the index.html path — works from both src/ (dev) and dist/ (published). */
10
+ function resolveHtmlPath() {
11
+ // When running from dist/, the file is at dist/preview/static/index.html
12
+ // When running from src/, it's at src/preview/static/index.html
13
+ const candidates = [
14
+ path.join(__dirname, "static", "index.html"),
15
+ path.join(__dirname, "..", "src", "preview", "static", "index.html"),
16
+ ];
17
+ for (const candidate of candidates) {
18
+ if (fs.existsSync(candidate)) {
19
+ return candidate;
20
+ }
21
+ }
22
+ throw new Error(`Could not find preview index.html. Searched:\n${candidates.join("\n")}`);
23
+ }
24
+ const VIEWPORT_WIDTHS = {
25
+ desktop: 1280,
26
+ tablet: 768,
27
+ mobile: 375,
28
+ };
29
+ /**
30
+ * Build a standalone HTML page for Figma capture (no chrome/iframe).
31
+ * Optionally constrains to a viewport width for responsive captures.
32
+ */
33
+ function buildCaptureHtml(compiledJs, viewportWidth) {
34
+ const escapedJs = JSON.stringify(compiledJs)
35
+ .replace(/</g, "\\u003c")
36
+ .replace(/>/g, "\\u003e");
37
+ const containerStyle = viewportWidth
38
+ ? `max-width: ${viewportWidth}px; margin: 0 auto; overflow: hidden;`
39
+ : "";
40
+ return [
41
+ "<!DOCTYPE html>",
42
+ "<html><head>",
43
+ '<meta charset="UTF-8" />',
44
+ '<meta name="viewport" content="width=device-width, initial-scale=1.0" />',
45
+ '<script src="https://mcp.figma.com/mcp/html-to-design/capture.js" async></script>',
46
+ '<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>',
47
+ '<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>',
48
+ '<script src="https://cdn.tailwindcss.com"></script>',
49
+ "<style>body { margin: 0; }</style>",
50
+ "</head><body>",
51
+ containerStyle
52
+ ? '<div id="root" style="' + containerStyle + '"></div>'
53
+ : '<div id="root"></div>',
54
+ "<script>",
55
+ "try {",
56
+ " var exports = {};",
57
+ " var module = { exports: exports };",
58
+ " function require(name) {",
59
+ ' if (name === "react" || name === "React") return React;',
60
+ ' if (name === "react-dom" || name === "react-dom/client" || name === "ReactDOM") return ReactDOM;',
61
+ ' throw new Error("Cannot require: " + name);',
62
+ " }",
63
+ " var s = document.createElement('script');",
64
+ " s.textContent = " + escapedJs + ";",
65
+ " document.body.appendChild(s);",
66
+ " var Component = module.exports.default || module.exports;",
67
+ ' if (typeof Component === "function") {',
68
+ ' ReactDOM.createRoot(document.getElementById("root")).render(React.createElement(Component));',
69
+ " }",
70
+ "} catch(e) {",
71
+ ' document.getElementById("root").textContent = e.message;',
72
+ "}",
73
+ "</script>",
74
+ "</body></html>",
75
+ ].join("\n");
76
+ }
77
+ /**
78
+ * Start the preview HTTP + WebSocket server.
79
+ *
80
+ * Serves the static preview page at GET / and attaches a WebSocket server
81
+ * for pushing live component updates.
82
+ */
83
+ export function startPreviewServer(port = PREVIEW_PORT, options = {}) {
84
+ const { openBrowser = true } = options;
85
+ return new Promise((resolve, reject) => {
86
+ const htmlPath = resolveHtmlPath();
87
+ const htmlContent = fs.readFileSync(htmlPath, "utf-8");
88
+ const server = http.createServer((req, res) => {
89
+ const parsedUrl = new URL(req.url ?? "/", `http://localhost:${port}`);
90
+ const url = parsedUrl.pathname;
91
+ if (req.method === "GET" && (url === "/" || url === "")) {
92
+ res.writeHead(200, {
93
+ "Content-Type": "text/html; charset=utf-8",
94
+ "Cache-Control": "no-cache",
95
+ });
96
+ res.end(htmlContent);
97
+ return;
98
+ }
99
+ // Standalone capture page — renders component without preview chrome.
100
+ // Used by Figma MCP's generate_figma_design to capture the component.
101
+ if (req.method === "GET" && url === "/capture") {
102
+ const last = getLastPreview();
103
+ if (!last) {
104
+ res.writeHead(404, { "Content-Type": "text/plain" });
105
+ res.end("No component previewed yet. Send code via the preview tool first.");
106
+ return;
107
+ }
108
+ res.writeHead(200, {
109
+ "Content-Type": "text/html; charset=utf-8",
110
+ "Cache-Control": "no-cache",
111
+ });
112
+ const viewport = parsedUrl.searchParams.get("viewport") ?? "desktop";
113
+ const viewportWidth = VIEWPORT_WIDTHS[viewport];
114
+ res.end(buildCaptureHtml(last.compiledJs, viewportWidth));
115
+ return;
116
+ }
117
+ res.writeHead(404, { "Content-Type": "text/plain" });
118
+ res.end("Not Found");
119
+ });
120
+ const { broadcast, getLastPreview } = createWsServer(server);
121
+ server.on("error", (err) => {
122
+ if (err.code === "EADDRINUSE") {
123
+ reject(new Error(`Port ${port} is already in use. Stop the other process or use a different port.`));
124
+ }
125
+ else {
126
+ reject(err);
127
+ }
128
+ });
129
+ server.listen(port, () => {
130
+ const url = `http://localhost:${port}`;
131
+ if (openBrowser) {
132
+ open(url).catch(() => {
133
+ // Silently ignore if browser cannot be opened (e.g. SSH session)
134
+ });
135
+ }
136
+ resolve({
137
+ url,
138
+ broadcast,
139
+ close: () => {
140
+ server.close();
141
+ },
142
+ });
143
+ });
144
+ });
145
+ }
146
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/preview/server.ts"],"names":[],"mappings":"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"}