@oyerinde/caliper 0.1.4 → 0.2.1

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/CHANGELOG.md CHANGED
@@ -2,6 +2,41 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.2.1] - 2026-02-16
6
+
7
+ ### Refactored
8
+
9
+ - **Configuration Engine**: Renamed `OverlayConfig` to `CaliperConfig` to reflect its expanded scope.
10
+ - **Bridge Decoupling**: Moved `bridge` configuration out of the core config type. It is now exclusively a plugin concern, with specialized `IIFEConfig` handling for CDN/script-tag users.
11
+
12
+ ### Added
13
+
14
+ - **Agent Bridge Serialization**: Introduced `onStateChangeGlobal` to allow string-based callback names in `data-config` for IIFE/CDN environments.
15
+
16
+ ### Fixed
17
+
18
+ - **Boundary Box Snapping**: Fixed a bug where boxes would snap to `(0,0)` when elements animated out or were removed from the DOM. The overlay now retains the last known good position.
19
+
20
+ ## [0.2.0] - 2026-02-12
21
+
22
+ ### Added
23
+
24
+ - **Agent Bridge**: Support for AI agents and programmatic audits via `@oyerinde/caliper/bridge`.
25
+ - **MCP Server**: Integrated MCP server for AI auditing (activate via `npx @oyerinde/caliper`).
26
+ - **MCP tools**: `caliper_list_tabs`, `caliper_get_context`, `caliper_switch_tab`, `caliper_inspect`, `caliper_measure`, `caliper_clear`, `caliper_walk_dom`, and `caliper_walk_and_measure`.
27
+ - **Accessibility Tools**: `caliper_check_contrast` and `caliper_delta_e`.
28
+ - **MCP prompts**: `caliper-selector-audit` and `caliper-selectors-compare`.
29
+ - **MCP resources**: `caliper://tabs` and `caliper://state`.
30
+ - **Context Menu**: Right-click selected elements to copy metadata.
31
+ - **Expanded Distribution**: Multi-entry support for `@oyerinde/caliper/preset` and `@oyerinde/caliper/bridge`, alongside dedicated `index.js`, `index.min.js`, and `index.global.js` bundles.
32
+
33
+ ### Fixed
34
+
35
+ - **Geometry Engine**: Improved coordinate tracking for `fixed` and `sticky` elements and nested scroll containers.
36
+ - Fix: Precision tracking for sticky elements across complex DOM hierarchies.
37
+ - Fix: Deep scroll resolution for nested overflow containers.
38
+ - Fix: Real-time clipping path calculation for partially visible elements.
39
+
5
40
  ## [0.1.4] - 2026-01-16
6
41
 
7
42
  ### Fixed
package/README.md CHANGED
@@ -7,6 +7,16 @@
7
7
 
8
8
  Caliper is a high-precision, framework-agnostic measurement tool that lives in your browser during development. It helps you catch "pixel-drift" and alignment issues before they reach production.
9
9
 
10
+ ### AI Agents & MCP 🤖
11
+
12
+ Caliper is "AI-Native". It can be connected to AI agents (like Cursor, Claude Code, or Antigravity) via the **Model Context Protocol (MCP)**, allowing agents to perform pixel-perfect audits of your UI.
13
+
14
+ 1. **Install Bridge**: Available as `@oyerinde/caliper/bridge` for custom integrations.
15
+ 2. **Run Server**: `npx @oyerinde/caliper`
16
+ 3. **Connect**: Add the MCP server to your editor on the default port **9876**.
17
+
18
+ The AI agent gains "layout eyes" and can perform high-precision audits, measurements, and alignment checks directly in your browser.
19
+
10
20
  ---
11
21
 
12
22
  ## Features 🚀
@@ -17,6 +27,8 @@ Caliper is a high-precision, framework-agnostic measurement tool that lives in y
17
27
  - **Edge Projections**: Check alignment across the entire viewport using relative projections (W/A/S/D).
18
28
  - **Viewport Rulers**: Draggable guidelines with magnetic snapping and chained distance measurements (Shift + R).
19
29
  - **Integrated Calculator**: Precise spatial math for complex component spacing (T/R/B/L/G).
30
+ - **Agent Bridge**: Built-in support for AI-driven audits and programmatic UI inspection.
31
+ - **Agent State Sync**: Real-time "passive observation" synchronization with AI agents, providing stable JSON fingerprints for seamless tool-based hand-off.
20
32
  - **Full Customization**: Fully configurable shortcuts and theme colors.
