What Is the elementCenter Calculation Used for Screenshot Clipping in ego-browser?
The elementCenter helper in ego-browser resolves a CSS selector or @ref to the viewport-relative center point of a DOM element, and that coordinate becomes the geometric anchor for the clip region passed to Chrome DevTools Protocol's screenshot command.
The elementCenter calculation is the geometric foundation for screenshot clipping in ego-browser, the lightweight browser-automation layer inside the citrolabs/ego-lite repository. When you want to capture a specific element rather than the full viewport, this helper locates the element's visual center. The resulting coordinates are then consumed by the screenshot routine in src/driver/observe.ts to build a pixel-perfect clipping rectangle.
How elementCenter Computes the Viewport Center Point
Resolving References with ensureRefMapForRef
Inside src/driver/observe.ts, the elementCenter method first ensures the internal ref-map is current by calling ensureRefMapForRef. This guarantees that a numeric @ref handle can be safely resolved to a live DOM element before any geometry is measured.
The resolveElementCenter CDP Script
The actual measurement is delegated to resolveElementCenter in src/element-resolver.js. That routine runs a CDP Runtime.evaluate script which:
- Retrieves the element's bounding box via
getBoundingClientRect(). - Extracts
x,y,width, andheightin CSS pixels. - Computes the center point as:
const cx = rect.x + rect.width / 2;
const cy = rect.y + rect.height / 2;
The function returns an object { x: cx, y: cy } representing the point relative to the current viewport after all scroll offsets. According to the ego-lite source code, this viewport-relative precision is what makes downstream clipping reliable.
How That Calculation Enables Screenshot Clipping
Building the Clip Region from a ScreenshotClip
When observe.screenshot is invoked, the caller may supply a ScreenshotClip object, or the code can build one automatically from an element. In either case, the coordinates derived from elementCenter serve as the geometric anchor for the x and y bounds.
Applying Device Pixel Ratio Scaling
Before the capture is triggered, observe.screenshot reads window.devicePixelRatio and computes a CSS scale factor of 1 / dpr. It then merges scale: cssScale with the user-supplied x, y, width, and height. This step ensures that high-DPI displays do not distort the clipped region.
Capturing via Page.captureScreenshot
The finalized params.clip object, now containing both the geometric bounds and the scale factor, is passed to the CDP method Page.captureScreenshot. Because the clip coordinates originate from the elementCenter calculation, the resulting PNG is aligned exactly with the element's visual representation on the page.
Practical Examples for Element-Level Screenshots
Resolve the center of an element by selector or @ref:
const { x, y } = await page.elementCenter('#login-button');
// → { x: 452.3, y: 298.7 }
Capture a screenshot clipped around that center point:
const clip = {
x: x - 100,
y: y - 50,
width: 200,
height: 100
};
const path = await page.screenshot({ clip });
// → writes a PNG containing only the login-button area
For a tight clip that uses the element's exact dimensions:
const rect = await page.evaluate((sel) => {
const el = document.querySelector(sel);
const { x, y, width, height } = el.getBoundingClientRect();
return { x, y, width, height };
}, '#login-button');
const tightPath = await page.screenshot({ clip: { ...rect } });
Key Source Files in the ego-lite Codebase
src/driver/observe.ts– implementselementCenterand the screenshot clipping logic.src/element-resolver.js– containsresolveElementCenter, which runs the CDPRuntime.evaluatescript.src/helpers.ts– re-exportselementCenterso it is available aspage.elementCenter.src/format.ts– documents the helper signature and usage examples.src/driver/pointer.ts– importselementCenterfor mouse-target resolution, demonstrating broader use beyond screenshots.
Summary
elementCenterinego-browserresolves a selector or@refto a viewport-relative center point via CDP.- The calculation uses
getBoundingClientRect()data and the formularect.x + rect.width / 2andrect.y + rect.height / 2. src/driver/observe.tsconsumes this point to build aclipobject forPage.captureScreenshot.- The screenshot routine compensates for device pixel ratio with a scale factor of
1 / dpr. - Because the clip is anchored to the element's center, the captured image aligns precisely with the element's on-screen bounds.
Frequently Asked Questions
How does elementCenter handle scrolled pages?
The CDP script evaluated by resolveElementCenter calls getBoundingClientRect(), which returns coordinates relative to the current viewport after any scrolling. Therefore, elementCenter naturally accounts for scroll offset without requiring manual math.
Can elementCenter accept numeric @ref handles instead of CSS selectors?
Yes. The elementCenter implementation in src/driver/observe.ts first invokes ensureRefMapForRef to map a numeric @ref to a live element, so both string selectors and internal reference handles are valid inputs.
Why is device pixel ratio important for screenshot clipping?
observe.screenshot fetches window.devicePixelRatio and applies a CSS scale of 1 / dpr to the clip parameters. Without this adjustment, high-DPI displays would produce screenshots with incorrect physical dimensions or blurry scaling.
Where is the elementCenter helper exposed on the page object?
src/helpers.ts re-exports elementCenter, attaching it to the page instance so you can call it directly as await page.elementCenter('#selector'). The same utility is also imported in src/driver/pointer.ts for mouse targeting.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →