canicode 0.8.5 → 0.8.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.
package/README.md CHANGED
@@ -108,7 +108,7 @@ Or with a Figma API token (no Figma MCP needed):
108
108
  claude mcp add canicode -e FIGMA_TOKEN=figd_xxxxxxxxxxxxx -- npx -y -p canicode canicode-mcp
109
109
  ```
110
110
 
111
- For Cursor / Claude Desktop config, see [`docs/CUSTOMIZATION.md`](docs/CUSTOMIZATION.md).
111
+ For Cursor / Claude Desktop config, see [`docs/REFERENCE.md`](docs/REFERENCE.md).
112
112
 
113
113
  **Figma MCP Rate Limits**
114
114
 
@@ -160,7 +160,7 @@ Posts analysis as a PR comment. Fails if score is below threshold. See [**canico
160
160
 
161
161
  > Ask any LLM *"Write a canicode custom rule that checks X"* — it can generate the JSON for you.
162
162
 
163
- See [`docs/CUSTOMIZATION.md`](docs/CUSTOMIZATION.md) for the full guide, examples, and all available options.
163
+ See [`docs/REFERENCE.md`](docs/REFERENCE.md) for the full guide, examples, and all available options.
164
164
 
165
165
  ---
166
166
 
package/dist/cli/index.js CHANGED
@@ -72,12 +72,26 @@ function resizePng(png, targetWidth, targetHeight) {
72
72
  function compareScreenshots(path1, path2, diffOutputPath) {
73
73
  const raw1 = PNG.sync.read(readFileSync(path1));
74
74
  const raw2 = PNG.sync.read(readFileSync(path2));
75
- const width = Math.max(raw1.width, raw2.width);
76
- const height = Math.max(raw1.height, raw2.height);
77
- const img1 = raw1.width !== width || raw1.height !== height ? resizePng(raw1, width, height) : raw1;
78
- const img2 = raw2.width !== width || raw2.height !== height ? resizePng(raw2, width, height) : raw2;
75
+ if (raw1.width !== raw2.width || raw1.height !== raw2.height) {
76
+ const width2 = Math.max(raw1.width, raw2.width);
77
+ const height2 = Math.max(raw1.height, raw2.height);
78
+ const img1 = resizePng(raw1, width2, height2);
79
+ const img2 = resizePng(raw2, width2, height2);
80
+ const diff2 = new PNG({ width: width2, height: height2 });
81
+ pixelmatch(img1.data, img2.data, diff2.data, width2, height2, { threshold: 0.1 });
82
+ mkdirSync(dirname(diffOutputPath), { recursive: true });
83
+ writeFileSync(diffOutputPath, PNG.sync.write(diff2));
84
+ return {
85
+ similarity: 0,
86
+ diffPixels: width2 * height2,
87
+ totalPixels: width2 * height2,
88
+ width: width2,
89
+ height: height2
90
+ };
91
+ }
92
+ const { width, height } = raw1;
79
93
  const diff = new PNG({ width, height });
80
- const diffPixels = pixelmatch(img1.data, img2.data, diff.data, width, height, {
94
+ const diffPixels = pixelmatch(raw1.data, raw2.data, diff.data, width, height, {
81
95
  threshold: 0.1
82
96
  });
83
97
  mkdirSync(dirname(diffOutputPath), { recursive: true });
@@ -1105,7 +1119,7 @@ async function loadFromApi(fileKey, nodeId, token) {
1105
1119
  }
1106
1120
 
1107
1121
  // package.json
1108
- var version = "0.8.5";
1122
+ var version = "0.8.7";
1109
1123
  var AnalysisNodeTypeSchema = z.enum([
1110
1124
  "DOCUMENT",
1111
1125
  "CANVAS",
@@ -4267,7 +4281,7 @@ EXAMPLE
4267
4281
  USAGE
4268
4282
  canicode analyze <url> --custom-rules ./my-rules.json
4269
4283
 
4270
- Full guide: docs/CUSTOMIZATION.md
4284
+ Full guide: docs/REFERENCE.md
4271
4285
  Examples: examples/custom-rules.json
4272
4286
 
4273
4287
  TIP: Ask any LLM "Write a canicode custom rule that checks X" with the
@@ -4302,16 +4316,61 @@ EXAMPLE
4302
4316
  USAGE
4303
4317
  canicode analyze <url> --config ./my-config.json
4304
4318
 
4305
- Full guide: docs/CUSTOMIZATION.md
4319
+ Full guide: docs/REFERENCE.md
4306
4320
  Examples: examples/config.json
4307
4321
  `.trimStart());
