@neonwatty/limner 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 (82) hide show
  1. package/README.md +161 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +26 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/commands/capture.d.ts +12 -0
  6. package/dist/commands/capture.js +66 -0
  7. package/dist/commands/capture.js.map +1 -0
  8. package/dist/commands/compare-image-app.d.ts +12 -0
  9. package/dist/commands/compare-image-app.js +45 -0
  10. package/dist/commands/compare-image-app.js.map +1 -0
  11. package/dist/commands/compare-image-reference.d.ts +28 -0
  12. package/dist/commands/compare-image-reference.js +82 -0
  13. package/dist/commands/compare-image-reference.js.map +1 -0
  14. package/dist/commands/compare.d.ts +15 -0
  15. package/dist/commands/compare.js +168 -0
  16. package/dist/commands/compare.js.map +1 -0
  17. package/dist/commands/init.d.ts +12 -0
  18. package/dist/commands/init.js +65 -0
  19. package/dist/commands/init.js.map +1 -0
  20. package/dist/commands/preview.d.ts +2 -0
  21. package/dist/commands/preview.js +27 -0
  22. package/dist/commands/preview.js.map +1 -0
  23. package/dist/commands/report.d.ts +2 -0
  24. package/dist/commands/report.js +14 -0
  25. package/dist/commands/report.js.map +1 -0
  26. package/dist/commands/runs.d.ts +2 -0
  27. package/dist/commands/runs.js +63 -0
  28. package/dist/commands/runs.js.map +1 -0
  29. package/dist/core/dom-metrics.d.ts +18 -0
  30. package/dist/core/dom-metrics.js +54 -0
  31. package/dist/core/dom-metrics.js.map +1 -0
  32. package/dist/core/playwright-capture.d.ts +27 -0
  33. package/dist/core/playwright-capture.js +46 -0
  34. package/dist/core/playwright-capture.js.map +1 -0
  35. package/dist/core/playwright-dom.d.ts +16 -0
  36. package/dist/core/playwright-dom.js +64 -0
  37. package/dist/core/playwright-dom.js.map +1 -0
  38. package/dist/core/reference-dom-facts.d.ts +65 -0
  39. package/dist/core/reference-dom-facts.js +71 -0
  40. package/dist/core/reference-dom-facts.js.map +1 -0
  41. package/dist/core/report-writer.d.ts +43 -0
  42. package/dist/core/report-writer.js +181 -0
  43. package/dist/core/report-writer.js.map +1 -0
  44. package/dist/core/run-logger.d.ts +22 -0
  45. package/dist/core/run-logger.js +67 -0
  46. package/dist/core/run-logger.js.map +1 -0
  47. package/dist/core/side-by-side.d.ts +8 -0
  48. package/dist/core/side-by-side.js +33 -0
  49. package/dist/core/side-by-side.js.map +1 -0
  50. package/dist/core/static-server.d.ts +6 -0
  51. package/dist/core/static-server.js +73 -0
  52. package/dist/core/static-server.js.map +1 -0
  53. package/dist/core/visual-spec-agent-pack.d.ts +27 -0
  54. package/dist/core/visual-spec-agent-pack.js +143 -0
  55. package/dist/core/visual-spec-agent-pack.js.map +1 -0
  56. package/dist/core/visual-spec-prompts.d.ts +32 -0
  57. package/dist/core/visual-spec-prompts.js +129 -0
  58. package/dist/core/visual-spec-prompts.js.map +1 -0
  59. package/dist/core/workspace.d.ts +31 -0
  60. package/dist/core/workspace.js +97 -0
  61. package/dist/core/workspace.js.map +1 -0
  62. package/dist/index.d.ts +14 -0
  63. package/dist/index.js +12 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/schemas/contract.d.ts +43 -0
  66. package/dist/schemas/contract.js +19 -0
  67. package/dist/schemas/contract.js.map +1 -0
  68. package/dist/schemas/events.d.ts +34 -0
  69. package/dist/schemas/events.js +29 -0
  70. package/dist/schemas/events.js.map +1 -0
  71. package/dist/schemas/visual-spec.d.ts +410 -0
  72. package/dist/schemas/visual-spec.js +201 -0
  73. package/dist/schemas/visual-spec.js.map +1 -0
  74. package/docs/agent-workflow.md +45 -0
  75. package/package.json +64 -0
  76. package/skills/limner/SKILL.md +51 -0
  77. package/templates/target/AGENT_GUIDE.md +24 -0
  78. package/templates/target/contract/acceptance.md +23 -0
  79. package/templates/target/contract/regions.json +11 -0
  80. package/templates/target/contract/tokens.json +21 -0
  81. package/templates/target/reference/index.html +22 -0
  82. package/templates/target/reference/styles.css +53 -0
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@neonwatty/limner",
3
+ "version": "0.1.0",
4
+ "description": "Agent-guided visual fidelity workbench for turning images into HTML references and comparing references to real apps.",
5
+ "type": "module",
6
+ "bin": {
7
+ "limn": "dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "templates",
12
+ "docs",
13
+ "skills",
14
+ "README.md"
15
+ ],
16
+ "scripts": {
17
+ "build": "npm run clean && tsc -p tsconfig.build.json",
18
+ "check": "npm run lint && npm run typecheck && npm test && npm run build && npm run knip && npm run check:size",
19
+ "check:size": "node scripts/check-file-size.mjs",
20
+ "clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
21
+ "dev": "tsx src/cli.ts",
22
+ "knip": "knip",
23
+ "lint": "eslint .",
24
+ "lint:staged": "lint-staged",
25
+ "test": "vitest run",
26
+ "typecheck": "tsc --noEmit"
27
+ },
28
+ "lint-staged": {
29
+ "*.{js,mjs,cjs,ts,tsx}": [
30
+ "eslint --fix --no-error-on-unmatched-pattern"
31
+ ],
32
+ "*": [
33
+ "node scripts/check-file-size.mjs --staged"
34
+ ]
35
+ },
36
+ "keywords": [
37
+ "visual-regression",
38
+ "design",
39
+ "playwright",
40
+ "cli",
41
+ "agent"
42
+ ],
43
+ "license": "MIT",
44
+ "engines": {
45
+ "node": ">=20"
46
+ },
47
+ "dependencies": {
48
+ "commander": "^15.0.0",
49
+ "playwright": "^1.57.0",
50
+ "sharp": "^0.34.5",
51
+ "zod": "^4.2.1"
52
+ },
53
+ "devDependencies": {
54
+ "@eslint/js": "^10.0.1",
55
+ "@types/node": "^25.0.0",
56
+ "eslint": "^10.4.1",
57
+ "knip": "^6.16.1",
58
+ "lint-staged": "^17.0.7",
59
+ "tsx": "^4.21.0",
60
+ "typescript": "^6.0.3",
61
+ "typescript-eslint": "^8.61.0",
62
+ "vitest": "^4.1.0"
63
+ }
64
+ }
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: limner
3
+ description: Use when turning an image into a reference HTML facsimile or comparing approved reference HTML against a real app implementation.
4
+ ---
5
+
6
+ # Limner
7
+
8
+ Use Limner for structured visual fidelity loops.
9
+
10
+ ## Image To Reference
11
+
12
+ 1. Run `limn init <image> --target <name>` if the target does not exist.
13
+ 2. Inspect `source/ideal.png`.
14
+ 3. Fill `contract/regions.json`, `contract/tokens.json`, and `contract/acceptance.md`.
15
+ 4. Edit `reference/index.html` and `reference/styles.css`.
16
+ 5. Run `limn compare image-reference --target <name>`.
17
+ 6. Review `captures/image-reference/side-by-side.png`.
18
+ 7. Record findings in `reports/image-reference.md`.
19
+
20
+ Optional structured spec layer:
21
+
22
+ - Run `limn compare image-reference --target <name> --spec`.
23
+ - Edit `contract/visual-spec-instructions.md` to customize the agent prompt for this target, or pass `--spec-instructions <path>` for a shared policy file.
24
+ - Use `captures/image-reference/spec/agent-prompt.codex.md` for Codex or `captures/image-reference/spec/agent-prompt.claude.md` for Claude.
25
+ - Use the generated `captures/image-reference/spec/agent-response.schema.json` for strict structured output when the agent supports it.
26
+ - The agent should inspect the ideal image and reference screenshot separately. The side-by-side is comparison context, not the image to parse.
27
+ - Have the agent write `captures/image-reference/spec/agent-response.json`.
28
+ - Rerun the same command so Limner can validate the response and emit the spec and diff JSON artifacts.
29
+
30
+ ## Reference To App
31
+
32
+ 1. Confirm the reference HTML is approved.
33
+ 2. Ensure every important region has both `referenceSelector` and `appSelector`.
34
+ 3. Run `limn compare reference-app --target <name> --url <app-url>`.
35
+ 4. Review `captures/reference-app/side-by-side.png` and `dom-metrics.json`.
36
+ 5. Use the report to drive one scoped app fix.
37
+ 6. Rerun after the fix.
38
+
39
+ ## Image To App Grounding
40
+
41
+ Use `limn compare image-app --target <name> --url <app-url>` to compare the source image directly to an app screenshot.
42
+
43
+ Add `--storage-state <path>` for authenticated pages and `--full-page` only when a full-page screenshot is intended. The default is viewport-only.
44
+
45
+ For generated-image reconstruction work, do not skip Image To Reference. Build the HTML facsimile first, then compare the approved reference to the app.
46
+
47
+ ## Constraints
48
+
49
+ - Limner does not call an AI vision model itself. The `--spec` workflow requires an external agent.
50
+ - Limner does not make final pass/fail judgments.
51
+ - Limner logs only local JSONL events under `.limner/runs/`.
@@ -0,0 +1,24 @@
1
+ # Agent Guide
2
+
3
+ Use this target folder as a structured workbench for visual fidelity.
4
+
5
+ ## Loop 1: Image To Reference
6
+
7
+ 1. Inspect `source/ideal.png`.
8
+ 2. Fill out `contract/regions.json`, `contract/tokens.json`, and `contract/acceptance.md`.
9
+ 3. Edit `reference/index.html` and `reference/styles.css` until the reference is a faithful HTML facsimile.
10
+ 4. Run `limn compare image-reference --target <target>`.
11
+ 5. Review `captures/image-reference/side-by-side.png` and `reports/image-reference.md`.
12
+ 6. Record remaining mismatches or intentional deviations.
13
+
14
+ ## Loop 2: Reference To App
15
+
16
+ 1. Treat the reference HTML as the approved design.
17
+ 2. Add app selectors to `contract/regions.json`.
18
+ 3. Run `limn compare reference-app --target <target> --url <app-url>`.
19
+ 4. Review screenshots, DOM metrics, and `reports/reference-app.md`.
20
+ 5. Fix the app, rerun the comparison, and keep notes in the report.
21
+
22
+ ## Rule
23
+
24
+ Limner does not decide visual success automatically. It produces evidence so the agent and human can make sharper decisions.
@@ -0,0 +1,23 @@
1
+ # Acceptance Notes
2
+
3
+ ## Required Regions
4
+
5
+ - `reference-root`: the complete reference surface.
6
+
7
+ ## Intentional Differences
8
+
9
+ - Record any visual or product-truth deviations here before treating the reference as approved.
10
+
11
+ ## Forbidden Affordances
12
+
13
+ - Do not add fake navigation, forms, or actions that do not exist in the app implementation.
14
+
15
+ ## Top Failure Modes
16
+
17
+ 1. The reference HTML captures the rough layout but misses the visual hierarchy of the input image.
18
+ 2. The app implementation matches colors or copy while missing the actual region proportions.
19
+ 3. Disabled or unavailable actions look enabled.
20
+
21
+ ## Negative Checks
22
+
23
+ - Confirm clipped text, overflow, and disabled affordances are explicitly reviewed.
@@ -0,0 +1,11 @@
1
+ {
2
+ "regions": [
3
+ {
4
+ "id": "reference-root",
5
+ "label": "Reference Root",
6
+ "referenceSelector": "[data-limner-region='reference-root']",
7
+ "appSelector": "body",
8
+ "checks": ["bounds", "visible", "computed-style", "text"]
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "colors": {
3
+ "background": "#f8fafc",
4
+ "surface": "#ffffff",
5
+ "text": "#0f172a",
6
+ "mutedText": "#475569",
7
+ "border": "#dbe3ee"
8
+ },
9
+ "radii": {
10
+ "panel": 12,
11
+ "control": 6
12
+ },
13
+ "typography": {
14
+ "bodyFont": "Inter, ui-sans-serif, system-ui, sans-serif",
15
+ "headingWeight": 760
16
+ },
17
+ "spacing": {
18
+ "pagePadding": 32,
19
+ "panelPadding": 28
20
+ }
21
+ }
@@ -0,0 +1,22 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Limner Reference</title>
7
+ <link rel="stylesheet" href="./styles.css">
8
+ </head>
9
+ <body>
10
+ <main data-limner-region="reference-root" class="limner-reference">
11
+ <section class="reference-panel">
12
+ <p class="eyebrow">Limner Reference</p>
13
+ <h1>Recreate the input image here</h1>
14
+ <p>
15
+ Replace this scaffold with faithful HTML and CSS. Add
16
+ <code>data-limner-region</code> attributes to regions that should be
17
+ compared against app selectors.
18
+ </p>
19
+ </section>
20
+ </main>
21
+ </body>
22
+ </html>
@@ -0,0 +1,53 @@
1
+ :root {
2
+ color-scheme: light;
3
+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
4
+ color: #0f172a;
5
+ background: #f8fafc;
6
+ }
7
+
8
+ * {
9
+ box-sizing: border-box;
10
+ }
11
+
12
+ body {
13
+ margin: 0;
14
+ min-height: 100vh;
15
+ background: #f8fafc;
16
+ }
17
+
18
+ .limner-reference {
19
+ min-height: 100vh;
20
+ display: grid;
21
+ place-items: center;
22
+ padding: 32px;
23
+ }
24
+
25
+ .reference-panel {
26
+ width: min(760px, 100%);
27
+ padding: 28px;
28
+ border: 1px solid #dbe3ee;
29
+ border-radius: 12px;
30
+ background: #ffffff;
31
+ box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
32
+ }
33
+
34
+ .eyebrow {
35
+ margin: 0 0 8px;
36
+ color: #2563eb;
37
+ font-size: 0.75rem;
38
+ font-weight: 800;
39
+ letter-spacing: 0.08em;
40
+ text-transform: uppercase;
41
+ }
42
+
43
+ h1 {
44
+ margin: 0 0 10px;
45
+ font-size: 2rem;
46
+ line-height: 1.1;
47
+ }
48
+
49
+ p {
50
+ margin: 0;
51
+ color: #475569;
52
+ line-height: 1.55;
53
+ }