21
33
 
22
34
  ---
@@ -26,6 +38,7 @@ Caliper is a high-precision, framework-agnostic measurement tool that lives in y
26
38
  Caliper is designed to be side-effect-free in production and easy to integrate into any modern stack.
27
39
 
28
40
  ### 1. Next.js (App Router)
41
+
29
42
  ```tsx
30
43
  // app/layout.tsx
31
44
  import Script from "next/script";
@@ -37,7 +50,7 @@ export default function RootLayout({ children }) {
37
50
  {process.env.NODE_ENV === "development" && (
38
51
  <Script
39
52
  src="https://unpkg.com/@oyerinde/caliper/dist/index.global.js"
40
- data-config={JSON.stringify({ theme: { primary: '#AC2323' } })}
53
+ data-config={JSON.stringify({ theme: { primary: "#AC2323" } })}
41
54
  strategy="afterInteractive"
42
55
  />
43
56
  )}
@@ -49,19 +62,21 @@ export default function RootLayout({ children }) {
49
62
  ```
50
63
 
51
64
  ### 2. Vite
65
+
52
66
  ```html
53
67
  <!-- index.html -->
54
68
  <script type="module">
55
- if (import.meta.env.DEV) {
56
- // Run npm i @oyerinde/caliper then
57
- import("@oyerinde/caliper").then(({ init }) => {
58
- init({ theme: { primary: '#AC2323' } });
59
- });
60
- }
69
+ if (import.meta.env.DEV) {
70
+ // Run npm i @oyerinde/caliper then
71
+ import("@oyerinde/caliper").then(({ init }) => {
72
+ init({ theme: { primary: "#AC2323" } });
73
+ });
74
+ }
61
75
  </script>
62
76
  ```
63
77
 
64
78
  ### 3. HTML (Plain)
79
+
65
80
  ```html
66
81
  <!-- index.html -->
67
82
  <script type="module">
@@ -76,12 +91,13 @@ if (import.meta.env.DEV) {
76
91
  ```
77
92
 
78
93
  ### 4. Astro
94
+
79
95
  ```html
80
96
  <!-- src/components/Caliper.astro -->
81
97
  <script type="module" is:inline>
82
98
  if (import.meta.env.DEV) {
83
99
  // Run npm i @oyerinde/caliper then
84
- import('@oyerinde/caliper').then(({ init }) => {
100
+ import("@oyerinde/caliper").then(({ init }) => {
85
101
  init();
86
102
  });
87
103
  }
@@ -89,6 +105,7 @@ if (import.meta.env.DEV) {
89
105
  ```
90
106
 
91
107
  ### 5. Nuxt
108
+
92
109
  ```ts
93
110
  // nuxt.config.ts
94
111
  export default defineNuxtConfig({
@@ -96,43 +113,45 @@ export default defineNuxtConfig({
96
113
  head: {
97
114
  script: [
98
115
  {
99
- src: 'https://unpkg.com/@oyerinde/caliper/dist/index.global.js',
100
- 'data-config': JSON.stringify({ theme: { primary: '#AC2323' } }),
101
- defer: true
102
- }
103
- ]
104
- }
105
- }
116
+ src: "https://unpkg.com/@oyerinde/caliper/dist/index.global.js",
117
+ "data-config": JSON.stringify({ theme: { primary: "#AC2323" } }),
118
+ defer: true,
119
+ },
120
+ ],
121
+ },
122
+ },
106
123
  });
107
124
  ```
108
125
 
109
126
  ### 6. Vue
127
+
110
128
  ```html
111
129
  <!-- index.html -->
112
130
  <script type="module">
113
131
  if (import.meta.env.DEV) {
114
132
  // Run npm i @oyerinde/caliper then
115
133
  import("@oyerinde/caliper").then(({ init }) => {
116
- init({ theme: { primary: '#AC2323' } });
134
+ init({ theme: { primary: "#AC2323" } });
117
135
  });
118
136
  }
119
137
  </script>
120
138
  ```
121
139
 
122
140
  ### 7. TanStack Start
