| name | alignment-verification |
| description | Zero-tolerance alignment verification protocol. Alignment is binary - elements are either in line or they're not. Report exact measurements, no tolerances, no "close enough." |
Alignment Verification Skill
RULE: Alignment is BINARY. In line or not. Zero tolerances.
Core Principle
Alignment verification has exactly two outcomes:
- Delta = 0px --> ALIGNED: YES
- Delta > 0px --> ALIGNED: NO (report exact deviation)
There are NO tolerances. A 2px deviation in a row of chips is visible. A 1px misalignment between form labels is noticeable. "Close enough" does not exist.
When you claim something is aligned, you MUST prove it with pixel measurements.
Mental Model
Alignment is a RELATIONSHIP between elements, not a property of a single element.
Every alignment check requires:
- Target Element(s) - What you are checking
- Reference Element - What you are aligning TO (parent, sibling, baseline)
- Alignment Type - How they should relate (center, edge, spacing)
- Container Space - For alignment to work, there must be space to align within
Example mental model:
"Button should be horizontally centered in its parent"
- Target: the button
- Reference: the parent container
- Type: horizontal center
- Container: parent must be wider than button for centering to be meaningful
Verification Protocol
Step 1: Identify What Should Align
Before measuring, explicitly state:
- Which elements are being checked
- What type of alignment is expected
- What the reference point is
Step 2: Extract Exact Pixel Values
Use Puppeteer's evaluate to get precise measurements:
// Get element bounding box via puppeteer_evaluate
puppeteer_evaluate({
script: `
const el = document.querySelector('[selector]');
const box = el.getBoundingClientRect();
JSON.stringify({ x: box.x, y: box.y, width: box.width, height: box.height });
`
})
// Returns: { x, y, width, height }
Extract ALL values needed for your alignment type.
Step 3: Calculate Exact Deviations
Calculate with full precision. DO NOT round. DO NOT apply tolerances.
// For horizontal centering in parent
const parentBox = await page.locator('[parent]').boundingBox();
const childBox = await page.locator('[child]').boundingBox();
const parentCenter = parentBox.x + (parentBox.width / 2);
const childCenter = childBox.x + (childBox.width / 2);
const deviation = Math.abs(parentCenter - childCenter);
// Report: deviation === 0 ? "ALIGNED: YES" : `ALIGNED: NO (${deviation}px off)`
Step 4: Output ALIGNMENT_CHECK Block
Every alignment verification MUST produce this output:
ALIGNMENT_CHECK:
- Task: [alignment goal in plain language]
- Type: [horizontal_center|vertical_center|left_edge|right_edge|top_edge|bottom_edge|spacing]
- Elements measured:
- [selector]: [value]px
- [selector]: [value]px
- ALIGNED: YES/NO
- Max deviation: Xpx
- Deviations: [list if multiple elements]
Alignment Types with Code
Center Horizontally in Parent
// Measure
const parent = await page.locator('.parent').boundingBox();
const child = await page.locator('.child').boundingBox();
// Calculate
const parentCenterX = parent.x + (parent.width / 2);
const childCenterX = child.x + (child.width / 2);
const deviation = Math.abs(parentCenterX - childCenterX);
// Report
console.log(`Parent center: ${parentCenterX}px`);
console.log(`Child center: ${childCenterX}px`);
console.log(`Deviation: ${deviation}px`);
console.log(`ALIGNED: ${deviation === 0 ? 'YES' : 'NO'}`);
Center Vertically in Parent
// Measure
const parent = await page.locator('.parent').boundingBox();
const child = await page.locator('.child').boundingBox();
// Calculate
const parentCenterY = parent.y + (parent.height / 2);
const childCenterY = child.y + (child.height / 2);
const deviation = Math.abs(parentCenterY - childCenterY);
// Report
console.log(`Parent center Y: ${parentCenterY}px`);
console.log(`Child center Y: ${childCenterY}px`);
console.log(`Deviation: ${deviation}px`);
console.log(`ALIGNED: ${deviation === 0 ? 'YES' : 'NO'}`);
Left Edge Alignment (Multiple Elements)
// Measure all elements
const elements = await page.locator('.item').all();
const leftEdges = [];
for (const el of elements) {
const box = await el.boundingBox();
leftEdges.push(box.x);
}
// Calculate deviations from first element
const reference = leftEdges[0];
const deviations = leftEdges.map((x, i) => ({
index: i,
value: x,
deviation: Math.abs(x - reference)
}));
// Report
const maxDeviation = Math.max(...deviations.map(d => d.deviation));
console.log(`Reference left edge: ${reference}px`);
deviations.forEach(d => {
console.log(`Element ${d.index}: ${d.value}px (deviation: ${d.deviation}px)`);
});
console.log(`Max deviation: ${maxDeviation}px`);
console.log(`ALIGNED: ${maxDeviation === 0 ? 'YES' : 'NO'}`);
Right Edge Alignment
// Measure
const elements = await page.locator('.item').all();
const rightEdges = [];
for (const el of elements) {
const box = await el.boundingBox();
rightEdges.push(box.x + box.width);
}
// Calculate deviations from first element
const reference = rightEdges[0];
const deviations = rightEdges.map((r, i) => ({
index: i,
value: r,
deviation: Math.abs(r - reference)
}));
// Report
const maxDeviation = Math.max(...deviations.map(d => d.deviation));
console.log(`ALIGNED: ${maxDeviation === 0 ? 'YES' : 'NO'}`);
Top Edge Alignment
// Measure
const elements = await page.locator('.item').all();
const topEdges = [];
for (const el of elements) {
const box = await el.boundingBox();
topEdges.push(box.y);
}
// Calculate deviations from first element
const reference = topEdges[0];
const maxDeviation = Math.max(...topEdges.map(y => Math.abs(y - reference)));
// Report
console.log(`ALIGNED: ${maxDeviation === 0 ? 'YES' : 'NO'}`);
console.log(`Max deviation: ${maxDeviation}px`);
Equal Spacing Between Elements
// Measure
const elements = await page.locator('.item').all();
const boxes = [];
for (const el of elements) {
boxes.push(await el.boundingBox());
}
// Calculate gaps between consecutive elements
const gaps = [];
for (let i = 1; i < boxes.length; i++) {
const gap = boxes[i].x - (boxes[i-1].x + boxes[i-1].width);
gaps.push(gap);
}
// Calculate deviations from first gap
const referenceGap = gaps[0];
const deviations = gaps.map((g, i) => ({
index: i,
value: g,
deviation: Math.abs(g - referenceGap)
}));
// Report
const maxDeviation = Math.max(...deviations.map(d => d.deviation));
console.log(`Reference gap: ${referenceGap}px`);
deviations.forEach(d => {
console.log(`Gap ${d.index}: ${d.value}px (deviation: ${d.deviation}px)`);
});
console.log(`ALIGNED: ${maxDeviation === 0 ? 'YES' : 'NO'}`);
Common Pitfalls
CSS: margin: auto needs flex/grid parent
/* WRONG - margin auto alone does nothing in block layout */
.child {
margin: 0 auto;
}
/* RIGHT - parent must be flex or block with defined width */
.parent {
display: flex;
justify-content: center;
}
/* OR */
.child {
width: 200px; /* must have explicit width */
margin: 0 auto;
}
SwiftUI: .center needs frame larger than content
// WRONG - no frame means content hugs, nothing to center within
Text("Hello")
.frame(alignment: .center)
// RIGHT - explicit frame provides space to center within
Text("Hello")
.frame(maxWidth: .infinity, alignment: .center)
Transforms affect visual but not bounding box
getBoundingClientRect() returns the ORIGINAL position before CSS transforms. If you use transform: translateX() or similar, the visual position differs from the measured position.
// Element visually at 100px but boundingBox shows 0px due to transform
// Solution: account for transforms or use offsetLeft/getBoundingClientRect
Asymmetric content (icon in button)
A button with an icon on one side may APPEAR off-center even when the button IS centered, because the visual weight is asymmetric.
[ Icon Text ] <-- Button is centered but looks left-heavy
Solution: Either accept true center or adjust with padding to achieve
optical center (but document this explicitly).
Anti-Patterns (FORBIDDEN Language)
The following phrases are REJECTED in alignment verification:
| Phrase | Why Rejected |
|---|---|
| "within tolerance" | There is no tolerance. 0px or report deviation. |
| "close enough" | Not a measurement. What is the actual deviation? |
| "approximately aligned" | Approximate is not aligned. Give the number. |
| "looks aligned" | Visual assertion without ALIGNMENT_CHECK block. |
| "alignment seems fine" | "Seems" is not measurement. Prove it. |
| "roughly centered" | "Roughly" is not a pixel value. |
How to Fix
WRONG:
"The chips look aligned to me."
RIGHT:
ALIGNMENT_CHECK:
- Task: Verify horizontal alignment of chip row
- Type: top_edge
- Elements measured:
- chip[0]: y=142px
- chip[1]: y=142px
- chip[2]: y=142px
- chip[3]: y=144px
- ALIGNED: NO
- Max deviation: 2px
- Deviations: chip[3] is 2px below reference
Complete Verification Example
Task: "Center the modal horizontally in the viewport"
// Step 1: Identify
// - Target: .modal
// - Reference: viewport
// - Type: horizontal_center
// Step 2: Measure
const viewport = await page.viewportSize();
const modal = await page.locator('.modal').boundingBox();
// Step 3: Calculate
const viewportCenterX = viewport.width / 2;
const modalCenterX = modal.x + (modal.width / 2);
const deviation = Math.abs(viewportCenterX - modalCenterX);
// Step 4: Output
console.log(`
ALIGNMENT_CHECK:
- Task: Center modal horizontally in viewport
- Type: horizontal_center
- Elements measured:
- viewport center: ${viewportCenterX}px
- modal center: ${modalCenterX}px
- ALIGNED: ${deviation === 0 ? 'YES' : 'NO'}
- Max deviation: ${deviation}px
`);
Integration with Other Skills
- debugging-first: Use alignment verification AFTER confirming elements render
- design-qa-skill: Alignment checks are one component of full design QA
- lovable-pitfalls: Avoid premature "looks good" claims by measuring
When to Apply This Skill
ALWAYS apply when:
- User says "center this"
- User says "align these"
- User says "make them line up"
- Reviewing spacing consistency
- Verifying layout implementation
SKIP when:
- No alignment requirements mentioned
- Working on non-visual code (APIs, logic)
- User explicitly says "don't worry about exact alignment"