4308
4322
  }
4323
+ function printDocsVisualCompare() {
4324
+ console.log(`
4325
+ VISUAL COMPARE \u2014 Pixel-level comparison between Figma and AI-generated code
4326
+
4327
+ USAGE
4328
+ canicode visual-compare ./index.html --figma-url 'https://www.figma.com/design/ABC/File?node-id=1-234'
4329
+
4330
+ OPTIONS
4331
+ --figma-url <url> Figma URL with node-id (required)
4332
+ --token <token> Figma API token (or FIGMA_TOKEN env var)
4333
+ --output <dir> Output directory (default: /tmp/canicode-visual-compare)
4334
+ --width <px> Viewport width override (default: match Figma screenshot)
4335
+ --height <px> Viewport height override (default: match Figma screenshot)
4336
+
4337
+ OUTPUT FILES
4338
+ /tmp/canicode-visual-compare/
4339
+ figma.png Figma screenshot (scale=2)
4340
+ code.png Playwright render of your HTML
4341
+ diff.png Pixel diff (red = different pixels)
4342
+
4343
+ JSON OUTPUT (stdout)
4344
+ {
4345
+ "similarity": 87, // 0-100%
4346
+ "diffPixels": 1340,
4347
+ "totalPixels": 102400,
4348
+ "width": 800,
4349
+ "height": 600,
4350
+ "figmaScreenshot": "/tmp/.../figma.png",
4351
+ "codeScreenshot": "/tmp/.../code.png",
4352
+ "diff": "/tmp/.../diff.png"
4353
+ }
4354
+
4355
+ HOW IT WORKS
4356
+ 1. Fetches Figma screenshot via REST API (scale=2)
4357
+ 2. Reads screenshot dimensions
4358
+ 3. Renders your HTML with Playwright at the same viewport size
4359
+ 4. Compares pixel-by-pixel with pixelmatch (threshold: 0.1)
4360
+ 5. Returns similarity % and diff image
4361
+
4362
+ REQUIREMENTS
4363
+ npx playwright install chromium
4364
+ Figma API token with read access
4365
+ `.trimStart());
4366
+ }
4309
4367
  var DOCS_TOPICS = {
4310
4368
  setup: printDocsSetup,
4311
4369
  install: printDocsSetup,
4312
4370
  // alias
4313
4371
  rules: printDocsRules,
4314
- config: printDocsConfig
4372
+ config: printDocsConfig,
4373
+ "visual-compare": printDocsVisualCompare
4315
4374
  };
4316
4375
  function handleDocs(topic) {
4317
4376
  if (!topic) {
@@ -4323,7 +4382,7 @@ function handleDocs(topic) {
4323
4382
  handler();
4324
4383
  } else {
4325
4384
  console.error(`Unknown docs topic: ${topic}`);
4326
- console.error(`Available topics: setup, rules, config`);
4385
+ console.error(`Available topics: setup, rules, config, visual-compare`);
4327
4386
  process.exit(1);
4328
4387
  }
4329
4388
  }
@@ -5034,7 +5093,7 @@ cli.command("list-rules", "List all analysis rules with scores and severity").op
5034
5093
  process.exit(1);
5035
5094
  }
5036
5095
  });
5037
- cli.command("docs [topic]", "Show documentation (topics: setup, rules, config)").action((topic) => {
5096
+ cli.command("docs [topic]", "Show documentation (topics: setup, rules, config, visual-compare)").action((topic) => {
5038
5097
  handleDocs(topic);
5039
5098
  });
5040
5099
  cli.help((sections) => {