141
+
123
142
  ```tsx
124
143
  // root.tsx
125
- import { Meta, Scripts } from '@tanstack/react-router';
144
+ import { Meta, Scripts } from "@tanstack/react-router";
126
145
 
127
146
  export function Root() {
128
147
  return (
129
148
  <html lang="en">
130
149
  <head>
131
150
  <Meta />
132
- {process.env.NODE_ENV === 'development' && (
151
+ {process.env.NODE_ENV === "development" && (
133
152
  <script
134
153
  src="https://unpkg.com/@oyerinde/caliper/dist/index.global.js"
135
- data-config={JSON.stringify({ theme: { primary: '#AC2323' } })}
154
+ data-config={JSON.stringify({ theme: { primary: "#AC2323" } })}
136
155
  async
137
156
  />
138
157
  )}
@@ -147,6 +166,59 @@ export function Root() {
147
166
 
148
167
  ---
149
168
 
169
+ ## Agent Bridge Installation 🤖
170
+
171
+ The Agent Bridge enables AI agents (like Claude or Cursor) to communicate with Caliper. It is available as a sub-export of the main package.
172
+
173
+ ### 1. Vite & Module Bundlers
174
+
175
+ If you've installed `@oyerinde/caliper` via npm, you can initialize the bridge using the plugin pattern:
176
+
177
+ ```typescript
178
+ import { init } from "@oyerinde/caliper";
179
+ import { CaliperBridge } from "@oyerinde/caliper/bridge";
180
+
181
+ const caliper = init();
182
+
183
+ caliper.use(
184
+ CaliperBridge({
185
+ enabled: true,
186
+ wsPort: 9876,
187
+ })
188
+ );
189
+ ```
190
+
191
+ ### 2. Standalone (CDN/IIFE)
192
+
193
+ If you are using the global script tag, the bridge is automatically included in the default bundle. Use the **minified lite** version if you don't need bridge support:
194
+
195
+ ```html
196
+ <!-- Full version (Includes Agent Bridge) -->
197
+ <script
198
+ src="https://unpkg.com/@oyerinde/caliper/dist/index.global.js"
199
+ data-config='{"bridge": {"enabled": true}}'
200
+ ></script>
201
+
202
+ <!-- Lite Version (Core only, No Bridge) -->
203
+ <script src="https://unpkg.com/@oyerinde/caliper/dist/index.global.min.js"></script>
204
+ ```
205
+
206
+ ### 3. Next.js (App Router)
207
+
208
+ Enable the bridge directly in your configuration block:
209
+
210
+ ```tsx
211
+ <Script
212
+ src="https://unpkg.com/@oyerinde/caliper/dist/index.global.js"
213
+ data-config={JSON.stringify({
214
+ bridge: { enabled: true },
215
+ })}
216
+ strategy="afterInteractive"
217
+ />
218
+ ```
219
+
220
+ ---
221
+
150
222
  ## Configuration 🛠️
151
223
 
152
224
  Caliper can be customized to fit your specific design system and workflow. `init()` automatically mounts the overlay in the browser.
@@ -157,17 +229,39 @@ import { init } from "@oyerinde/caliper";
157
229
  init({
158
230
  theme: {
159
231
  primary: "#18A0FB", // Main brand color
160
- ruler: "#AC2323", // Guideline color
161
- calcBg: "rgba(0,0,0,0.9)",
232
+ secondary: "#F24E1E", // Accent color (for highlights)
233
+ calcBg: "rgba(30,30,30,0.95)",
234
+ calcShadow: "rgba(0,0,0,0.5)",
235
+ calcOpHighlight: "#18A0FB", // Operator pulse color
236
+ calcText: "#FFFFFF",
237
+ text: "#FFFFFF",
238
+ projection: "#9B51E4", // Edge projection lines
239
+ ruler: "#18A0FB", // Ruler/guideline color
162
240
  },
163
241
  commands: {
164
- activate: "Alt", // Key to show overlay
242
+ activate: "Alt", // Reveal overlay
165
243
  freeze: " ", // Key to lock lines
166
- ruler: "r", // Key for guideline (Shift+r)
167
- selectionHoldDuration: 250, // Hold duration to select
244
+ select: "Control", // Key to select (held)
245
+ clear: "Escape", // Clear measurements
246
+ ruler: "r", // Ruler (Shift+r)
247
+ selectionHoldDuration: 250, // Select hold-time (ms)
248
+ calculator: {
249
+ top: "t",
250
+ right: "r",
251
+ bottom: "b",
252
+ left: "l",
253
+ distance: "g",
254
+ },
255
+ projection: {
256
+ top: "w",
257
+ left: "a",
258
+ bottom: "s",
259
+ right: "d",
260
+ },
168
261
  },
169
262
  animation: {
170
- lerpFactor: 0.2, // Smoothness (0-1)
263
+ enabled: true, // Smooth hover box
264
+ lerpFactor: 0.25, // Fluidity (low = slower)
171
265
  },
172
266
  });
173
267
  ```
