pixl-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +91 -0
  2. package/dist/design.js +128 -0
  3. package/dist/design.js.map +1 -0
  4. package/dist/flow.js +52 -0
  5. package/dist/flow.js.map +1 -0
  6. package/dist/index.js +34 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/linter/contrast.js +46 -0
  9. package/dist/linter/contrast.js.map +1 -0
  10. package/dist/linter/index.js +190 -0
  11. package/dist/linter/index.js.map +1 -0
  12. package/dist/linter/linter.test.js +99 -0
  13. package/dist/linter/linter.test.js.map +1 -0
  14. package/dist/mcp/tools.js +129 -0
  15. package/dist/mcp/tools.js.map +1 -0
  16. package/dist/presets/catalog.js +162 -0
  17. package/dist/presets/catalog.js.map +1 -0
  18. package/dist/presets/contract.js +140 -0
  19. package/dist/presets/contract.js.map +1 -0
  20. package/dist/presets/types.js +2 -0
  21. package/dist/presets/types.js.map +1 -0
  22. package/dist/preview-server/index.js +143 -0
  23. package/dist/preview-server/index.js.map +1 -0
  24. package/dist/screens.js +52 -0
  25. package/dist/screens.js.map +1 -0
  26. package/dist/session.js +50 -0
  27. package/dist/session.js.map +1 -0
  28. package/dist/workspace/index.js +149 -0
  29. package/dist/workspace/index.js.map +1 -0
  30. package/dist/workspace/schemas.js +48 -0
  31. package/dist/workspace/schemas.js.map +1 -0
  32. package/package.json +47 -0
  33. package/preview-app/index.html +12 -0
  34. package/preview-app/src/App.tsx +53 -0
  35. package/preview-app/src/FlowCanvas.tsx +208 -0
  36. package/preview-app/src/Gallery.tsx +35 -0
  37. package/preview-app/src/api.ts +51 -0
  38. package/preview-app/src/main.tsx +10 -0
  39. package/preview-app/src/styles.css +173 -0
  40. package/preview-app/src/useLiveReload.ts +17 -0
  41. package/preview-app/src/vite-env.d.ts +1 -0
  42. package/preview-app/tsconfig.json +15 -0
