Sample a coordinate and see the browser's rendered DOM hit-test stack there, the top sampled candidate, and the computed state that can explain surprising interception.
One dependency-free script. No extension. No account. No network.
Inject dist/hitstack.js into any page. Call window.__hitstack.activate().
Move your pointer to a coordinate. Press F2. The instrument shows:
- every element the browser returns for that coordinate, ordered top to bottom
- the computed
pointer-events,opacity, andvisibilityfor each candidate - a Copy receipt button that writes a
hitstack-snapshot/v1JSON to your clipboard
Press Escape or call deactivate() to tear down completely.
What this is not: a "target," "receiver," "handler," or event-delivery truth.
elementsFromPoint is a hit-test primitive, not an event-delivery oracle. The
element at index 0 is the top sampled candidate — not a claim about what the
page would deliver a click to. Known divergences include disabled controls, pointer
capture, shadow retargeting, cross-origin frames, and top-layer chains.
<script src="dist/hitstack.js"></script>Or paste the contents of dist/hitstack.js into a browser console.
dist/hitstack.js is a self-contained IIFE. No imports, no exports, no bundler
required. It installs window.__hitstack and nothing else.
const controller = window.__hitstack.activate({ sampleKey: 'F2' });
// sampleKey is optional; defaults to 'F2'
controller.deactivate(); // full teardown
controller.isActive(); // boolean
controller.getReceipt(); // returns the hitstack-snapshot/v1 object, or null- F2 only (configurable at activation). The key is captured in the capture
phase and
stopPropagation'd — the host page never receives it while the instrument is active. This is a deliberate event-flow mutation. - No hover sampling. Pointer position supplies the coordinate; moving the pointer never triggers a sample.
- No armed click. Sampling never dispatches a page click.
- One frozen sample. Coordinate, ordered candidates, and computed state are captured once at F2. Scroll or resize after the sample invalidates it with an explicit message; the instrument never auto-re-samples.
The copied JSON contains tag only in each candidate's descriptor — no id,
no class. The on-screen rail may display id/class tokens for legibility;
those are never copied. Copy is explicit and local only; nothing is uploaded or
stored.
Example (an opacity:0; pointer-events:auto overlay above a button,
sampled at the button's center):
{
"schema": "hitstack-snapshot/v1",
"point": { "space": "viewport-client", "x": 50, "y": 183 },
"candidates": [
{ "index": 0, "descriptor": { "tag": "div" },
"state": { "pointerEvents": "auto", "opacity": "0", "visibility": "visible" } },
{ "index": 1, "descriptor": { "tag": "button" },
"state": { "pointerEvents": "auto", "opacity": "1", "visibility": "visible" } },
{ "index": 2, "descriptor": { "tag": "div" },
"state": { "pointerEvents": "auto", "opacity": "1", "visibility": "visible" } },
{ "index": 3, "descriptor": { "tag": "body" },
"state": { "pointerEvents": "auto", "opacity": "1", "visibility": "visible" } },
{ "index": 4, "descriptor": { "tag": "html" },
"state": { "pointerEvents": "auto", "opacity": "1", "visibility": "visible" } }
],
"boundaries": {
"scope": "top-document-only",
"shadowInternals": "not-descended",
"iframeContents": "not-inspected"
},
"engine": { "family": "Chromium", "userAgent": "..." }
}Index 0 (opacity: "0", pointer-events: "auto") is the invisible interceptor.
Index 1 is the underlying visible button. Both appear in one F2 sample.
| Boundary | v1 treatment |
|---|---|
| Closed shadow internals | Opaque; host shown as terminal |
| Open shadow internals | Not descended in v1; host shown as terminal |
| All iframe contents (same-origin and cross-origin) | Opaque; labelled iframe-contents-not-inspected |
| Pseudo-elements | Host element only |
Top-layer chains (<dialog>) |
Stack is not DOM ancestry; global caveat |
| Disabled controls | May be top candidate; no click-delivery claim |
| Pointer capture / delegation | Out of scope; never inferred |
While a host showModal() dialog or fullscreen element is active, the
instrument's overlay may be occluded — position: fixed cannot paint above the
top layer. The instrument does not detect modal or fullscreen state and provides
no fallback surface. Sampled data remains correct; only the visual presentation
is unsupported in this configuration.
| Engine | Status |
|---|---|
| Chromium | Supported |
| Firefox | Supported |
| WebKit / Safari | Out of scope — untested, unsupported |
| Mobile / touch | Out of scope — no touch sampling path |
Not a browser extension, DevTools panel, or inspector suite. Not an event-listener debugger. Not an AI fixer. Not a CSS / z-index / accessibility inspector. Not a selector generator. Not a mutation or design-editing tool. Not a persistent inspection session. No account, backend, telemetry, or dashboard.
See LIMITATIONS.md for the full caveat list.
npm install # Playwright is the only dev dependency
npx playwright install chromium firefox
npm run build # regenerate dist/hitstack.js from src/
npm run test:unit # node --test: pure modules + build fidelity
npm run test:e2e # Playwright, Chromium + Firefox
npm test # bothdist/hitstack.js is generated. Edit src/ and re-run npm run build; a test
asserts the committed bundle is byte-identical to a fresh build, so an unbuilt
change fails rather than shipping quietly.
MIT. See LICENSE.