@@ -182,6 +276,16 @@ To prevent Caliper from measuring specific elements (like sidebars, floating but
182
276
  </div>
183
277
  ```
184
278
 
279
+ ### Stable Markers
280
+
281
+ For AI agents to reliably rediscover elements across re-renders (like HMR), we recommend adding stable markers to critical UI components. Use the `caliperProps` helper to add these attributes only in non-production environments.
282
+
283
+ **Usage:**
284
+
285
+ ```tsx
286
+ <div {...caliperProps("main-sidebar")}>...</div>
287
+ ```
288
+
185
289
  ---
186
290
 
187
291
  ## Interaction Guide ⌨️
@@ -189,6 +293,7 @@ To prevent Caliper from measuring specific elements (like sidebars, floating but
189
293
  ### Measurements
190
294
 
191
295
  - **Cmd/Ctrl + Click + Hold** (250ms) — Select an element.
296
+ - **Right-Click** — Copy element metadata (selector, ID, text) when selected.
192
297
  - **Hover** — View relative distances to target.
193
298
  - **Option/Alt** — Hold to reveal the overlay.
194
299
  - **Space** — Freeze the current state.
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ var chunkPYAVLOZM_cjs = require('./chunk-PYAVLOZM.cjs');
4
+
5
+
6
+
7
+ Object.defineProperty(exports, "CALIPER_METHODS", {
8
+ enumerable: true,
9
+ get: function () { return chunkPYAVLOZM_cjs.CALIPER_METHODS; }
10
+ });
11
+ Object.defineProperty(exports, "CaliperActionResultSchema", {
12
+ enumerable: true,
13
+ get: function () { return chunkPYAVLOZM_cjs.CaliperActionResultSchema; }
14
+ });
15
+ Object.defineProperty(exports, "CaliperAgentStateSchema", {
16
+ enumerable: true,
17
+ get: function () { return chunkPYAVLOZM_cjs.CaliperAgentStateSchema; }
18
+ });
19
+ Object.defineProperty(exports, "CaliperBridge", {
20
+ enumerable: true,
21
+ get: function () { return chunkPYAVLOZM_cjs.CaliperBridge; }
22
+ });
23
+ Object.defineProperty(exports, "CaliperGetContextPayloadSchema", {
24
+ enumerable: true,
25
+ get: function () { return chunkPYAVLOZM_cjs.CaliperGetContextPayloadSchema; }
26
+ });
27
+ Object.defineProperty(exports, "CaliperInspectPayloadSchema", {
28
+ enumerable: true,
29
+ get: function () { return chunkPYAVLOZM_cjs.CaliperInspectPayloadSchema; }
30
+ });
31
+ Object.defineProperty(exports, "CaliperMeasurePayloadSchema", {
32
+ enumerable: true,
33
+ get: function () { return chunkPYAVLOZM_cjs.CaliperMeasurePayloadSchema; }
34
+ });
35
+ Object.defineProperty(exports, "CaliperSelectPayloadSchema", {
36
+ enumerable: true,
37
+ get: function () { return chunkPYAVLOZM_cjs.CaliperSelectPayloadSchema; }
38
+ });
39
+ Object.defineProperty(exports, "CaliperWalkAndMeasurePayloadSchema", {
40
+ enumerable: true,
41
+ get: function () { return chunkPYAVLOZM_cjs.CaliperWalkAndMeasurePayloadSchema; }
42
+ });
43
+ Object.defineProperty(exports, "CaliperWalkDomPayloadSchema", {
44
+ enumerable: true,
45
+ get: function () { return chunkPYAVLOZM_cjs.CaliperWalkDomPayloadSchema; }
46
+ });
47
+ Object.defineProperty(exports, "dispatchCaliperIntent", {
48
+ enumerable: true,
49
+ get: function () { return chunkPYAVLOZM_cjs.dispatchCaliperIntent; }
50
+ });