@@ -0,0 +1,99 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { lintScreen } from "./index.js";
3
+ import { contrastRatio } from "./contrast.js";
4
+ import { getPreset } from "../presets/catalog.js";
5
+ import { buildTailwindHead } from "../presets/contract.js";
6
+ const tokens = getPreset("clean-saas").tokens;
7
+ const head = buildTailwindHead(tokens);
8
+ /** Wrap body markup in a fully-compliant document shell (head + viewport lock). */
9
+ function screen(bodyInner, tk = tokens) {
10
+ const { width, height } = tk.breakpoints;
11
+ return `<!doctype html><html><head>${head}</head>
12
+ <body class="bg-bg text-text font-sans" style="width:${width}px;height:${height}px;">
13
+ ${bodyInner}
14
+ </body></html>`;
15
+ }
16
+ const rulesOf = (html, tk = tokens) => new Set(lintScreen(html, tk).violations.map((v) => v.rule));
17
+ describe("lintScreen — clean screen passes", () => {
18
+ it("accepts a compliant reference screen", () => {
19
+ const html = getPreset("clean-saas").referenceScreenHtml;
20
+ const res = lintScreen(html, tokens);
21
+ expect(res.ok).toBe(true);
22
+ expect(res.errorCount).toBe(0);
23
+ });
24
+ it("accepts on-scale utilities and role colors", () => {
25
+ const html = screen(`
26
+ <div class="p-6 gap-4 rounded-lg bg-surface border border-border">
27
+ <h1 class="text-2xl text-text">Hi</h1>
28
+ <button class="h-12 bg-primary text-primaryText rounded-md">Go</button>
29
+ </div>`);
30
+ expect(lintScreen(html, tokens).ok).toBe(true);
31
+ });
32
+ });
33
+ describe("lintScreen — off-standard screens are rejected", () => {
34
+ it("flags raw hex in markup", () => {
35
+ const html = screen(`<div style="color:#ff00aa">x</div>`);
36
+ expect(rulesOf(html)).toContain("raw-color");
37
+ expect(lintScreen(html, tokens).ok).toBe(false);
38
+ });
39
+ it("flags arbitrary bracket hex color", () => {
40
+ const html = screen(`<div class="bg-[#123456] p-4">x</div>`);
41
+ expect(rulesOf(html)).toContain("raw-color");
42
+ });
43
+ it("flags off-grid arbitrary spacing (37px)", () => {
44
+ const html = screen(`<div class="p-[37px]">x</div>`);
45
+ expect(rulesOf(html)).toContain("off-scale-spacing");
46
+ });
47
+ it("allows on-grid arbitrary spacing (a multiple of 4)", () => {
48
+ const html = screen(`<div class="p-[24px]">x</div>`);
49
+ expect(rulesOf(html)).not.toContain("off-scale-spacing");
50
+ });
51
+ it("flags off-scale arbitrary font size", () => {
52
+ const html = screen(`<p class="text-[15px]">x</p>`);
53
+ expect(rulesOf(html)).toContain("off-scale-type");
54
+ });
55
+ it("allows an on-scale arbitrary font size", () => {
56
+ const html = screen(`<p class="text-[16px]">x</p>`); // 16 is in the type scale
57
+ expect(rulesOf(html)).not.toContain("off-scale-type");
58
+ });
59
+ it("flags a sub-44px tap target (h-8 = 32px)", () => {
60
+ const html = screen(`<button class="h-8 bg-primary text-primaryText">Go</button>`);
61
+ expect(rulesOf(html)).toContain("tap-target");
62
+ });
63
+ it("flags a sub-44px inline-height tap target", () => {
64
+ const html = screen(`<button style="height:30px" class="bg-primary text-primaryText">Go</button>`);
65
+ expect(rulesOf(html)).toContain("tap-target");
66
+ });
67
+ it("accepts a 44px tap target (h-11)", () => {
68
+ const html = screen(`<button class="h-11 bg-primary text-primaryText">Go</button>`);
69
+ expect(rulesOf(html)).not.toContain("tap-target");
70
+ });
71
+ it("flags low-contrast role pairing", () => {
72
+ // border (#e5e7eb light) text on bg (#fff) — far below AA
73
+ const html = screen(`<p class="text-border bg-bg">low contrast</p>`);
74
+ expect(rulesOf(html)).toContain("contrast");
75
+ });
76
+ it("flags a missing Tailwind head", () => {
77
+ const html = `<!doctype html><html><head></head>
78
+ <body style="width:390px;height:844px;"><div>x</div></body></html>`;
79
+ expect(rulesOf(html)).toContain("missing-head");
80
+ });
81
+ it("flags a missing viewport lock", () => {
82
+ const html = `<!doctype html><html><head>${head}</head><body class="bg-bg"><div>x</div></body></html>`;
83
+ expect(rulesOf(html)).toContain("viewport-unlocked");
84
+ });
85
+ it("does not flag token hexes living in the Tailwind config head", () => {
86
+ // The config script contains many hexes; those must not count as raw-color.
87
+ const html = screen(`<div class="bg-surface p-4">clean</div>`);
88
+ expect(rulesOf(html)).not.toContain("raw-color");
89
+ });
90
+ });
91
+ describe("contrastRatio", () => {
92
+ it("black on white is 21:1", () => {
93
+ expect(contrastRatio("#000000", "#ffffff")).toBeCloseTo(21, 0);
94
+ });
95
+ it("returns 0 for unparseable input", () => {
96
+ expect(contrastRatio("nope", "#fff")).toBe(0);
97
+ });
98
+ });
99
+ //# sourceMappingURL=linter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linter.test.js","sourceRoot":"","sources":["../../src/linter/linter.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAG3D,MAAM,MAAM,GAAG,SAAS,CAAC,YAAY,CAAE,CAAC,MAAM,CAAC;AAC/C,MAAM,IAAI,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAEvC,mFAAmF;AACnF,SAAS,MAAM,CAAC,SAAiB,EAAE,KAAa,MAAM;IACpD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC;IACzC,OAAO,8BAA8B,IAAI;uDACY,KAAK,aAAa,MAAM;EAC7E,SAAS;eACI,CAAC;AAChB,CAAC;AAED,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,KAAa,MAAM,EAAE,EAAE,CACpD,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAE9D,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;IAChD,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,IAAI,GAAG,SAAS,CAAC,YAAY,CAAE,CAAC,mBAAmB,CAAC;QAC1D,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACrC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,IAAI,GAAG,MAAM,CAAC;;;;aAIX,CAAC,CAAC;QACX,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,gDAAgD,EAAE,GAAG,EAAE;IAC9D,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,MAAM,IAAI,GAAG,MAAM,CAAC,oCAAoC,CAAC,CAAC;QAC1D,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAC7C,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,uCAAuC,CAAC,CAAC;QAC7D,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,IAAI,GAAG,MAAM,CAAC,+BAA+B,CAAC,CAAC;QACrD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,IAAI,GAAG,MAAM,CAAC,+BAA+B,CAAC,CAAC;QACrD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,8BAA8B,CAAC,CAAC;QACpD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,IAAI,GAAG,MAAM,CAAC,8BAA8B,CAAC,CAAC,CAAC,0BAA0B;QAC/E,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,IAAI,GAAG,MAAM,CAAC,6DAA6D,CAAC,CAAC;QACnF,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,IAAI,GAAG,MAAM,CAAC,6EAA6E,CAAC,CAAC;QACnG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,8DAA8D,CAAC,CAAC;QACpF,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,0DAA0D;QAC1D,MAAM,IAAI,GAAG,MAAM,CAAC,+CAA+C,CAAC,CAAC;QACrE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,IAAI,GAAG;mEACkD,CAAC;QAChE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,IAAI,GAAG,8BAA8B,IAAI,uDAAuD,CAAC;QACvG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,4EAA4E;QAC5E,MAAM,IAAI,GAAG,MAAM,CAAC,yCAAyC,CAAC,CAAC;QAC/D,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,129 @@
1
+ import { z } from "zod";
2
+ import { presetSummaries } from "../presets/catalog.js";
3
+ import { applyDesignSystem, planScreens } from "../design.js";
4
+ import { writeScreen, lintScreenHtml } from "../screens.js";
5
+ import { setFlow } from "../flow.js";
6
+ import { TokensSchema } from "../workspace/schemas.js";
7
+ /** MCP tool results expect a content array; this wraps JSON/text uniformly. */
8
+ function ok(data) {
9
+ const text = typeof data === "string" ? data : JSON.stringify(data, null, 2);
10
+ return { content: [{ type: "text", text }] };
11
+ }
12
+ /**
13
+ * Registers every Pixl tool. Phase 1 implements pixl_init and pixl_status
14
+ * end-to-end; the rest are declared as stubs so the surface is discoverable
15
+ * and each later build phase fills one in.
16
+ */
17
+ export function registerTools(server, session) {
18
+ server.registerTool("pixl_init", {
19
+ title: "Initialize Pixl",
20
+ description: "Pixl auto-initializes on startup — you do NOT need to call this first. Use it only to re-open the browser preview or fetch the preview URL. Idempotent.",
21
+ inputSchema: {
22
+ openBrowser: z
23
+ .boolean()
24
+ .default(true)
25
+ .describe("Open the preview in the default browser automatically."),
26
+ },
27
+ }, async ({ openBrowser }) => {
28
+ const url = await session.ensureStarted(openBrowser);
29
+ return ok({
30
+ ok: true,
31
+ previewUrl: url,
32
+ workspace: session.workspace.dir,
33
+ next: "Call pixl_list_presets, then pixl_set_design_system to lock the design system.",
34
+ });
35
+ });
36
+ server.registerTool("pixl_status", {
37
+ title: "Pixl status",
38
+ description: "Report current workspace state: whether initialized, the active design system, screen count, flow node count, and preview URL.",
39
+ inputSchema: {},
40
+ }, async () => ok(await session.workspace.status(session.previewUrl)));
41
+ // --- phase 2: design system ---------------------------------------------
42
+ server.registerTool("pixl_list_presets", {
43
+ title: "List design presets",
44
+ description: "List the curated design-system presets. Show these to the user and let them pick one (by id) before calling pixl_set_design_system.",
45
+ inputSchema: {},
46
+ }, async () => ok({ presets: presetSummaries() }));
47
+ server.registerTool("pixl_set_design_system", {
48
+ title: "Set design system",
49
+ description: "Lock the design system. Pass a presetId (from pixl_list_presets) with optional overrides, OR fully custom tokens. Writes tokens.json + design/*.md and returns the TOKEN CONTRACT — obey it for every screen you generate.",
50
+ inputSchema: {
51
+ presetId: z
52
+ .string()
53
+ .optional()
54
+ .describe("Preset id, e.g. 'clean-saas'. Omit only if passing customTokens."),
55
+ overrides: z
56
+ .object({
57
+ name: z.string().optional(),
58
+ colors: z.record(z.string()).optional().describe("Override color roles, e.g. { primary: '#111' }"),
59
+ fontFamilies: z.array(z.string()).optional(),
60
+ })
61
+ .optional(),
62
+ customTokens: TokensSchema.optional().describe("Full custom token set (same shape as a preset's tokens). Use for a bespoke system."),
63
+ },
64
+ }, async (args) => ok(await applyDesignSystem(session.workspace, args)));
65
+ server.registerTool("pixl_plan_screens", {
66
+ title: "Plan screens & journey",
67
+ description: "Record the screen list and the user journey between them. Writes screens.md and seeds the flow map. Do this after the design system is set and before generating screens.",
68
+ inputSchema: {
69
+ screens: z
70
+ .array(z.object({
71
+ id: z.string().regex(/^[a-z0-9-]+$/, "kebab-case"),
72
+ name: z.string(),
73
+ description: z.string().optional(),
74
+ }))
75
+ .describe("Ordered list of screens."),
76
+ journey: z
77
+ .array(z.object({
78
+ from: z.string(),
79
+ to: z.string(),
80
+ label: z.string().optional().describe("What triggers the transition, e.g. 'Tap Sign in'"),
81
+ }))
82
+ .optional()
83
+ .describe("Directed transitions between screen ids."),
84
+ },
85
+ }, async (args) => ok(await planScreens(session.workspace, args)));
86
+ // --- phase 3: screen generation + linter ---------------------------------
87
+ const screenInput = {
88
+ id: z.string().regex(/^[a-z0-9-]+$/, "kebab-case").describe("Screen id; matches a screen from pixl_plan_screens."),
89
+ name: z.string().describe("Human-readable screen name."),
90
+ description: z.string().optional(),
91
+ html: z
92
+ .string()
93
+ .describe("Full self-contained HTML document for the screen, sized to the viewport and using the contract's headBlock + role classes."),
94
+ };
95
+ server.registerTool("pixl_write_screen", {
96
+ title: "Write a screen",
97
+ description: "Submit a screen's HTML. It is linted against the token contract; on pass it is saved to screens/<id>.html and live-renders in the gallery, on fail the violations are returned and NOTHING is saved — fix them and resubmit.",
98
+ inputSchema: screenInput,
99
+ }, async (args) => ok(await writeScreen(session.workspace, args)));
100
+ server.registerTool("pixl_lint_screen", {
101
+ title: "Lint a screen",
102
+ description: "Lint provided HTML against the active token contract WITHOUT saving. Use to check a draft before committing it with pixl_write_screen.",
103
+ inputSchema: { html: z.string().describe("Full screen HTML to lint.") },
104
+ }, async ({ html }) => ok(await lintScreenHtml(session.workspace, html)));
105
+ // --- phase 4: flow canvas ------------------------------------------------
106
+ server.registerTool("pixl_set_flow", {
107
+ title: "Set flow",
108
+ description: "Set/update the user-journey graph the flow canvas renders. Provide the edges (transitions between screen ids). Nodes default to one per planned screen and keep any positions the user has dragged. Writes flow.json and live-updates the Flow tab.",
109
+ inputSchema: {
110
+ edges: z
111
+ .array(z.object({
112
+ from: z.string().describe("source screen id"),
113
+ to: z.string().describe("target screen id"),
114
+ label: z.string().optional().describe("what triggers the transition, e.g. 'Tap Sign in'"),
115
+ }))
116
+ .describe("Directed transitions between screens."),
117
+ nodes: z
118
+ .array(z.object({
119
+ id: z.string(),
120
+ label: z.string().optional(),
121
+ x: z.number().optional(),
122
+ y: z.number().optional(),
123
+ }))
124
+ .optional()
125
+ .describe("Optional explicit node set/positions; omit to use one node per screen."),
126
+ },
127
+ }, async (args) => ok(await setFlow(session.workspace, args)));
128
+ }
129
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,162 @@
1
+ import { buildReferenceScreen } from "./contract.js";
2
+ // Shared scales — Tailwind-aligned so default utilities stay on-grid.
3
+ const SPACING = [0, 2, 4, 6, 8, 10, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96];
4
+ const TYPE_SCALE = [12, 13, 14, 16, 18, 20, 24, 28, 32, 36, 44];
5
+ const VIEWPORT = { width: 390, height: 844 };
6
+ function toPreset(spec) {
7
+ const tokens = {
8
+ name: spec.name,
9
+ preset: spec.id,
10
+ typeScale: TYPE_SCALE,
11
+ fontFamilies: spec.fontFamilies,
12
+ spacing: SPACING,
13
+ radius: spec.radius,
14
+ colors: spec.colors,
15
+ shadows: spec.shadows,
16
+ breakpoints: VIEWPORT,
17
+ };
18
+ return {
19
+ id: spec.id,
20
+ name: spec.name,
21
+ vibe: spec.vibe,
22
+ tokens,
23
+ rules: spec.rules,
24
+ referenceScreenHtml: buildReferenceScreen(tokens),
25
+ };
26
+ }
27
+ const SPECS = [
28
+ {
29
+ id: "ios-native",
30
+ name: "iOS Native",
31
+ vibe: "Apple HIG — system font, crisp, familiar, restrained color.",
32
+ fontFamilies: ['-apple-system', 'BlinkMacSystemFont', '"SF Pro Text"', '"Segoe UI"', "sans-serif"],
33
+ colors: {
34
+ bg: "#ffffff",
35
+ surface: "#f2f2f7",
36
+ text: "#000000",
37
+ textMuted: "#8e8e93",
38
+ border: "#c6c6c8",
39
+ primary: "#007aff",
40
+ primaryText: "#ffffff",
41
+ accent: "#34c759",
42
+ danger: "#ff3b30",
43
+ success: "#34c759",
44
+ },
45
+ radius: [8, 10, 14, 20],
46
+ shadows: [
47
+ "0 1px 2px rgba(0,0,0,0.06)",
48
+ "0 4px 12px rgba(0,0,0,0.10)",
49
+ "0 12px 32px rgba(0,0,0,0.16)",
50
+ ],
51
+ rules: [
52
+ "Follow Apple HIG: generous whitespace, clear hierarchy, one primary action per screen.",
53
+ "Use the system blue for primary actions only; avoid decorative color.",
54
+ "Large bold titles, secondary text in muted gray.",
55
+ "Rounded corners on cards and buttons; never sharp 0px corners.",
56
+ ],
57
+ },
58
+ {
59
+ id: "clean-saas",
60
+ name: "Clean SaaS",
61
+ vibe: "Linear/Stripe — Inter, tight neutral grays, indigo accent, subtle depth.",
62
+ fontFamilies: ["Inter", "ui-sans-serif", "system-ui", "sans-serif"],
63
+ colors: {
64
+ bg: "#ffffff",
65
+ surface: "#f9fafb",
66
+ text: "#111827",
67
+ textMuted: "#6b7280",
68
+ border: "#e5e7eb",
69
+ primary: "#4f46e5",
70
+ primaryText: "#ffffff",
71
+ accent: "#0ea5e9",
72
+ danger: "#ef4444",
73
+ success: "#10b981",
74
+ },
75
+ radius: [6, 8, 12, 16],
76
+ shadows: [
77
+ "0 1px 2px rgba(16,24,40,0.05)",
78
+ "0 4px 12px rgba(16,24,40,0.08)",
79
+ "0 12px 32px rgba(16,24,40,0.12)",
80
+ ],
81
+ rules: [
82
+ "Neutral gray scale for structure; indigo reserved for primary actions and links.",
83
+ "Tight, consistent spacing; align everything to a grid.",
84
+ "Subtle shadows and 1px borders for separation, not heavy boxes.",
85
+ "Sentence case labels, concise microcopy.",
86
+ ],
87
+ },
88
+ {
89
+ id: "playful-consumer",
90
+ name: "Playful Consumer",
91
+ vibe: "Rounded, warm, vibrant — friendly consumer app energy.",
92
+ fontFamilies: ["Poppins", "ui-rounded", "system-ui", "sans-serif"],
93
+ colors: {
94
+ bg: "#fffdf9",
95
+ surface: "#ffffff",
96
+ text: "#1f2937",
97
+ textMuted: "#9ca3af",
98
+ border: "#f3e8e2",
99
+ primary: "#ff6b6b",
100
+ primaryText: "#ffffff",
101
+ accent: "#8b5cf6",
102
+ danger: "#ef4444",
103
+ success: "#22c55e",
104
+ },
105
+ radius: [12, 16, 24, 32],
106
+ shadows: [
107
+ "0 2px 8px rgba(255,107,107,0.12)",
108
+ "0 8px 20px rgba(139,92,246,0.14)",
109
+ "0 16px 40px rgba(0,0,0,0.12)",
110
+ ],
111
+ rules: [
112
+ "Big rounded corners, generous padding, soft colorful shadows.",
113
+ "Warm off-white background; white surfaces float above it.",
114
+ "Coral primary, purple accent — use color to delight, keep text readable.",
115
+ "Friendly, human copy; bold rounded headings.",
116
+ ],
117
+ },
118
+ {
119
+ id: "minimal-mono",
120
+ name: "Minimal Mono",
121
+ vibe: "High-contrast monochrome, sharp small radius, editorial restraint.",
122
+ fontFamilies: ['"Space Grotesk"', "ui-sans-serif", "system-ui", "sans-serif"],
123
+ colors: {
124
+ bg: "#ffffff",
125
+ surface: "#fafafa",
126
+ text: "#0a0a0a",
127
+ textMuted: "#737373",
128
+ border: "#e5e5e5",
129
+ primary: "#0a0a0a",
130
+ primaryText: "#ffffff",
131
+ accent: "#0a0a0a",
132
+ danger: "#dc2626",
133
+ success: "#16a34a",
134
+ },
135
+ radius: [2, 4, 6, 8],
136
+ shadows: [
137
+ "0 1px 0 rgba(0,0,0,0.05)",
138
+ "0 1px 3px rgba(0,0,0,0.08)",
139
+ "0 4px 12px rgba(0,0,0,0.10)",
140
+ ],
141
+ rules: [
142
+ "Monochrome only; black is the primary, gray for hierarchy.",
143
+ "Small sharp radius, thin borders, lots of negative space.",
144
+ "Typography does the work — strong weight contrast, tight tracking on headings.",
145
+ "No decorative color; danger/success reserved for status only.",
146
+ ],
147
+ },
148
+ ];
149
+ export const PRESETS = SPECS.map(toPreset);
150
+ export function getPreset(id) {
151
+ return PRESETS.find((p) => p.id === id);
152
+ }
153
+ export function presetSummaries() {
154
+ return PRESETS.map((p) => ({
155
+ id: p.id,
156
+ name: p.name,
157
+ vibe: p.vibe,
158
+ primary: p.tokens.colors.primary,
159
+ font: p.tokens.fontFamilies[0],
160
+ }));
161
+ }
162
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/presets/catalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Every generated screen embeds this <head> block: Tailwind via CDN plus a
3
+ * config that binds utility classes (bg-primary, rounded-lg, shadow-md, …) to
4
+ * the locked tokens. This is how the model consumes the design system — it
5
+ * writes layout with normal Tailwind classes and the theme supplies the taste.
6
+ */
7
+ export function buildTailwindConfig(tokens) {
8
+ const radius = tokens.radius;
9
+ const named = (arr, keys) => {
10
+ const out = {};
11
+ keys.forEach((k, i) => {
12
+ if (arr[i] !== undefined)
13
+ out[k] = `${arr[i]}px`;
14
+ });
15
+ return out;
16
+ };
17
+ const borderRadius = { ...named(radius, ["sm", "md", "lg", "xl"]), full: "9999px" };
18
+ const shadowKeys = ["sm", "md", "lg"];
19
+ const boxShadow = {};
20
+ tokens.shadows.slice(0, 3).forEach((s, i) => (boxShadow[shadowKeys[i]] = s));
21
+ const config = {
22
+ theme: {
23
+ extend: {
24
+ colors: tokens.colors,
25
+ fontFamily: { sans: tokens.fontFamilies },
26
+ borderRadius,
27
+ boxShadow,
28
+ },
29
+ },
30
+ };
31
+ return `tailwind.config = ${JSON.stringify(config, null, 2)}`;
32
+ }
33
+ /** Full <script> block a screen must include in <head>. */
34
+ export function buildTailwindHead(tokens) {
35
+ return [
36
+ `<script src="https://cdn.tailwindcss.com"></script>`,
37
+ `<script>${buildTailwindConfig(tokens)}</script>`,
38
+ ].join("\n");
39
+ }
40
+ /**
41
+ * The structured payload pixl_set_design_system returns into the model context.
42
+ * It is the single steering artifact for screen generation.
43
+ */
44
+ export function buildTokenContract(tokens, rules) {
45
+ return {
46
+ designSystem: tokens.name,
47
+ viewport: tokens.breakpoints,
48
+ headBlock: buildTailwindHead(tokens),
49
+ palette: tokens.colors,
50
+ fontFamilies: tokens.fontFamilies,
51
+ typeScalePx: tokens.typeScale,
52
+ spacingScalePx: tokens.spacing,
53
+ radiusPx: tokens.radius,
54
+ shadows: tokens.shadows,
55
+ rules,
56
+ usage: [
57
+ "Every screen is a full self-contained HTML document sized to the viewport above.",
58
+ "Paste headBlock verbatim into <head>; it wires Tailwind classes to these tokens.",
59
+ "Use ONLY palette color roles (bg-<role>, text-<role>, border-<role>) — never raw hex.",
60
+ "Use Tailwind spacing/size utilities (they sit on the 4px grid) — no arbitrary px.",
61
+ "Font sizes must come from the type scale; body uses font-sans (already the preset font).",
62
+ "Interactive targets ≥ 44px tall. Lint runs on submit and will reject violations.",
63
+ ],
64
+ };
65
+ }
66
+ /** Generates the five design/*.md docs deterministically from the tokens. */
67
+ export function buildDesignDocs(tokens, rules) {
68
+ const list = (arr) => arr.map((v) => `\`${v}\``).join(", ");
69
+ const colorRows = Object.entries(tokens.colors)
70
+ .map(([role, hex]) => `| \`${role}\` | ${hex} | \`bg-${role}\` \`text-${role}\` \`border-${role}\` |`)
71
+ .join("\n");
72
+ return {
73
+ typography: `# Typography — ${tokens.name}
74
+
75
+ **Font stack:** ${tokens.fontFamilies.map((f) => `\`${f}\``).join(" → ")}
76
+
77
+ **Type scale (px):** ${list(tokens.typeScale)}
78
+
79
+ Use only these sizes. Body text is \`font-sans\`; headings step up the scale. Keep line-height comfortable (1.4–1.6 for body).`,
80
+ color: `# Color — ${tokens.name}
81
+
82
+ Use color **roles**, never raw hex. Each role maps to a Tailwind class.
83
+
84
+ | Role | Hex | Classes |
85
+ |---|---|---|
86
+ ${colorRows}`,
87
+ spacing: `# Spacing & radius — ${tokens.name}
88
+
89
+ **Spacing scale (px):** ${list(tokens.spacing)} — matches Tailwind's 4px grid, so \`p-4\`, \`gap-6\`, etc. are on-scale.
90
+
91
+ **Radius (px):** ${list(tokens.radius)} → \`rounded-sm|md|lg|xl\`, plus \`rounded-full\`.
92
+
93
+ Never use arbitrary spacing (\`p-[13px]\`). Stay on the scale.`,
94
+ components: `# Components — ${tokens.name}
95
+
96
+ - **Buttons:** primary = \`bg-primary text-primaryText\`, min height 44px, \`rounded-md\`.
97
+ - **Cards/surfaces:** \`bg-surface\` with \`shadow-sm|md\` and \`rounded-lg\`.
98
+ - **Text hierarchy:** primary \`text-text\`, secondary \`text-textMuted\`.
99
+ - **Borders/dividers:** \`border-border\`.
100
+ - **Shadows:** ${list(tokens.shadows)}.`,
101
+ principles: `# Principles — ${tokens.name}
102
+
103
+ _${tokens.name}_ — vibe and rules that keep screens on-standard:
104
+
105
+ ${rules.map((r) => `- ${r}`).join("\n")}
106
+
107
+ Viewport is locked to ${tokens.breakpoints.width}×${tokens.breakpoints.height}. Design for one phone screen at a time.`,
108
+ };
109
+ }
110
+ /** A worked example screen the model can pattern-match against. */
111
+ export function buildReferenceScreen(tokens, title = "Welcome") {
112
+ return `<!doctype html>
113
+ <html lang="en">
114
+ <head>
115
+ <meta charset="UTF-8" />
116
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
117
+ <title>${title}</title>
118
+ ${buildTailwindHead(tokens)}
119
+ </head>
120
+ <body class="bg-bg text-text font-sans" style="width:${tokens.breakpoints.width}px;height:${tokens.breakpoints.height}px;">
121
+ <div class="flex flex-col h-full px-6 pt-16 pb-8">
122
+ <div class="flex-1">
123
+ <div class="w-12 h-12 rounded-lg bg-primary mb-8"></div>
124
+ <h1 class="text-3xl font-bold tracking-tight mb-2">${title}</h1>
125
+ <p class="text-base text-textMuted mb-10">Sign in to continue to your account.</p>
126
+
127
+ <label class="block text-sm text-textMuted mb-2">Email</label>
128
+ <input class="w-full h-12 px-4 mb-4 rounded-md bg-surface border border-border" placeholder="you@example.com" />
129
+
130
+ <label class="block text-sm text-textMuted mb-2">Password</label>
131
+ <input type="password" class="w-full h-12 px-4 rounded-md bg-surface border border-border" placeholder="••••••••" />
132
+ </div>
133
+
134
+ <button class="w-full h-12 rounded-md bg-primary text-primaryText font-semibold shadow-md">Sign in</button>
135
+ <p class="text-center text-sm text-textMuted mt-4">Don't have an account? <span class="text-primary font-medium">Sign up</span></p>
136
+ </div>
137
+ </body>
138
+ </html>`;
139
+ }
140
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/presets/contract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/presets/types.ts"],"names":[],"mappings":""}